system settings
git clone https://git.lucas.co/cce-system-interface.git
popover layer: replay carves in the widget's own order
The page dropdown's hovered-row highlight was drawn UNDER the menu's
frosted plate: the popover collector split a widget's emission into
plain rects and inset-plate carves, and display_list replayed all the
rects and then all the carves — but a Dropdown draws its highlight after
the plate it claims for the menu face. PageContent now records, per
carve, how many rects preceded it, and display_list slots each carve
back between the rects it was claimed between. Page-widget popovers'
marks shift past the chrome popover's rects when they are merged.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AxEbg3N3GndoetpY7LThEA
src/app.rs | 10 ++++++++++
src/main.rs | 46 +++++++++++++++++++++++++++++++++-------------
src/renderer.rs | 7 ++++++-
3 files changed, 49 insertions(+), 14 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index 4409aed..7a13f3b 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -170,6 +170,12 @@ pub struct PageContent {
/// depth, carve), page coordinates, pre-scroll; display_list re-emits them
/// as real relief prims.
pub control_reliefs: Vec<ControlCarve>,
+ /// Per carve, `rects.len()` at the moment it was claimed — the carve's
+ /// place in the widget's own emission order. A Dropdown draws its
+ /// hovered-row highlight AFTER the inset plate it claims for the menu
+ /// face; replaying every rect and then every carve put the frosted plate
+ /// over the highlight. The popover layer interleaves on these marks.
+ pub control_relief_marks: Vec<usize>,
pub clip_stack: Vec<[f32; 4]>,
pub measure_only: bool,
}
@@ -182,6 +188,7 @@ impl Default for PageContent {
buttons: Vec::new(),
reliefs: Vec::new(),
control_reliefs: Vec::new(),
+ control_relief_marks: Vec::new(),
clip_stack: Vec::new(),
measure_only: true,
}
@@ -196,6 +203,7 @@ impl PageContent {
buttons: Vec::new(),
reliefs: Vec::new(),
control_reliefs: Vec::new(),
+ control_relief_marks: Vec::new(),
clip_stack: Vec::new(),
measure_only: false,
}
@@ -366,6 +374,7 @@ impl RenderTarget for PageContent {
if self.measure_only {
return;
}
+ self.control_relief_marks.push(self.rects.len());
self.control_reliefs.push(ControlCarve::Plate { x, y, w, h, radius, depth, color });
}
@@ -377,6 +386,7 @@ impl RenderTarget for PageContent {
if self.measure_only {
return;
}
+ self.control_relief_marks.push(self.rects.len());
self.control_reliefs.push(ControlCarve::Step(*carve));
}
diff --git a/src/main.rs b/src/main.rs
index 77d118d..3f57922 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -47,6 +47,10 @@ struct SystemInterface {
/// Popover-layer inset plates (window coords, scroll already applied) —
/// the dropdown's grown-trigger surface via the inset_plate hook.
popover_control_reliefs: Vec<ControlCarve>,
+ /// Per popover carve, the index into `popover_widgets` it precedes
+ /// (`PageContent::control_relief_marks`) — display_list slots each carve
+ /// back between the rects the widget drew before and after it.
+ popover_control_relief_marks: Vec<usize>,
page_buttons: Vec<(cce_ui::widget::Adapted<cce_ui::widget::Button>, AppAction)>,
sidebar_width: f32,
@@ -168,6 +172,7 @@ impl cce_ui::engine::Application for SystemInterface {
popover_widgets: Vec::new(),
popover_texts: Vec::new(),
popover_control_reliefs: Vec::new(),
+ popover_control_relief_marks: Vec::new(),
page_buttons: Vec::new(),
sidebar_width,
header_height: 0.0,
@@ -504,19 +509,13 @@ impl cce_ui::engine::Application for SystemInterface {
if let Some((qx, qy, qw, qh, qc)) = cce_ui::widget::hover_animation::get_quad() {
pc.quad(Rect { x: qx, y: qy - self.scroll_y, width: qw, height: qh }, qc);
}
- for w in &self.popover_widgets {
- let rect = Rect { x: w.x, y: w.y, width: w.w, height: w.h };
- if w.radius > 0.1 {
- pc.rounded_rect(rect, w.radius, w.corners, w.color);
- } else {
- pc.quad(rect, w.color);
- }
- }
- // Popover surfaces claimed through the inset_plate hook (the dropdown's
- // grown-trigger plate): real relief prims at the popover layer, over
- // the page and its control troughs.
- for &carve in &self.popover_control_reliefs {
- match carve {
+ // Popover rects and the surfaces claimed through the inset_plate hook
+ // (the dropdown's menu plate), replayed in the widget's OWN order:
+ // each carve goes out just before the rect it was claimed ahead of,
+ // so the hovered-row highlight a Dropdown draws after its plate lands
+ // on top of the frosted face instead of underneath it.
+ {
+ let emit_carve = |pc: &mut cce_ui::scene::paint::PaintCtx, carve: ControlCarve| match carve {
ControlCarve::Plate { x, y, w, h, radius, depth, color } => pc.inset_plate(
Rect { x, y, width: w, height: h },
(radius, radius, radius, radius),
@@ -524,6 +523,27 @@ impl cce_ui::engine::Application for SystemInterface {
depth,
),
ControlCarve::Step(c) => pc.carve(&c),
+ };
+ let mut carves = self
+ .popover_control_reliefs
+ .iter()
+ .copied()
+ .zip(self.popover_control_relief_marks.iter().copied())
+ .peekable();
+ for (i, w) in self.popover_widgets.iter().enumerate() {
+ while carves.peek().map_or(false, |&(_, mark)| mark <= i) {
+ let (carve, _) = carves.next().unwrap();
+ emit_carve(&mut pc, carve);
+ }
+ let rect = Rect { x: w.x, y: w.y, width: w.w, height: w.h };
+ if w.radius > 0.1 {
+ pc.rounded_rect(rect, w.radius, w.corners, w.color);
+ } else {
+ pc.quad(rect, w.color);
+ }
+ }
+ for (carve, _) in carves {
+ emit_carve(&mut pc, carve);
}
}
for (text, font_size, x, y, col, font, bounds) in self.texts.iter().chain(self.popover_texts.iter()) {
diff --git a/src/renderer.rs b/src/renderer.rs
index 4aa2e66..45d8064 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -656,6 +656,9 @@ impl SystemInterface {
}
}
}
+ // The chrome popover's rects are already in place: the page
+ // carves' marks shift past them so the interleave stays true.
+ let rect_base = popover_pc.rects.len();
for (c, x, y, w, h, r, corners) in page_pop_pc.rects {
popover_pc.rects.push((c, x, y - self.scroll_y, w, h, r, corners));
}
@@ -663,8 +666,9 @@ impl SystemInterface {
let shifted = bounds.map(|[l, tb, rr, b]| [l, tb - self.scroll_y, rr, b - self.scroll_y]);
popover_pc.texts.push((t, size, x, y - self.scroll_y, tc, font, shifted));
}
- for carve in page_pop_pc.control_reliefs {
+ for (carve, mark) in page_pop_pc.control_reliefs.into_iter().zip(page_pop_pc.control_relief_marks) {
popover_pc.control_reliefs.push(carve.shifted_y(-self.scroll_y));
+ popover_pc.control_relief_marks.push(rect_base + mark);
}
}
if cce_ui::widget::context_menu::is_visible() {
@@ -703,6 +707,7 @@ impl SystemInterface {
}).collect();
self.popover_texts = popover_pc.texts;
self.popover_control_reliefs = popover_pc.control_reliefs;
+ self.popover_control_relief_marks = popover_pc.control_relief_marks;
self.widgets = widgets;
self.texts = texts;