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}