summaryrefslogtreecommitdiff
path: root/src/gui/gui.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/gui.zig')
-rw-r--r--src/gui/gui.zig31
1 files changed, 22 insertions, 9 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index e1d5c86d..1f7812e4 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -500,6 +500,12 @@ const WebChromeTarget = struct { col: u16, row: u16 };
/// Fat-finger hit test for web layout chrome. A gesture is classified once at
/// finger-down, then never changes into scrolling. Handle coordinates are
/// snapped onto the core's one-cell resize edge; body rows remain untouched.
+///
+/// The tag row and the stacked-pair seam come from the core's own rule:
+/// Tagbottom puts a pane's tag on its LAST row, which makes its FIRST row an
+/// ordinary scrollable body row and moves the h-handle down to the lower
+/// pane's first. Kept a line-for-line clone of web.zig's chromeTarget — the
+/// two must classify a finger identically.
fn webChromeTarget(core: *const pardes.Pardes, col: u16, row: u16) ?WebChromeTarget {
if (row < pardes.TOPBAR_H) return .{ .col = col, .row = row };
@@ -508,8 +514,9 @@ fn webChromeTarget(core: *const pardes.Pardes, col: u16, row: u16) ?WebChromeTar
for (core.panes, 0..) |slot, id| {
if (slot == null) continue;
const rect = core.rects[id];
- if (row == rect.y and col >= rect.x and col < rect.x + rect.w and col < rect.x + config.GUTTER)
- return .{ .col = col, .row = rect.y };
+ const tag = if (core.tag_bottom) rect.y + rect.h -| pardes.BOX_H else rect.y;
+ if (row == tag and col >= rect.x and col < rect.x + rect.w and col < rect.x + config.GUTTER)
+ return .{ .col = col, .row = tag };
}
for (0..core.ncol -| 1) |column| {
@@ -520,7 +527,7 @@ fn webChromeTarget(core: *const pardes.Pardes, col: u16, row: u16) ?WebChromeTar
if (col < core.col_x[column] or col >= core.col_x[column] + core.col_w[column]) continue;
for (0..core.col_n[column] -| 1) |index| {
const rect = core.rects[core.col_terms[column][index]];
- const handle = rect.y + rect.h -| 1;
+ const handle = if (core.tag_bottom) rect.y +| rect.h else rect.y + rect.h -| 1;
if (row == handle) return .{ .col = col, .row = handle };
}
}
@@ -529,8 +536,9 @@ fn webChromeTarget(core: *const pardes.Pardes, col: u16, row: u16) ?WebChromeTar
for (core.panes, 0..) |slot, id| {
if (slot == null) continue;
const rect = core.rects[id];
- if (row == rect.y and col >= rect.x and col < rect.x + rect.w)
- return .{ .col = col, .row = rect.y };
+ const tag = if (core.tag_bottom) rect.y + rect.h -| pardes.BOX_H else rect.y;
+ if (row == tag and col >= rect.x and col < rect.x + rect.w)
+ return .{ .col = col, .row = tag };
}
// One-cell tolerance around thin separators, after exact tag rows have had
@@ -543,7 +551,7 @@ fn webChromeTarget(core: *const pardes.Pardes, col: u16, row: u16) ?WebChromeTar
if (col < core.col_x[column] or col >= core.col_x[column] + core.col_w[column]) continue;
for (0..core.col_n[column] -| 1) |index| {
const rect = core.rects[core.col_terms[column][index]];
- const handle = rect.y + rect.h -| 1;
+ const handle = if (core.tag_bottom) rect.y +| rect.h else rect.y + rect.h -| 1;
if (cellDistance(row, handle) == 1) return .{ .col = col, .row = handle };
}
}
@@ -984,6 +992,7 @@ const Gui = struct {
// scroll_delta the way the wheel arm of dispatch does.
scroll_pane: ?usize = null,
scroll_rect: pardes.Rect = .{ .x = 0, .y = 0, .w = 0, .h = 0 },
+ scroll_body_y: u16 = 0, // that rect's first BODY row (Tagbottom moves it)
scroll_col: u16 = 0, // where the wheel turned: crossed rows are delivered
scroll_row: u16 = 0, // THERE, not wherever the pointer has drifted to since
scroll_delta: f32 = 0, // finite raw distance waiting for the render batch
@@ -2884,6 +2893,10 @@ fn stepScroll(g: *Gui, core: *pardes.Pardes, gpa: std.mem.Allocator) void {
}
g.scroll_lag = st.lag;
g.scroll_rect = r;
+ // the body origin travels with the rect: the two draw sites below have no
+ // core to ask, and with Tagbottom the body starts at r.y, not r.y + BOX_H
+ const body_y = if (core.tag_bottom) r.y else r.y + pardes.BOX_H;
+ g.scroll_body_y = body_y;
if (st.rows != 0) {
// The offset opens a gap at the trailing edge of the travel, and what
// belongs in it is the row that just left the pane: already gone from
@@ -2896,7 +2909,7 @@ fn stepScroll(g: *Gui, core: *pardes.Pardes, gpa: std.mem.Allocator) void {
const bw = r.w - config.GUTTER;
const bh = r.h - pardes.BOX_H;
const k: u16 = @intCast(@min(@abs(st.rows), @as(i32, bh)));
- const srow = r.y + pardes.BOX_H + (if (st.rows > 0) k - 1 else bh - k);
+ const srow = body_y + (if (st.rows > 0) k - 1 else bh - k);
if (srow < s.rows) {
if (g.scroll_edge.len < bw) {
gpa.free(g.scroll_edge);
@@ -2923,7 +2936,7 @@ fn emitScrollRows(g: *Gui, instances: [*]CellInstance, base: u32, surface: *pard
const r = g.scroll_rect;
if (r.w <= config.GUTTER or r.h <= pardes.BOX_H) return 0;
const x0 = r.x + config.GUTTER;
- const y0 = r.y + pardes.BOX_H;
+ const y0 = g.scroll_body_y;
const bw = r.w - config.GUTTER;
const bh = r.h - pardes.BOX_H;
if (x0 + bw > surface.cols or y0 + bh > surface.rows) return 0; // resized under us
@@ -2960,7 +2973,7 @@ fn emitScrollRows(g: *Gui, instances: [*]CellInstance, base: u32, surface: *pard
fn scrollScissor(g: *const Gui, layout: CellLayout, sw: u32, sh: u32) c.SDL_Rect {
const r = g.scroll_rect;
const px = layout.x_off + @as(f32, @floatFromInt(r.x + config.GUTTER)) * layout.w;
- const py = layout.y_off + @as(f32, @floatFromInt(r.y + pardes.BOX_H)) * layout.h;
+ const py = layout.y_off + @as(f32, @floatFromInt(g.scroll_body_y)) * layout.h;
const pw = @as(f32, @floatFromInt(r.w - config.GUTTER)) * layout.w;
const ph = @as(f32, @floatFromInt(r.h - pardes.BOX_H)) * layout.h;
const x0 = std.math.clamp(@as(i32, @intFromFloat(@floor(px))), 0, @as(i32, @intCast(sw)));