diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-24 09:45:50 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | a39fb20cb770c3adb911cec7d1f3d033669ed1bb (patch) | |
| tree | e7bb88af15990e502b5f4deac5493ea2957e8b24 /test/column_drag.zig | |
| parent | 39cdba439c1ae47dbc7c3243a9273aa011c6affa (diff) | |
| download | pardes-a39fb20cb770c3adb911cec7d1f3d033669ed1bb.tar.gz pardes-a39fb20cb770c3adb911cec7d1f3d033669ed1bb.zip | |
Light a held column grip, and rail its landing beside the rule where the GUI shows it
The column grip worked in the GUI but showed nothing anyone could see.
Driving the real SDL window with pixel mouse events, press, drag and
release all reach the core and reorder or resize the column; the feedback
is what failed. The grip kept its muted color while held, and a reorder's
insertion rail was drawn in the gutter cell at the destination edge. The
GUI paints that cell as the column's scroll rail, and at the window's left
edge, the common case of moving the right column first, the dashes were
lost in it. From the leftmost column, a drag short of a neighbour's middle
shows no rail, rightly, since nothing would move, but nothing said the
grip was even held.
A held grip now lights in column_box, the accent its muted color is mixed
from, and the rail takes that color. The rail runs in the seam cell left of
where the column's rule will land, where a border drag's rail runs, for a
reorder and a left-edge move alike; at the window's left edge, which has no
seam, it runs just past the scroll rail, leaving column 0's grip and pane
boxes whole. A carried column's pointer aims at a place, not a word, so the
column tags no longer light the word under it, and a release snaps the
layout as a border drag's does rather than animating it. The preview and the release both
ask layout.columnDrop where the column goes, so the rail stands where the
release puts the edge, and the drag no longer carries its unused column
index.
The GUI test feed takes ESC]777;mouse;<down|up|motion>;<button>;<x>;<y> in
window pixels and dispatches it as an SDL event. test/column_grip.py uses
it to drive the grip through the same pixel-to-cell and tag hit path as a
hand on the mouse, and checks the grip, the rail and the result against
GPU captures and the 9P grid.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Diffstat (limited to 'test/column_drag.zig')
| -rw-r--r-- | test/column_drag.zig | 89 |
1 files changed, 87 insertions, 2 deletions
diff --git a/test/column_drag.zig b/test/column_drag.zig index 85dca66b..b2b8f35d 100644 --- a/test/column_drag.zig +++ b/test/column_drag.zig @@ -176,7 +176,7 @@ test "column grip is separate from compact text and the resize seam" { p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = seam, .row = body_row } }); } -test "column grips stay blank and muted across focus hover and drag" { +test "column grips stay blank, and muted across focus and hover until grabbed" { const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 20 }); defer p.deinit(); _ = try p.setTestFile("left\n"); @@ -198,11 +198,12 @@ test "column grips stay blank and muted across focus hover and drag" { _ = frame.reset(.retain_capacity); const surface = try p.render(frame.allocator()); const muted: pardes.Color = .{ .rgb = p.chromeTheme().column_box_dim }; + const lit: pardes.Color = .{ .rgb = p.chromeTheme().column_box }; for (0..p.ncol) |column| { for (0..config.GUTTER) |offset| { const cell = surface.at(p.col_x[column] + @as(u16, @intCast(offset)), pardes.TOPBAR_H); try std.testing.expectEqualStrings(" ", cell.grapheme()); - try std.testing.expectEqual(muted, cell.style.bg); + try std.testing.expectEqual(if (dragging and column == active_column) lit else muted, cell.style.bg); try std.testing.expectEqual(pardes.FontRole.tagline, cell.style.font_role); } try std.testing.expectEqual(p.col_x[column] + pardes.TAG_TEXT_INSET, (try tagLayer(p, column)).viewport.x); @@ -252,3 +253,87 @@ test "column grip dropped in its own place moves the column's left edge" { try std.testing.expectEqual(serials[1], p.col_serial[0]); try std.testing.expectEqual(serials[0], p.col_serial[1]); } + +/// The column of the drag preview's rail, checked to run the full height +/// below the workspace tag in the grabbed grip's color, except through the +/// grip and pane boxes at the window's left edge. +fn previewRail(p: *Pardes, frame: *std.heap.ArenaAllocator) !?u16 { + _ = frame.reset(.retain_capacity); + const surface = try p.render(frame.allocator()); + const lit: pardes.Color = .{ .rgb = p.chromeTheme().column_box }; + var found: ?u16 = null; + for (0..surface.cols) |x| { + if (!std.mem.eql(u8, surface.at(@intCast(x), surface.rows - 1).grapheme(), "╎")) continue; + try std.testing.expect(found == null); + found = @intCast(x); + for (p.topBarHeight()..surface.rows) |row| { + const cell = surface.at(@intCast(x), @intCast(row)); + if (x < config.GUTTER and cell.style.font_role == .tagline) { + try std.testing.expect(!std.mem.eql(u8, cell.grapheme(), "╎")); + continue; + } + try std.testing.expectEqualStrings("╎", cell.grapheme()); + try std.testing.expectEqual(lit, cell.style.fg); + } + } + return found; +} + +test "column grip drag previews where the column lands, in the seam beside its rule" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 120, .rows = 24 }); + defer p.deinit(); + _ = try p.setTestFile("body\n"); + p.presentation.enabled = false; + p.settings.column_tags = true; + for (0..2) |_| { + try std.testing.expect(p.executeBuiltinLine(p.active, "New")); + try std.testing.expect(layout.splitColumn(p, p.active, p.active, false)); + } + try std.testing.expectEqual(@as(usize, 3), p.ncol); + p.update(.tick); + var frame = std.heap.ArenaAllocator.init(p.gpa); + defer frame.deinit(); + _ = try p.render(frame.allocator()); + const serials = .{ p.col_serial[0], p.col_serial[1], p.col_serial[2] }; + + // Held on its own grip it lands nowhere new: no rail. + mouse(p, .press, p.col_x[1]); + mouse(p, .drag, p.col_x[1] + 1); + try std.testing.expectEqual(@as(?u16, null), try previewRail(p, &frame)); + // Over the first column's left half it goes first. The window edge has + // no seam, and the gutter there is the GUI's scroll rail, so the rail + // runs in the gutter's last cell. + mouse(p, .drag, 3); + try std.testing.expectEqual(@as(?u16, config.GUTTER - 1), try previewRail(p, &frame)); + // The pointer is over the first column's "New", but a carried column + // aims at a place: no word lights under it. + for (0..p.screen_w) |x| try std.testing.expect(!std.meta.eql(p.surface.at(@intCast(x), pardes.TOPBAR_H).style.bg, pardes.Color{ .rgb = p.theme().sel_bg })); + mouse(p, .release, 3); + try std.testing.expectEqual(serials[1], p.col_serial[0]); + try std.testing.expectEqual(serials[0], p.col_serial[1]); + + // Past the middle column's middle it lands after it: the rail is in the + // seam cell left of the last column's rule, where a border drag's is. + mouse(p, .press, p.col_x[0]); + const past = p.col_x[1] + p.col_w[1] - 2; + mouse(p, .drag, past); + try std.testing.expectEqual(@as(?u16, p.col_x[2] - 1), try previewRail(p, &frame)); + // Past the last column's middle: the window's last cell. + mouse(p, .drag, p.col_x[2] + p.col_w[2] - 1); + try std.testing.expectEqual(@as(?u16, p.screen_w - 1), try previewRail(p, &frame)); + mouse(p, .release, p.col_x[2] + p.col_w[2] - 1); + try std.testing.expectEqual(serials[0], p.col_serial[0]); + try std.testing.expectEqual(serials[2], p.col_serial[1]); + try std.testing.expectEqual(serials[1], p.col_serial[2]); + + // Short of a neighbour's middle the left edge moves, and the preview + // is the seam that edge will have: exactly where the release puts it. + const edge = p.col_x[2]; + mouse(p, .press, edge + 1); + mouse(p, .drag, edge + 1 - 6); + try std.testing.expectEqual(@as(?u16, edge - 6 - 1), try previewRail(p, &frame)); + mouse(p, .release, edge + 1 - 6); + _ = try p.render(frame.allocator()); + try std.testing.expectEqual(edge - 6, p.col_x[2]); + try std.testing.expectEqual(@as(?u16, null), try previewRail(p, &frame)); +} |
