Skip to main content

fret_runtime/
docking_settings.rs

1use fret_core::{Modifiers, Px};
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub struct DockingInteractionSettings {
5    pub drag_inversion: DockDragInversionSettings,
6    /// Drag activation threshold for docking tab drags (window-local logical pixels).
7    pub tab_drag_threshold: Px,
8    /// Split handle hit thickness (window-local logical pixels).
9    ///
10    /// Dear ImGui exposes this concept as `Style.DockingSeparatorSize` (scaled).
11    pub split_handle_hit_thickness: Px,
12    /// Split handle gap between panels (window-local logical pixels).
13    ///
14    /// This is kept as an explicit knob because it affects both:
15    /// - the computed panel rects, and
16    /// - the split handle centers/hit rects.
17    pub split_handle_gap: Px,
18    /// Drag distance threshold for suppressing viewport right-click context menus (screen px).
19    ///
20    /// Docking forwards viewport pointer input via `Effect::ViewportInput` and uses pointer capture
21    /// to keep delivering events when the cursor leaves the viewport bounds.
22    ///
23    /// For editor-like viewports, it is common to support both:
24    /// - right-click context menus (when the pointer does not move), and
25    /// - right-drag navigation (orbit/pan) without a context menu on release.
26    ///
27    /// When this value is exceeded during a right-button viewport capture, docking will suppress
28    /// bubbling on the matching `PointerUp` so context-menu primitives upstream do not trigger.
29    pub viewport_context_menu_drag_threshold: Px,
30    /// When true, suppress bubbling of secondary right-click events while a viewport capture
31    /// session is active (e.g. during a left-drag marquee).
32    pub suppress_context_menu_during_viewport_capture: bool,
33    /// Scale factor for the inner docking hint pad geometry (1.0 matches current ImGui-parity).
34    pub dock_hint_scale_inner: f32,
35    /// Scale factor for the outer docking hint pad geometry (1.0 matches current ImGui-parity).
36    pub dock_hint_scale_outer: f32,
37    /// Optional ImGui-style "transparent payload" behavior when a dock tear-off window is
38    /// following the cursor.
39    ///
40    /// When enabled, the runner may:
41    /// - make the dock-floating OS window semi-transparent, and
42    /// - ignore mouse events for it ("NoInputs"), so hovered-window selection can "peek behind"
43    ///   the moving window in overlap cases.
44    ///
45    /// Default is `false` to keep multi-window behavior conservative across platforms/backends.
46    pub transparent_payload_during_follow: bool,
47    /// Optional ImGui-style "follow window" behavior during docking drags.
48    ///
49    /// When enabled, docking interactions may request the runner to treat certain dock drags as a
50    /// "move the OS window" gesture (while still allowing cross-window hover/drop routing).
51    ///
52    /// This is intentionally conservative by default: runners vary in how reliable it is to move
53    /// OS windows at high frequency, and the UX depends on also supporting "peek behind the moving
54    /// window" hover semantics.
55    pub follow_window_during_drag: bool,
56    /// Alpha multiplier for the tear-off payload window while following the cursor.
57    ///
58    /// ImGui uses `0.50` for `ConfigDockingTransparentPayload`.
59    pub transparent_payload_alpha: f32,
60}
61
62impl Default for DockingInteractionSettings {
63    fn default() -> Self {
64        Self {
65            drag_inversion: DockDragInversionSettings::default(),
66            tab_drag_threshold: Px(6.0),
67            split_handle_hit_thickness: Px(6.0),
68            split_handle_gap: Px(0.0),
69            viewport_context_menu_drag_threshold: Px(6.0),
70            suppress_context_menu_during_viewport_capture: true,
71            dock_hint_scale_inner: 1.0,
72            dock_hint_scale_outer: 1.0,
73            transparent_payload_during_follow: false,
74            follow_window_during_drag: false,
75            transparent_payload_alpha: 0.5,
76        }
77    }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub struct DockDragInversionSettings {
82    pub modifier: DockDragInversionModifier,
83    pub policy: DockDragInversionPolicy,
84}
85
86impl Default for DockDragInversionSettings {
87    fn default() -> Self {
88        Self {
89            modifier: DockDragInversionModifier::Shift,
90            policy: DockDragInversionPolicy::DockByDefault,
91        }
92    }
93}
94
95impl DockDragInversionSettings {
96    pub fn wants_dock_previews(self, modifiers: Modifiers) -> bool {
97        let modifier_down = self.modifier.is_down(modifiers);
98        match self.policy {
99            DockDragInversionPolicy::DockByDefault => !modifier_down,
100            DockDragInversionPolicy::DockOnlyWhenModifier => modifier_down,
101        }
102    }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum DockDragInversionModifier {
107    None,
108    Shift,
109    Ctrl,
110    Alt,
111    AltGr,
112    Meta,
113}
114
115impl DockDragInversionModifier {
116    pub fn is_down(self, modifiers: Modifiers) -> bool {
117        match self {
118            Self::None => false,
119            Self::Shift => modifiers.shift,
120            Self::Ctrl => modifiers.ctrl,
121            Self::Alt => modifiers.alt,
122            Self::AltGr => modifiers.alt_gr,
123            Self::Meta => modifiers.meta,
124        }
125    }
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum DockDragInversionPolicy {
130    DockByDefault,
131    DockOnlyWhenModifier,
132}