From 0be7609bf7eb987949ae328b6c5e3d2ae81f6582 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sun, 1 Nov 2026 15:31:53 -0800 Subject: [PATCH] Tabs: Above Text checks the place below text against the window's top The place below the text was taken even when the text was panned above the canvas, which put the panel above the main window. It is now taken only when it is at or below the window's top. A docked Tabs panel is measured at the 360-point height it floats at, not 240, so it is placed below the text only when it fits there. --- crates/ui-egui/src/panel_docking.rs | 2 +- crates/ui-egui/src/panels/tabs.rs | 14 +++++++++----- crates/ui-egui/src/panels/tabs/tests.rs | 25 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/crates/ui-egui/src/panel_docking.rs b/crates/ui-egui/src/panel_docking.rs index 83cad5282..a35166d97 100644 --- a/crates/ui-egui/src/panel_docking.rs +++ b/crates/ui-egui/src/panel_docking.rs @@ -1237,7 +1237,7 @@ const DOCK_LABELS: &[(&str, &str)] = &[ ]; /// The size a panel floats at (tab strip included), whatever the size of the dock it left. -fn floating_size(panel: &str) -> egui::Vec2 { +pub(crate) fn floating_size(panel: &str) -> egui::Vec2 { match panel { "properties" | "layers" | "libraries" => egui::vec2(300.0, 420.0), // Tall enough to show its Corners and Shared Edges sections, last in it, which the Corner diff --git a/crates/ui-egui/src/panels/tabs.rs b/crates/ui-egui/src/panels/tabs.rs index ae49d2048..c8ef4331c 100644 --- a/crates/ui-egui/src/panels/tabs.rs +++ b/crates/ui-egui/src/panels/tabs.rs @@ -264,15 +264,19 @@ fn above_text(app: &mut VectorcraftApp, ctx: &egui::Context, n: &Node, span: f64 return None; } let width = span as f32 * per + RULER_LEFT * 2.0; - let height = crate::panel_docking::layout_of(&app.ui).floating.iter().find(|w| w.contains(&"tabs".to_string())).map_or(240.0, |w| w.rect[3]); - // Text near the top of the window: the panel goes just below the text when it fits there in - // the canvas, else at the window's top, so its bar stays where it can be grabbed rather than - // above the screen. + let height = crate::panel_docking::layout_of(&app.ui) + .floating + .iter() + .find(|w| w.contains(&"tabs".to_string())) + .map_or(crate::panel_docking::floating_size("tabs").y, |w| w.rect[3]); + // Text near the top of the window: the panel goes just below the text when that place is in + // the window and the panel fits there in the canvas, else at the window's top, so its bar + // stays where it can be grabbed rather than above the screen. let above = on_screen.top() - height - 6.0; let below = on_screen.bottom() + 6.0; let top = if above >= 0.0 { above - } else if below + height <= app.canvas_rect.map_or(f32::NEG_INFINITY, |c| c.bottom()) { + } else if below >= 0.0 && below + height <= app.canvas_rect.map_or(f32::NEG_INFINITY, |c| c.bottom()) { below } else { 0.0 diff --git a/crates/ui-egui/src/panels/tabs/tests.rs b/crates/ui-egui/src/panels/tabs/tests.rs index 8a6d2394e..7b02b72ff 100644 --- a/crates/ui-egui/src/panels/tabs/tests.rs +++ b/crates/ui-egui/src/panels/tabs/tests.rs @@ -1081,3 +1081,28 @@ fn above_text_keeps_the_panel_bar_in_the_window() { assert_eq!(g.native.unwrap()[1], 100.0 + top, "text {text_height} high: the OS window"); } } + +/// Position Panel Above Text puts the panel at the window's top when the place below the text is +/// above the window (text panned above the canvas), or when the panel at the height it floats at +/// does not fit below the text in the canvas. +#[test] +fn above_text_puts_the_panel_at_the_top_when_below_the_text_does_not_fit() { + // The view's centre and the text's height: panned so the text is above the canvas, and a text + // whose bottom leaves room for 240 points of panel but not for the 360 it floats at. + for (center_y, text_height) in [(600.0, 100.0), (350.0, 340.0)] { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 600, "height": 800})).unwrap(); + app.session.execute("text.create", &json!({"x": 40, "y": 20, "text": "a b", "area": {"width": 300, "height": text_height}})).unwrap(); + app.canvas_rect = Some(egui::Rect::from_min_size(egui::pos2(50.0, 40.0), vec2(1000.0, 700.0))); + if let Some(v) = app.view_mut() { + v.zoom = 1.0; + v.center = vectorcraft_geom::Point::new(300.0, center_y); + } + let (node, _, span) = current(&app).unwrap(); + let ctx = egui::Context::default(); + above_text(&mut app, &ctx, &node, span).unwrap(); + let layout = app.ui.docking.clone().unwrap(); + let g = layout.floating.iter().find(|w| w.contains(&"tabs".to_string())).unwrap(); + assert_eq!(g.rect[1], 0.0, "view centered at y {center_y}"); + } +}