git.lucas.co / cce-designer
graphic design tool
git clone https://git.lucas.co/cce-designer.git

commit6694eb677ddc4737a24b8bf76cef5d8393c65c18
parentd5545c1722
authorLucas Galante <[email protected]>
date2026-08-03 14:48
fix: open popovers occlude the text beneath them

The engine's text-occlusion clamp reads ui_context.active_popovers, but
only the legacy render_widget helper ever registered popovers — the
designer's own paint walk never did, so the clamp ran against an empty
list and text behind open dropdown popups bled through their plates.
collect_display_list now refreshes the registration each frame from the
slots' popover_rect()s.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/render.rs | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/render.rs b/src/render.rs
index 31bc8a9..10a1a2f 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -60,6 +60,18 @@ impl State {
     /// cache are gone). Draw order is the hand-maintained slot order the vertex path
     /// used; the circular network pane rides `PaintItem::clip_circle`.
     pub(crate) fn collect_display_list(&mut self) -> DisplayList {
+        // Refresh popover registration: the engine's text-occlusion clamp
+        // reads `ui_context.active_popovers` to keep underlying text from
+        // bleeding through an open popup's plate. The legacy render_widget
+        // helper registered these as a side effect; the designer's own paint
+        // walk must do it explicitly or open dropdowns get no occlusion.
+        self.ui_context.clear_popovers();
+        for i in 0..WIDGET_COUNT {
+            if self.slots.get_dyn(i).visible() && self.slots.get_dyn(i).popover_rect().is_some() {
+                self.ui_context.register_popover(self.slots.get_dyn_mut(i));
+            }
+        }
+
         let show_cursor = self.drag_widget.is_none() && self.app_drag.is_none();
 
         // The graph content clip (node quads, cursor) and the circular pane clip.