summaryrefslogtreecommitdiff
path: root/src/draw.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 15:43:46 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commitcd6ce6c2b3015c776644fb3866280f5dfd03addc (patch)
treed4e38e5375b71ebec21ee18fe44870e314b2c783 /src/draw.zig
parent0465775799cff895e3e830d2aa19f57966cdf21c (diff)
downloadpardes-cd6ce6c2b3015c776644fb3866280f5dfd03addc.tar.gz
pardes-cd6ce6c2b3015c776644fb3866280f5dfd03addc.zip
A notice's word under the pointer is lit, in its band and the grid; mark_hover is gone
Open point 6 of docs/render-pipeline.md: notice words are Look and Exec targets, so the hover affordance headers have is back on notices, painted once in the notice's layer and joined into the grid from it. Deleted: Surface.mark_hover, Cell.hover and render's per-frame reset of it, none of which had been set since stage 5 (macOS loses its glass hover rect; its build is ignored for now). Snapshot goldens unchanged. Shared files touched: macos.zig (the hover bit's removal). Not touched: pardes.zig, Messages.zig, mouse.zig, gui.zig, detached/*.
Diffstat (limited to 'src/draw.zig')
-rw-r--r--src/draw.zig47
1 files changed, 39 insertions, 8 deletions
diff --git a/src/draw.zig b/src/draw.zig
index 4242a6e7..3798bf59 100644
--- a/src/draw.zig
+++ b/src/draw.zig
@@ -163,10 +163,6 @@ pub fn render(p: *Pardes, arena: std.mem.Allocator) !*Surface {
// the pointer per-text (the macOS I-beam) read this as "target" and
// afford it the arrow instead.
if (p.look_hover_preview != null) s.pointer_shape = .target;
- // Stale hover bits must not survive into a frame whose pointer has
- // moved on: the ordinary content paint does not clear fields it
- // never set.
- for (s.cells) |*c| c.hover = false;
for (&s.body_layers) |*layer| layer.rows = 0;
for (&s.tag_layers) |*layer| layer.rows = 0;
s.nimages = 0;
@@ -661,10 +657,11 @@ fn renderHeaderLayer(p: *Pardes, arena: std.mem.Allocator, layer: *pardes.Layer,
var surface: Surface = .{ .cols = columns, .rows = 1, .cells = layer.cells[index * columns ..][0..columns] };
surface.fill(0, 0, columns, 1, .{ .bg = .{ .rgb = bg }, .font_role = .tagline });
_ = surface.print(0, 0, columns, shown[panes.File.rawAtDisplay(shown, scroll)..], .{ .fg = .{ .rgb = fg }, .bg = .{ .rgb = bg }, .font_role = .tagline });
- // The word under the pointer: on a header even while it is edited,
- // but not on a notice (a message is not a command line), nor on a
- // column a carried column's pointer is aiming at a place over.
- const hovered = p.pointer_inside and kind != .notice and !(kind == .column and p.drag == .column_move);
+ // The word under the pointer, a Look or Exec target: on a header even
+ // while it is edited, on a notice, and on the grid's copy of either
+ // (joined from this); not on a column a carried column's pointer is
+ // aiming at a place over.
+ const hovered = p.pointer_inside and !(kind == .column and p.drag == .column_move);
if (hovered) {
const tag_hit = p.pointer_tag_hit;
const col: ?usize = if (tag_hit) |pointer|
@@ -1033,6 +1030,40 @@ test "place puts every part where the painters and layers put it, in every layou
}
}
+test "the word under the pointer on a notice is lit in its layer and in the grid's copy" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 41, .rows = 12 });
+ defer p.deinit();
+ _ = try p.setTestFile("text\n");
+ var arena: std.heap.ArenaAllocator = .init(std.testing.allocator);
+ defer arena.deinit();
+ try std.testing.expect(p.executeBuiltinLine(p.active, "Msg Look here"));
+ p.sync();
+ var s = try p.render(arena.allocator());
+ const notice = for (s.regionList()) |region| {
+ if (region.kind == .notice) break region;
+ } else return error.TestExpectedNotice;
+ const row = s.cells[@as(usize, notice.rect.y) * s.cols ..][0..s.cols];
+ // "here", the chip's last word, before its blank edge.
+ const here = notice.rect.x + notice.rect.w - 5;
+ try std.testing.expectEqualStrings("h", row[here].grapheme());
+ p.pointer_inside = true;
+ p.hover_col = here + 1;
+ p.hover_row = notice.rect.y;
+ _ = arena.reset(.retain_capacity);
+ s = try p.render(arena.allocator());
+ const lit = s.cells[@as(usize, notice.rect.y) * s.cols ..][0..s.cols];
+ const sel: Color = .{ .rgb = p.theme().sel_bg };
+ for (lit[here..][0..4]) |cell| try std.testing.expectEqual(sel, cell.style.bg);
+ try std.testing.expect(!std.meta.eql(sel, lit[here - 2].style.bg));
+ const layer = for (s.tagLayers()) |*layer| {
+ if (layer.rows != 0 and layer.kind == .notice) break layer;
+ } else return error.TestExpectedNotice;
+ const lit_in_layer = for (layer.cells) |cell| {
+ if (std.meta.eql(sel, cell.style.bg)) break true;
+ } else false;
+ try std.testing.expect(lit_in_layer);
+}
+
test "a wide glyph cut by a tag's or a notice's edge is joined into the grid as blank, never half drawn" {
const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 41, .rows = 12 });
defer p.deinit();