From 0a60b36b669c9e10eabef1ed22b8e7027d095ff9 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Sun, 5 Jul 2026 15:03:11 +0300 Subject: [PATCH] fix(ui): open the OSNAP settings popup near its button, not the corner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The snap popup used a hardcoded 4 px right offset, pinning it to the window's right edge — but the Osnap button sits well to the left, with up to ten pills after it (Space, Scale, Units, Transparency, Isolate, …). Anchor it by the summed width of the pills that follow Osnap, honouring the user's per-pill visibility. iced gives the view no real layout metrics, so the pill widths are estimated (icon pills fixed, labelled pills approximate); the popup now opens by the button instead of the corner. Closes #248 Co-Authored-By: Claude Opus 4.8 --- src/app/view/mod.rs | 8 +++++++- src/ui/statusbar/mod.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/app/view/mod.rs b/src/app/view/mod.rs index cb2aec467..dfe52c1dc 100644 --- a/src/app/view/mod.rs +++ b/src/app/view/mod.rs @@ -1262,7 +1262,13 @@ impl OpenCADStudio { .height(Fill); let snap_layer: Element<'_, Message> = if self.snap_popup_open { - crate::ui::popup::snap_popup::snap_popup_overlay(&self.snapper, 4.0) + crate::ui::popup::snap_popup::snap_popup_overlay( + &self.snapper, + crate::ui::statusbar::osnap_popup_right_offset( + &self.statusbar_config, + tab.scene.viewport_count(), + ), + ) } else { iced::widget::Space::new().width(0).height(0).into() }; diff --git a/src/ui/statusbar/mod.rs b/src/ui/statusbar/mod.rs index 2b543e137..d501d3467 100644 --- a/src/ui/statusbar/mod.rs +++ b/src/ui/statusbar/mod.rs @@ -404,6 +404,41 @@ fn tip_node<'a>(content: Element<'a, Message>, body: Element<'a, Message>) -> El /// A status-bar toggle, drawn as a tinted icon (issue #216: the old size-10 /// text labels were too small to read). The name lives in the tooltip each /// call site already wraps it with. +/// Approximate distance (px) from the window's right edge to the right edge of +/// the Osnap button — used to anchor the OSNAP settings popup above the button +/// instead of at the window corner (#248). The status-bar pills that follow +/// Osnap are summed by estimated width (icon pills are fixed; labelled pills are +/// approximate), honouring the user's per-pill visibility. iced gives the view +/// no real layout metrics, so this positions the popup near the button rather +/// than pixel-exact. +pub fn osnap_popup_right_offset(config: &StatusBarConfig, viewport_count: usize) -> f32 { + const SP: f32 = 2.0; // right_status row spacing between pills + const TOGGLE: f32 = 33.0; // icon toggle pill (17px icon + [4,7] pad + border) + // Pills after Osnap, in bar order, with estimated widths. + let after = [ + (StatusPill::Space, 58.0), + (StatusPill::Scale, 92.0), + (StatusPill::Units, 42.0), + (StatusPill::Transparency, TOGGLE), + (StatusPill::Isolate, TOGGLE), + (StatusPill::QuickProps, TOGGLE), + (StatusPill::SelFilter, TOGGLE), + (StatusPill::SelCycle, TOGGLE), + (StatusPill::Vp, 46.0), + (StatusPill::CleanScreen, TOGGLE), + ]; + // Bar right margin + the always-present customization button. + let mut w = 6.0 + 30.0 + SP; + for (pill, pw) in after { + let shown = + config.is_visible(pill) && !(matches!(pill, StatusPill::Vp) && viewport_count == 0); + if shown { + w += pw + SP; + } + } + w +} + fn toggle_pill(icon: &'static [u8], active: bool, msg: Message) -> Element<'static, Message> { let color = if active { OSNAP_ON_TEXT } else { OSNAP_OFF_TEXT }; button(crate::ui::icons::tinted(icon, 17.0, color))