Skip to main content

egui_charts/config/
interaction.rs

1//! Scroll, zoom, and tracking interaction options.
2//!
3//! Controls how mouse/touch gestures are interpreted: which gestures
4//! pan the chart, which zoom it, and how the tracking-mode (crosshair
5//! following) behaves.
6
7/// How tracking mode (crosshair auto-follow) is exited.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
9pub enum TrackingModeExitMode {
10    /// Exit tracking mode when touch/click ends
11    OnTouchEnd,
12
13    /// Exit tracking mode when mouse leaves the chart area
14    OnMouseLeave,
15
16    /// Exit tracking mode on the next tap/click
17    #[default]
18    OnNextTap,
19}
20
21/// Tracking mode options
22/// Controls automatic price following behavior
23#[derive(Debug, Clone, Copy, Default, PartialEq, serde::Serialize, serde::Deserialize)]
24pub struct TrackingModeOptions {
25    /// How to exit tracking mode
26    /// Default: OnNextTap
27    pub exit_mode: TrackingModeExitMode,
28}
29
30/// Handle Scroll Options
31/// Controls how scrolling/panning interactions work
32
33#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
34#[serde(default)]
35pub struct HandleScrollOptions {
36    /// Enable scroll gestures and their momentum without changing individual options.
37    /// Default: true
38    pub enabled: bool,
39
40    /// Scroll with mouse wheel (horizontal)
41    /// Default: true
42    pub mouse_wheel: bool,
43
44    /// Drag with left mouse button to pan
45    /// Default: true
46    pub pressed_mouse_move: bool,
47
48    /// Horizontal drag on touch devices
49    /// Default: true
50    pub horz_touch_drag: bool,
51
52    /// Vertical drag on touch devices
53    /// Default: true
54    pub vert_touch_drag: bool,
55}
56
57impl Default for HandleScrollOptions {
58    fn default() -> Self {
59        Self {
60            enabled: true,
61            mouse_wheel: true,
62            pressed_mouse_move: true,
63            horz_touch_drag: true,
64            vert_touch_drag: true,
65        }
66    }
67}
68
69/// Axis-specific pressed mouse move options
70#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
71pub struct AxisPressedMouseMoveOptions {
72    /// Drag along time axis (bottom)
73    /// Default: true
74    pub time: bool,
75
76    /// Drag on price scale (right/left)
77    /// Default: true
78    pub price: bool,
79}
80
81impl Default for AxisPressedMouseMoveOptions {
82    fn default() -> Self {
83        Self {
84            time: true,
85            price: true,
86        }
87    }
88}
89
90/// Axis-specific double-click reset options
91#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
92pub struct AxisDoubleClickResetOptions {
93    /// Double-click time axis to reset
94    /// Default: true
95    pub time: bool,
96
97    /// Double-click price axis to reset
98    /// Default: true
99    pub price: bool,
100}
101
102impl Default for AxisDoubleClickResetOptions {
103    fn default() -> Self {
104        Self {
105            time: true,
106            price: true,
107        }
108    }
109}
110
111/// Handle Scale Options
112/// Controls how zoom/scale interactions work
113
114#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
115#[serde(default)]
116pub struct HandleScaleOptions {
117    /// Enable wheel, pinch, axis drag and axis reset gestures without changing individual options.
118    /// Default: true
119    pub enabled: bool,
120
121    /// Zoom with mouse wheel (vertical scroll)
122    /// Default: true
123    pub mouse_wheel: bool,
124
125    /// Pinch zoom (touchpad / mobile)
126    /// Default: true
127    pub pinch: bool,
128
129    /// Click + drag axes to zoom
130    pub axis_pressed_mouse_move: AxisPressedMouseMoveOptions,
131
132    /// Double-click to reset scaling
133    pub axis_double_click_reset: AxisDoubleClickResetOptions,
134}
135
136impl Default for HandleScaleOptions {
137    fn default() -> Self {
138        Self {
139            enabled: true,
140            mouse_wheel: true,
141            pinch: true,
142            axis_pressed_mouse_move: AxisPressedMouseMoveOptions::default(),
143            axis_double_click_reset: AxisDoubleClickResetOptions::default(),
144        }
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    #[test]
153    fn test_tracking_mode_exit_mode_default() {
154        let mode = TrackingModeExitMode::default();
155        assert_eq!(mode, TrackingModeExitMode::OnNextTap);
156    }
157
158    /// Layouts saved before group switches retain their individual permissions and stay enabled.
159    #[test]
160    fn saved_handler_options_default_missing_group_switches_to_enabled() {
161        let scroll: HandleScrollOptions = serde_json::from_value(serde_json::json!({
162            "mouse_wheel": false, "pressed_mouse_move": true,
163            "horz_touch_drag": false, "vert_touch_drag": true
164        }))
165        .unwrap();
166        let scale: HandleScaleOptions = serde_json::from_value(serde_json::json!({
167            "mouse_wheel": true, "pinch": false,
168            "axis_pressed_mouse_move": {"time": false, "price": true},
169            "axis_double_click_reset": {"time": true, "price": false}
170        }))
171        .unwrap();
172        assert!(scroll.enabled && scale.enabled);
173        assert!(!scroll.mouse_wheel && !scroll.horz_touch_drag);
174        assert!(!scale.pinch && !scale.axis_pressed_mouse_move.time);
175        assert!(!scale.axis_double_click_reset.price);
176    }
177}