Dock: review cleanups - hover pending enum, FloatFrame, comment fixes

- dock_hover_pending is an Option<HoverPending> (Reveal / Hide) instead
  of a nested Option.
- dock_float_frame returns a FloatFrame with width() and bar_x(), so the
  floating menu no longer repeats the frame-width formula.
- Put dock_reveal's doc comment back on dock_reveal, and the group-move
  comment back above the match it describes.

No behaviour change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
This commit is contained in:
Claude committed 2026-10-10 11:55:23 +00:00
1 parent 2135dd499a
commit 02404301a5
4 files changed
+75 -29

No files matched your search

+17 -13
View File
@@ -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<Message> {
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<crate::ui::dock::PanelId>) -> iced::Task<Message> {
/// 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<Message> {
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);
+46 -13
View File
@@ -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<Message> 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.
+3 -3
View File
@@ -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<crate::ui::dock::PanelId>,
/// 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<Option<crate::ui::dock::PanelId>>,
/// 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<crate::ui::dock::HoverPending>,
pub(crate) dock_hover_gen: u64,
/// What the pointer is dragging in the dock (pallet, group, width,
/// splitter, floating size, Layer Manager column).
+9
View File
@@ -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);