From 5808bcc0f05b4dd4f40d4f2172859d1cfd69ff93 Mon Sep 17 00:00:00 2001 From: bherbruck Date: Tue, 13 Oct 2026 21:19:45 -0400 Subject: [PATCH] Toolbar drop-downs show all their rows after a shorter list (#874) (#918) * Toolbar drop-downs show all their rows after a shorter list (#874) A panel's drop-down kept its size by an id made from the panel name alone, so PLASTIC's MODIFY reused the one-row size of MESH's MODIFY and showed two rows with a scroll bar. The id now includes the tab, and the rows' scroll area may grow past the size the area remembered (up to the room below it), which also covers the same panel collapsed and expanded. Fixes #874 Co-Authored-By: Claude Opus 5.5 * Keep the Sketch Create menu's own sizing Its rows sit in egui menus (also inside the overflow menu), where a minimum height moved the rows between frames. Only the panel drop-downs need it. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- crates/ui-egui/src/toolbar.rs | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/toolbar.rs b/crates/ui-egui/src/toolbar.rs index e91b4cd2..df727350 100644 --- a/crates/ui-egui/src/toolbar.rs +++ b/crates/ui-egui/src/toolbar.rs @@ -619,7 +619,9 @@ pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) { let sketch_create = tab == "SKETCH" && *panel == "CREATE"; let stride = if sketch_create { 68.0 } else { 40.0 }; let enabled_panel = !cmds.is_empty() || *panel == "SELECT"; - let popup_id = ui.id().with(("panel_menu", panel)); + // Per tab: panels of the same name on other tabs (MODIFY, CREATE…) list other commands, + // and the drop-down's area remembers its size by this id (#874). + let popup_id = ui.id().with(("panel_menu", &tab, panel)); // Dropped on the panel's free space (all of a collapsed panel): the button goes to // its end. let drawn = if collapsed { 0 } else { shown.len() }; @@ -831,8 +833,10 @@ pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) { } } // The rows scroll when the drop-down would run past the window's bottom. + // `min_scrolled_height` lets the rows grow past the size the area kept from + // an earlier, shorter list (#874); they still shrink to fit their content. let room = (ui.ctx().content_rect().bottom() - ui.cursor().top() - 12.0).max(ROW_H * 3.0); - egui::ScrollArea::vertical().id_salt("panel_menu_rows").max_height(room).show(ui, |ui| { + egui::ScrollArea::vertical().id_salt("panel_menu_rows").max_height(room).min_scrolled_height(room).show(ui, |ui| { for c in &cmds { let pinned = crate::toolbar_custom::pinned_on(app, &tab, c.id).is_some(); match dropdown_row(app, ui, c, row_w, pinned) { @@ -1523,6 +1527,33 @@ mod dropdown_tests { let menu = crate::scenario::rect_of("toolbar_dropdown").unwrap(); assert!(menu.contains(*at), "the focused last row is out of view: {at:?} in {menu:?}"); } + + /// Every row of a drop-down is shown when the window has room, even after a shorter list was + /// shown first: another tab's panel of the same name, or the same panel collapsed (#874). + #[test] + fn a_drop_down_shows_all_its_rows_after_a_shorter_one() { + let mut h = crate::scenario::Harness::new(); + h.app.home.open = false; + h.call("ui.resize", json!({"width":1600,"height":1000})); + let open = |h: &mut crate::scenario::Harness, tab: &str| { + h.app.ui.tab = tab.into(); + h.frames(4); + h.step(&json!({"click":{"handle":format!("panel:{tab}:MODIFY")}})).unwrap(); + h.frames(6); + let menu = crate::scenario::rect_of("toolbar_dropdown").expect("the drop-down is open"); + let rows = crate::scenario::handles("dropdown:"); + h.step(&json!({"key":"Escape"})).unwrap(); + h.frames(4); + (menu, rows) + }; + let (short, short_rows) = open(&mut h, "MESH"); + let (menu, rows) = open(&mut h, "PLASTIC"); + assert!(rows.len() > short_rows.len(), "PLASTIC MODIFY lists more than MESH MODIFY: {rows:?} vs {short_rows:?}"); + assert!(menu.height() > short.height(), "the longer list is taller: {menu:?} vs {short:?}"); + for (id, at) in &rows { + assert!(menu.contains(*at), "{id} at {at:?} is cut off by the drop-down {menu:?}"); + } + } } #[cfg(test)]