From 1cb5f403fc76625e83ed182dd05d2f884246f855 Mon Sep 17 00:00:00 2001 From: Ridzzz0Alam Date: Sat, 24 Oct 2026 11:52:57 +0200 Subject: [PATCH] M1: a section's title draws above the labels of frames inside it (#1150) boards() listed a section before its contents, so the label of a frame near the section's top-left was painted over the section's title pill, and label_at (last label wins) gave clicks on the pill to that frame. A section now comes after everything inside it: its pill draws on top and takes the click. Test: a_sections_pill_is_above_the_labels_of_frames_inside_it (fails on the old order). --- crates/ui-egui/src/canvas.rs | 6 ++++-- crates/ui-egui/src/frame_label_tests.rs | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 5ced1edc..2d6a19f0 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -1470,7 +1470,9 @@ fn hatch(polys: &[Vec], gap: f32) -> Vec<[Pos2; 2]> { } /// The layers that get canvas labels and layout grids, in z-order: the page's visible top-level -/// layers and, inside sections whose contents show, their visible children (sections nest). +/// layers and, inside sections whose contents show, their visible children (sections nest). A +/// section comes after its children, so its title pill draws over (and takes clicks from) the +/// labels of frames near its top-left (#1150). fn boards(doc: &Document, page: NodeId) -> Vec { fn walk(doc: &Document, id: NodeId, depth: usize, out: &mut Vec) { let Some(n) = doc.node(id) else { return }; @@ -1479,10 +1481,10 @@ fn boards(doc: &Document, page: NodeId) -> Vec { if !cn.visible { continue; } - out.push(*c); if matches!(cn.kind, NodeKind::Section { contents_hidden: false }) && depth < 32 { walk(doc, *c, depth + 1, out); } + out.push(*c); } } let mut out = Vec::new(); diff --git a/crates/ui-egui/src/frame_label_tests.rs b/crates/ui-egui/src/frame_label_tests.rs index 687669e8..6c15fc00 100644 --- a/crates/ui-egui/src/frame_label_tests.rs +++ b/crates/ui-egui/src/frame_label_tests.rs @@ -156,3 +156,23 @@ fn a_sections_label_renames_it_and_a_click_elsewhere_commits() { assert!(u.app.ui.rename_label.is_none()); assert_eq!(u.app.session.ds().unwrap().history.undo.len(), undo + 1, "one undo step"); } + +#[test] +fn a_sections_pill_is_above_the_labels_of_frames_inside_it() { + // A frame near the section's top-left puts its label over the section's pill (#1150): the pill + // draws last, so pressing where they overlap selects the section. + let mut s = Session::new(); + let sec = id(s.execute("node.create", &json!({"type": "section", "x": 0, "y": 0, "width": 300, "height": 200, "name": "Marketing"})).unwrap()); + let f = id(s.execute("frame.create", &json!({"x": 10, "y": 22, "width": 100, "height": 80, "name": "Icon card", "parent": sec})).unwrap()); + s.execute("select.none", &json!({})).unwrap(); + let mut u = Ui::new(s); + u.frame(vec![]); + let at = mid(&label(&u, sec)); + let frame_label = egui::Rect::from_points(&label(&u, f)); + assert!(frame_label.contains(at), "the frame's label {frame_label:?} overlaps the pill at {at:?}"); + let order: Vec = u.app.session.tool.labels.iter().map(|(id, _)| *id).collect(); + assert_eq!(order, vec![f, sec], "the section's label comes after (above) its frames'"); + u.button(at, true); + u.button(at, false); + assert_eq!(u.app.session.selection(), vec![sec]); +}