centralize movement logic/debounce mouse wheel on cursor tabs
This commit is contained in:
parent
863111d801
commit
43ab8d1957
1 changed files with 46 additions and 41 deletions
87
src/tui.zig
87
src/tui.zig
|
|
@ -308,6 +308,10 @@ pub const App = struct {
|
|||
classification_map: ?zfin.classification.ClassificationMap = null,
|
||||
account_map: ?zfin.analysis.AccountMap = null,
|
||||
|
||||
// Mouse wheel debounce for cursor-based tabs (portfolio, options).
|
||||
// Terminals often send multiple wheel events per physical tick.
|
||||
last_wheel_ns: i128 = 0,
|
||||
|
||||
// Chart state (Kitty graphics)
|
||||
chart: ChartState = .{},
|
||||
vx_app: ?*vaxis.vxfw.App = null, // set during run(), for Kitty graphics access
|
||||
|
|
@ -346,29 +350,11 @@ pub const App = struct {
|
|||
fn handleMouse(self: *App, ctx: *vaxis.vxfw.EventContext, mouse: vaxis.Mouse) void {
|
||||
switch (mouse.button) {
|
||||
.wheel_up => {
|
||||
if (self.active_tab == .portfolio) {
|
||||
if (self.cursor > 0) self.cursor -= 1;
|
||||
self.ensureCursorVisible();
|
||||
} else if (self.active_tab == .options) {
|
||||
if (self.options_cursor > 0) self.options_cursor -= 1;
|
||||
self.ensureOptionsCursorVisible();
|
||||
} else {
|
||||
if (self.scroll_offset > 0) self.scroll_offset -= 3;
|
||||
}
|
||||
self.moveBy(-3, true);
|
||||
return ctx.consumeAndRedraw();
|
||||
},
|
||||
.wheel_down => {
|
||||
if (self.active_tab == .portfolio) {
|
||||
if (self.portfolio_rows.items.len > 0 and self.cursor < self.portfolio_rows.items.len - 1)
|
||||
self.cursor += 1;
|
||||
self.ensureCursorVisible();
|
||||
} else if (self.active_tab == .options) {
|
||||
if (self.options_rows.items.len > 0 and self.options_cursor < self.options_rows.items.len - 1)
|
||||
self.options_cursor += 1;
|
||||
self.ensureOptionsCursorVisible();
|
||||
} else {
|
||||
self.scroll_offset += 3;
|
||||
}
|
||||
self.moveBy(3, true);
|
||||
return ctx.consumeAndRedraw();
|
||||
},
|
||||
.left => {
|
||||
|
|
@ -577,30 +563,11 @@ pub const App = struct {
|
|||
}
|
||||
},
|
||||
.select_next => {
|
||||
if (self.active_tab == .portfolio) {
|
||||
if (self.portfolio_rows.items.len > 0 and self.cursor < self.portfolio_rows.items.len - 1)
|
||||
self.cursor += 1;
|
||||
self.ensureCursorVisible();
|
||||
} else if (self.active_tab == .options) {
|
||||
if (self.options_rows.items.len > 0 and self.options_cursor < self.options_rows.items.len - 1)
|
||||
self.options_cursor += 1;
|
||||
self.ensureOptionsCursorVisible();
|
||||
} else {
|
||||
self.scroll_offset += 1;
|
||||
}
|
||||
self.moveBy(1, false);
|
||||
return ctx.consumeAndRedraw();
|
||||
},
|
||||
.select_prev => {
|
||||
if (self.active_tab == .portfolio) {
|
||||
if (self.cursor > 0) self.cursor -= 1;
|
||||
self.ensureCursorVisible();
|
||||
} else if (self.active_tab == .options) {
|
||||
if (self.options_cursor > 0)
|
||||
self.options_cursor -= 1;
|
||||
self.ensureOptionsCursorVisible();
|
||||
} else {
|
||||
if (self.scroll_offset > 0) self.scroll_offset -= 1;
|
||||
}
|
||||
self.moveBy(-1, false);
|
||||
return ctx.consumeAndRedraw();
|
||||
},
|
||||
.expand_collapse => {
|
||||
|
|
@ -737,6 +704,44 @@ pub const App = struct {
|
|||
}
|
||||
}
|
||||
|
||||
/// Move cursor/scroll. Positive = down, negative = up.
|
||||
/// For portfolio and options tabs, moves the row cursor by 1.
|
||||
/// For other tabs, adjusts scroll_offset by |n|.
|
||||
/// When from_wheel is true, debounces on cursor tabs to absorb
|
||||
/// duplicate events that terminals send per physical scroll tick.
|
||||
fn moveBy(self: *App, n: isize, from_wheel: bool) void {
|
||||
if (self.active_tab == .portfolio or self.active_tab == .options) {
|
||||
if (from_wheel) {
|
||||
const now = std.time.nanoTimestamp();
|
||||
if (now - self.last_wheel_ns < 1 * std.time.ns_per_ms) return;
|
||||
self.last_wheel_ns = now;
|
||||
}
|
||||
if (self.active_tab == .portfolio) {
|
||||
stepCursor(&self.cursor, self.portfolio_rows.items.len, n);
|
||||
self.ensureCursorVisible();
|
||||
} else {
|
||||
stepCursor(&self.options_cursor, self.options_rows.items.len, n);
|
||||
self.ensureOptionsCursorVisible();
|
||||
}
|
||||
} else {
|
||||
if (n > 0) {
|
||||
self.scroll_offset += @intCast(n);
|
||||
} else {
|
||||
const abs: usize = @intCast(-n);
|
||||
if (self.scroll_offset > abs) self.scroll_offset -= abs else self.scroll_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stepCursor(cursor: *usize, row_count: usize, direction: isize) void {
|
||||
if (direction > 0) {
|
||||
if (row_count > 0 and cursor.* < row_count - 1)
|
||||
cursor.* += 1;
|
||||
} else {
|
||||
if (cursor.* > 0) cursor.* -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn ensureCursorVisible(self: *App) void {
|
||||
const cursor_row = self.cursor + self.portfolio_header_lines;
|
||||
if (cursor_row < self.scroll_offset) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue