summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 15:40:11 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit0465775799cff895e3e830d2aa19f57966cdf21c (patch)
tree88a26809d68da2e63c1bfbb6309a914eae5c2557
parent360b72ade0acfa655a3740b638a0cc8e23238a05 (diff)
downloadpardes-0465775799cff895e3e830d2aa19f57966cdf21c.tar.gz
pardes-0465775799cff895e3e830d2aa19f57966cdf21c.zip
A still pane's notice stays under a closing pane's tombstone
Tier 4 draws notices over every group; while a pane closes, a notice goes back to its own pane's group instead, so the tombstone sliding over it covers it as it did before stage 8. Review follow-up to stage 8. Shared files touched: gui.zig.
-rw-r--r--docs/render-pipeline.md2
-rw-r--r--src/gui/gui.zig22
2 files changed, 18 insertions, 6 deletions
diff --git a/docs/render-pipeline.md b/docs/render-pipeline.md
index 69645c96..6c5e4866 100644
--- a/docs/render-pipeline.md
+++ b/docs/render-pipeline.md
@@ -810,7 +810,7 @@ stripped. No visual change until stage 9 unless stated.
| 5 | JOIN: paint tags/notices/headers once into layers, copy into grid; the grid wins where the copies disagree, and each disagreement is listed for a later decision | goldens are the oracle; wide-grapheme re-clip at the edge (§3.2) |
| 6 | body layer joined the same way (paint once, copy visible rows) | riskiest join; A/B the old double paint in a temporary test with tag_bottom on and off, then delete it |
| 7 | Layer merge (TagLayer + BodyLayer), wire v8, web accessors | after the other agent lands; touches mouse hit paths; breaks the macOS shell's layer ABI (accepted: macOS build ignored for now); done: one `Layer` (src/Layer.zig) with `rows` (0 = no layer) and a `cursor{x, y}`; a tag of N rows is ONE layer of N grid rows (`tagHit` answers the row as `line`, `bodyHit` keeps its meaning), so the per-line layer bases are gone. Wire v8 ships rows, cursor y and the region list in the one bump; v7 and v9 peers are refused in both directions (tests). web: `tag_layer_value` 11 = rows, 12 = cursor y, and app.mjs lays every row. macOS: its Zig side compiles against `Layer`, but pardes.h still sees one row per tag layer (a taller tag shows its first row there) |
-| 8 | GUI draws from regions: role tiers with track groups in tiers 2-3, page cover, hard-edged snapped decor for rules/rails/grips (pane chrome in the pane's tier), per-instance clip; delete inference functions, `transient_on` and `mark_hover` (breaks macOS glass hover; accepted, macOS ignored for now) | stage-0 PPM goldens byte-identical (possible only because hard decor is snapped and not anti-aliased); pane chrome now also shows during transitions, which is the one allowed visible delta, listed Done: the frame is drawn in groups (makeGroups): tier 0, one group per track in paint order (tiers 2 and 3), tier 4 as two groups (the notices; then the guides and the debug box, which the core paints over them), tier 5 (bar cursors), each drawing cells, images, decor. Decor is every rule, rail, thumb, grip mark, spine, the workspace and column rules, the bottom band, notice rules and bar cursors: whole-pixel rects drawn by `decor.frag` over `ui.vert` as cell instances (colour in the ground, coverage in fg.r, blended like the overlay), so each carries its track's transition and clip; a closing pane's comes from the last frame's regions (`Surface.previous_regions`). Only `solid` exists yet: `decor.vert` and the other kinds (§5.1) come with the first effect that needs them. Deleted: taglineBaseRgb, topbarPaneBorderHeight, bottomTaglinePresent, frameChromeBg, cellBackgroundIs and the rail inference, paneGripCell's scan, transient_on, PaintPlan; one cover map (coverFrame: layer, grip and offset, focus, anchor, floating) is marked from layers and regions once a frame. New regions: `column` (spines, anchors, the focused column's tint), `guide`, `debug`; `Surface.chrome` is the palette, on the wire in v8 (not yet shipped, so no bump), and an attached GUI draws the same chrome (test). Per-instance clip (`CellInstance.clip_*`) replaces the vertical transition's scissor. Goldens: 01-12 byte-identical; 13-17 differ only in pixels past the grid (with a picture on screen the image pass left the scissor at the grid's size, cutting every rule end, rail foot and band that runs into the leftover pixels; they now run to the edge as in every scene without one); 16-debug shows the debug box (it was drawn from the grid under the source's context-row layer, so the GUI never showed it there); 18-mid-transition is new (virtual clock, PanelSlide Newcol with the picture, frame 6 of 12: chrome moves with its pane). Other deltas, outside the goldens: a guide over a tag or a context-row body now shows; with WindowOpacity < 100 a layer's bar cursor is ink like the grid's; an attached GUI gains the focus tint, notice rules, spines and the theme's page and caret colours. Deferrals fixed: the GUI sleeps when idle (SDL and queue events wake it; a smooth scroll, a gamepad, the test feed, a shell's kill deadline, a present to retry still poll), and a minimized or occluded window sleeps through animation. Tracy, `gui frame build`, 200x60, terminal output plus scrolling, ReleaseFast, two interleaved runs of ~180 frames: before 992/1015 µs median, after 989/987 µs |
+| 8 | GUI draws from regions: role tiers with track groups in tiers 2-3, page cover, hard-edged snapped decor for rules/rails/grips (pane chrome in the pane's tier), per-instance clip; delete inference functions, `transient_on` and `mark_hover` (breaks macOS glass hover; accepted, macOS ignored for now) | stage-0 PPM goldens byte-identical (possible only because hard decor is snapped and not anti-aliased); pane chrome now also shows during transitions, which is the one allowed visible delta, listed Done: the frame is drawn in groups (makeGroups): tier 0, one group per track in paint order (tiers 2 and 3), tier 4 as two groups (the notices; then the guides and the debug box, which the core paints over them), tier 5 (bar cursors), each drawing cells, images, decor. Decor is every rule, rail, thumb, grip mark, spine, the workspace and column rules, the bottom band, notice rules and bar cursors: whole-pixel rects drawn by `decor.frag` over `ui.vert` as cell instances (colour in the ground, coverage in fg.r, blended like the overlay), so each carries its track's transition and clip; a closing pane's comes from the last frame's regions (`Surface.previous_regions`). Only `solid` exists yet: `decor.vert` and the other kinds (§5.1) come with the first effect that needs them. Deleted: taglineBaseRgb, topbarPaneBorderHeight, bottomTaglinePresent, frameChromeBg, cellBackgroundIs and the rail inference, paneGripCell's scan, transient_on, PaintPlan; one cover map (coverFrame: layer, grip and offset, focus, anchor, floating) is marked from layers and regions once a frame. New regions: `column` (spines, anchors, the focused column's tint), `guide`, `debug`; `Surface.chrome` is the palette, on the wire in v8 (not yet shipped, so no bump), and an attached GUI draws the same chrome (test). Per-instance clip (`CellInstance.clip_*`, 104 → 120 bytes an instance, ~15% more upload a frame) replaces the vertical transition's scissor. While a pane closes, notices stay in their own panes' groups, under the tombstone sliding over them. Goldens: 01-12 byte-identical; 13-17 differ only in pixels past the grid (with a picture on screen the image pass left the scissor at the grid's size, cutting every rule end, rail foot and band that runs into the leftover pixels; they now run to the edge as in every scene without one); 16-debug shows the debug box (it was drawn from the grid under the source's context-row layer, so the GUI never showed it there); 18-mid-transition is new (virtual clock, PanelSlide Newcol with the picture, frame 6 of 12: chrome moves with its pane). Other deltas, outside the goldens: a guide over a tag or a context-row body now shows; with WindowOpacity < 100 a layer's bar cursor is ink like the grid's; an attached GUI gains the focus tint, notice rules, spines and the theme's page and caret colours. Deferrals fixed: the GUI sleeps when idle (SDL and queue events wake it; a smooth scroll, a gamepad, the test feed, a shell's kill deadline, a present to retry still poll), and a minimized or occluded window sleeps through animation. Tracy, `gui frame build`, 200x60, terminal output plus scrolling, ReleaseFast, two interleaved runs of ~180 frames: before 992/1015 µs median, after 989/987 µs |
| 9 | post chain: glslang, Shadertoy prefix, ping-pong, ShaderAnimation, redraw levels A/B (§5.5); bundled CRT without barrel; delete scene_effects/crt.zig/crt.frag | first visual change (the CRT look) |
| 10+ | `fx` bookmark: G1–G3 → feel review → G4 bundled → G5 lapis theme → P2s; tty T1–T2 → feel review → removals of audited effects (after user decision) → T3–T5 | each effect its own change, default off |
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 35fbc99d..39d7f61e 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -603,6 +603,10 @@ test "closing tombstone overlays but never owns canonical cells" {
};
const groups = makeGroups(&.{closing}, true);
try std.testing.expectEqual(@as(usize, 0), groupAt(&groups, 4, 4));
+ // A still pane's notice stays under the tombstone sliding over it.
+ const notice: pardes.Layer = .{ .kind = .notice, .viewport = .{ .x = 4, .y = 4, .w = 3, .h = 1 }, .rows = 1 };
+ try std.testing.expectEqual(@as(usize, 0), noticeGroup(&groups, &notice));
+ try std.testing.expectEqual(makeGroups(&.{}, false).notices, noticeGroup(&makeGroups(&.{}, false), &notice));
try std.testing.expectEqual(@as(usize, 1), groups.tracks);
try std.testing.expectEqual(pardes.animation.Phase.closing, groups.items[1].track.?.phase);
}
@@ -2071,6 +2075,14 @@ fn groupOf(groups: *const Groups, serial: u32) usize {
return 0;
}
+/// A notice floats over the panes (tier 4), except while a pane closes: then
+/// it stays in its own pane's group, under the tombstone sliding over it.
+fn noticeGroup(groups: *const Groups, layer: *const pardes.Layer) usize {
+ for (groups.items[1..][0..groups.tracks]) |group|
+ if (group.track.?.phase == .closing) return groupAt(groups, layer.viewport.x, layer.viewport.y);
+ return groups.notices;
+}
+
/// What draws a grid cell, marked once a frame from the layers and the
/// regions (coverFrame), so the cell loops read it rather than search.
const Cover = packed struct(u16) {
@@ -5344,7 +5356,7 @@ fn renderFrame(
}
for (surface.tagLayers()) |*layer| {
if (layer.rows == 0) continue;
- const group_index = if (layer.kind == .notice) groups.notices else groupAt(&groups, layer.viewport.x, layer.viewport.y);
+ const group_index = if (layer.kind == .notice) noticeGroup(&groups, layer) else groupAt(&groups, layer.viewport.x, layer.viewport.y);
groups.items[group_index].cell_count += (tagLayerCellCount(g, layer) + 1) * layer.rows;
}
for (groups.items[1..][0..groups.tracks], 1..) |group, index| {
@@ -5440,7 +5452,7 @@ fn renderFrame(
if (layer.rows == 0) continue;
const track_index = groupAt(&groups, layer.viewport.x, layer.viewport.y);
// A notice floats over the panes, moving with its own.
- const group_index = if (layer.kind == .notice) groups.notices else track_index;
+ const group_index = if (layer.kind == .notice) noticeGroup(&groups, layer) else track_index;
emitTagLayer(g, instances, &cell_next[group_index], layer, win_w, win_h, groups.items[track_index].track, page, cursors_shown, false);
}
for (groups.items[1..][0..groups.tracks], 1..) |group, index| {
@@ -7374,8 +7386,8 @@ fn buildDecor(g: *Gui, gpa: std.mem.Allocator, surface: *const pardes.Surface, g
// ruled off from the text beneath it the way a tag is: the same
// colour and thickness along its bottom, running to the window's
// edge when it does, fading up and dissolving with its band.
- if (index == groups.notices) for (surface.tagLayers()) |*layer| {
- if (layer.rows == 0 or layer.kind != .notice) continue;
+ for (surface.tagLayers()) |*layer| {
+ if (layer.rows == 0 or layer.kind != .notice or noticeGroup(groups, layer) != index) continue;
const x0 = @as(f32, @floatFromInt(layer.viewport.x)) * layout.w;
const x1 = x0 + @as(f32, @floatFromInt(layer.viewport.w)) * layout.w;
const rule_x1 = if (win_w - x1 < layout.w) @max(x1, win_w) else x1;
@@ -7386,7 +7398,7 @@ fn buildDecor(g: *Gui, gpa: std.mem.Allocator, surface: *const pardes.Surface, g
if (rule_y - 1 < top) continue;
const track = groups.items[groupAt(groups, layer.viewport.x, layer.viewport.y)].track;
try addDecor(g, gpa, x0, rule_y - 1, rule_x1, rule_y, chrome.border, layer.fade, track, win_w, win_h);
- };
+ }
if (index == groups.ink and cursors_shown) try cursorDecor(g, gpa, surface, layout, win_w, win_h);
}
}