diff --git a/src/app/dock/update.rs b/src/app/dock/update.rs index 9f0c6eec2..ad0b89cc8 100644 --- a/src/app/dock/update.rs +++ b/src/app/dock/update.rs @@ -30,7 +30,7 @@ impl OpenCADStudio { /// whichever panel the message names. pub(crate) fn on_dock(&mut self, m: crate::ui::dock::DockMsg) -> iced::Task { use crate::app::config::DockSide; - use crate::ui::dock::{DockDrag, DockMsg, DropTarget, FloatPanel}; + use crate::ui::dock::{DockDrag, DockMsg, DropTarget, FloatPanel, HoverPending}; match m { DockMsg::DockGrab(id) => self.dock_begin(DockDrag::moving(id, None), Some(id)), DockMsg::IconPress(id) => { @@ -160,7 +160,7 @@ impl OpenCADStudio { if self.dock_peek == Some(id) { self.dock_hover_cancel(); } else { - return self.dock_hover_arm(Some(id)); + return self.dock_hover_arm(HoverPending::Reveal(id)); } } } @@ -173,21 +173,25 @@ impl OpenCADStudio { if self.dock_drag.is_none() && self.dock_peek.is_some_and(|id| self.dock.auto_hides(id)) { - return self.dock_hover_arm(None); + return self.dock_hover_arm(HoverPending::Hide); } // Left before a pending reveal ran out: it never happens. self.dock_hover_cancel(); } DockMsg::HoverStay => { - if self.dock_hover_pending == Some(None) { + if self.dock_hover_pending == Some(HoverPending::Hide) { self.dock_hover_cancel(); } } DockMsg::HoverSettled(gen) => { if gen == self.dock_hover_gen && self.dock_drag.is_none() { match self.dock_hover_pending.take() { - Some(Some(id)) if self.dock.auto_hides(id) => self.dock_reveal(id), - Some(None) if self.dock_peek.is_some_and(|id| self.dock.auto_hides(id)) => { + Some(HoverPending::Reveal(id)) if self.dock.auto_hides(id) => { + self.dock_reveal(id) + } + Some(HoverPending::Hide) + if self.dock_peek.is_some_and(|id| self.dock.auto_hides(id)) => + { self.dock_peek = None; } _ => {} @@ -280,13 +284,13 @@ impl OpenCADStudio { grab }; let target = if started { - // A whole group only moves between group positions: it - // cannot join another group or float. // A floating panel that may not dock only floats. let found = match self.dock.float_rect(panel) { Some(f) if !f.docking => self.dock_float_target(point, grab), _ => self.dock_drop_target(point, grab), }; + // A whole group only moves between group positions: it + // cannot join another group or float. match (group, found) { (Some(_), found @ DropTarget::Edge { .. }) | (None, found) => Some(found), (Some(_), _) => None, @@ -381,11 +385,9 @@ impl OpenCADStudio { } } - /// Bring `id` into view: show its group on its edge and, where it - /// auto-hides, keep it revealed until the pointer leaves. - /// Arm a delayed reveal (`Some`) or hide (`None`); it applies when its - /// timer reports back unless a newer hover superseded it. - fn dock_hover_arm(&mut self, target: Option) -> iced::Task { + /// Arm a delayed reveal or hide; it applies when its timer reports back + /// unless a newer hover superseded it. + fn dock_hover_arm(&mut self, target: crate::ui::dock::HoverPending) -> iced::Task { self.dock_hover_gen = self.dock_hover_gen.wrapping_add(1); self.dock_hover_pending = Some(target); let gen = self.dock_hover_gen; @@ -400,6 +402,8 @@ impl OpenCADStudio { self.dock_hover_pending = None; } + /// Bring `id` into view: show its group on its edge and, where it + /// auto-hides, keep it revealed until the pointer leaves. pub(crate) fn dock_reveal(&mut self, id: crate::ui::dock::PanelId) { self.dock.show_group_of(id); self.dock_peek = Some(id); diff --git a/src/app/dock/view.rs b/src/app/dock/view.rs index 91ba479ca..bd5b01864 100644 --- a/src/app/dock/view.rs +++ b/src/app/dock/view.rs @@ -444,7 +444,7 @@ impl OpenCADStudio { tab: &'a DocumentTab, ) -> Element<'a, Message> { use crate::ui::dock::DockMsg; - let (x, y, bar_left, hidden) = self.dock_float_frame(f); + let FloatFrame { x, y, bar_left, hidden } = self.dock_float_frame(f); let hovered = self.dock_title_hover == Some(f.id); let bar = floating_title_bar(f.id, self.dock.auto_collapse(f.id), bar_left, hovered); let content: Element<'_, Message> = if hidden { @@ -519,10 +519,8 @@ impl OpenCADStudio { place_at(panel.into(), x, y) } - /// Where floating panel `f` draws: its top-left corner, whether its - /// title bar is on the left, and whether it is hidden down to that bar - /// (auto-hide, not hovered). - fn dock_float_frame(&self, f: crate::ui::dock::FloatPanel) -> (f32, f32, bool, bool) { + /// Where floating panel `f` draws. + fn dock_float_frame(&self, f: crate::ui::dock::FloatPanel) -> FloatFrame { let (ww, wh) = self.dock_workspace_size(); // The bar faces the nearer workspace edge; while resizing, it stays // opposite the grip being dragged so it cannot flip mid-drag. @@ -533,13 +531,15 @@ impl OpenCADStudio { _ => f.x + (f.w + DOCK_FLOAT_BAR_W) * 0.5 < ww * 0.5, }; let hidden = self.dock.auto_collapse(f.id) && self.dock_peek != Some(f.id); - let total_w = if hidden { DOCK_FLOAT_BAR_W } else { f.w + DOCK_FLOAT_BAR_W }; // A hidden panel keeps its title bar where it sits when shown. let x = if hidden && !bar_left { f.x + f.w } else { f.x }; + let frame = FloatFrame { x, y: f.y, bar_left, hidden }; // Keep the panel on screen when the window shrank since it was placed. - let x = x.min(ww - total_w).max(0.0); - let y = f.y.min(wh - f.h).max(0.0); - (x, y, bar_left, hidden) + FloatFrame { + x: x.min(ww - frame.width(f)).max(0.0), + y: f.y.min(wh - f.h).max(0.0), + ..frame + } } /// The open right-click menu of a floating title bar: Allow docking, @@ -554,11 +554,12 @@ impl OpenCADStudio { return None; } let (ww, wh) = self.dock_workspace_size(); - let (x, y, bar_left, hidden) = self.dock_float_frame(f); - let total_w = if hidden { DOCK_FLOAT_BAR_W } else { f.w + DOCK_FLOAT_BAR_W }; - let bar_x = if bar_left { x } else { x + total_w - DOCK_FLOAT_BAR_W }; + let frame = self.dock_float_frame(f); // Where the right-click happened, in the workspace. - let at = iced::Point::new(bar_x + self.dock_float_menu_at.x, y + self.dock_float_menu_at.y); + let at = iced::Point::new( + frame.bar_x(f) + self.dock_float_menu_at.x, + frame.y + self.dock_float_menu_at.y, + ); let menu_x = if at.x + DOCK_MENU_W <= ww { at.x } else { at.x - DOCK_MENU_W }; let menu_x = menu_x.clamp(0.0, (ww - DOCK_MENU_W).max(0.0)); let menu_y = at.y.min(wh - FLOAT_MENU_H).max(0.0); @@ -880,6 +881,38 @@ impl canvas::Program for VBarLabel { /// Width of a floating panel's vertical title bar. const DOCK_FLOAT_BAR_W: f32 = 28.0; +/// Where a floating panel draws: its top-left corner, whether its title bar +/// is on the left, and whether it is hidden down to that bar (auto-hide, not +/// hovered). +#[derive(Debug, Clone, Copy)] +struct FloatFrame { + x: f32, + y: f32, + bar_left: bool, + hidden: bool, +} + +impl FloatFrame { + /// On-screen width of panel `f` in this frame: the bar, plus the panel + /// unless hidden. + fn width(&self, f: crate::ui::dock::FloatPanel) -> f32 { + if self.hidden { + DOCK_FLOAT_BAR_W + } else { + f.w + DOCK_FLOAT_BAR_W + } + } + + /// Left edge of the title bar. + fn bar_x(&self, f: crate::ui::dock::FloatPanel) -> f32 { + if self.bar_left { + self.x + } else { + self.x + self.width(f) - DOCK_FLOAT_BAR_W + } + } +} + /// A floating panel's vertical title bar: close then the hide (auto-collapse) /// pin at the top, the panel's icon at the bottom with its title reading /// upward above it. Pressing the bar's free area drags the panel. diff --git a/src/app/mod.rs b/src/app/mod.rs index adbfcb285..bb5afd86f 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -850,9 +850,9 @@ pub(super) struct OpenCADStudio { /// floating frame): hovered, being dragged, or just opened. Cleared when /// the pointer leaves. pub(crate) dock_peek: Option, - /// Reveal (`Some(pallet)`) or hide (`None`) waiting out the hover delay, - /// with the generation its timer carries; any newer hover supersedes it. - pub(crate) dock_hover_pending: Option>, + /// Reveal or hide waiting out the hover delay, with the generation its + /// timer carries; any newer hover supersedes it. + pub(crate) dock_hover_pending: Option, pub(crate) dock_hover_gen: u64, /// What the pointer is dragging in the dock (pallet, group, width, /// splitter, floating size, Layer Manager column). diff --git a/src/ui/dock.rs b/src/ui/dock.rs index 6015b694e..5ef7d1986 100644 --- a/src/ui/dock.rs +++ b/src/ui/dock.rs @@ -86,6 +86,15 @@ pub enum DockMsg { HoverSettled(u64), } +/// An auto-hide change waiting out [`DOCK_HOVER_DELAY`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum HoverPending { + /// Reveal this pallet (its group, or its floating frame). + Reveal(PanelId), + /// Hide whatever auto-hiding pallet is revealed. + Hide, +} + /// How long the pointer must rest before an auto-hiding group reveals or /// hides, so passing over the strip doesn't flash groups open. pub const DOCK_HOVER_DELAY: std::time::Duration = std::time::Duration::from_millis(150);