Skip to main content

egui_charts/ui/drawing_toolbar/
state.rs

1//! Selection, recent tools, favorites and drawing utility state for the toolbar.
2//!
3//! Keep [`ToolbarState`] across frames to retain the user's choices.
4
5use super::DrawingTemplate;
6use super::categories::cursors::CursorType;
7use super::data;
8use crate::drawings::DrawingToolType;
9use std::collections::{HashMap, VecDeque};
10
11/// Types of magnet snapping behavior
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum MagnetType {
14    /// Snap only within the configured pixel threshold
15    Weak,
16    /// Snap to the nearest OHLC value of the bar under the pointer
17    Strong,
18}
19
20/// Drawing toolbar state
21#[derive(Clone)]
22pub struct ToolbarState {
23    /// Currently selected tool
24    pub sel_tool: Option<DrawingToolType>,
25    /// Whether the toolbar is expanded (shows names)
26    pub expanded: bool,
27    /// Currently expanded category (for nested menus)
28    pub expanded_category: Option<String>,
29    /// Favorite tools, in the order they were starred
30    pub favorites: Vec<DrawingToolType>,
31    /// Whether the floating strip of favorite tools is shown while there are favorites
32    pub floating_visible: bool,
33    /// Top-left corner of the floating strip, which the user can drag; `None` until it has been
34    /// shown, when it starts beside the toolbar
35    pub floating_pos: Option<egui::Pos2>,
36    /// Recently used tools (max 5)
37    pub recent: VecDeque<DrawingToolType>,
38    /// Whether drawing anchors snap to nearby chart values and drawing points
39    pub magnet_mode: bool,
40    /// Type of magnet snapping when magnet mode is enabled
41    pub magnet_type: MagnetType,
42    /// Whether magnet targets include visible study plots; independent of its strength.
43    pub snap_to_indicators: bool,
44    /// Whether the user dismissed the card that explains the magnet. Until then the card shows
45    /// beside the magnet button each time the user switches snapping on from the toolbar. Keep it
46    /// with the user's settings, as `UserSettings::magnet_hint_dismissed`; set it to leave the
47    /// card out.
48    pub magnet_hint_dismissed: bool,
49    /// Stay in drawing mode after placing tool
50    pub stay_in_drawing_mode: bool,
51    /// Currently selected drawing color
52    pub drawing_color: [u8; 4],
53    /// Whether to show the color picker popup
54    pub show_color_picker: bool,
55    /// Last selected tool per category (remembers which tool was last used in each category)
56    pub category_last_tool: HashMap<String, DrawingToolType>,
57    /// Whether the tool search bar is open
58    pub search_open: bool,
59    /// Current search query
60    pub search_query: String,
61    /// Glyph picker search, size and session recents.
62    pub glyph_picker: super::GlyphPicker,
63    /// Whether to show values tooltip on long press
64    pub values_tooltip_on_long_press: bool,
65    /// Whether eraser mode is currently active
66    pub eraser_mode_enabled: bool,
67    /// Whether all drawings are locked; the lock button shows it.
68    pub lock_all: bool,
69    /// Whether the Hide menu has hidden drawings; the menu shows a check on each hidden group.
70    pub hide_drawings: bool,
71    /// Whether the Hide menu has hidden indicators.
72    pub hide_indicators: bool,
73    /// Whether the Hide menu has hidden positions.
74    pub hide_positions: bool,
75    /// Whether the Hide menu has hidden orders.
76    pub hide_orders: bool,
77    /// Whether zoom history exists (for showing/hiding Zoom Out button)
78    pub has_zoom_history: bool,
79    /// Whether zoom-in mode is currently active (for button highlighting)
80    pub zoom_mode_active: bool,
81    /// Current cursor type (Cross, Dot, Arrow) - Arrow is default
82    pub current_cursor_type: CursorType,
83    /// Cached drawing templates loaded from the API
84    pub templates: Vec<DrawingTemplate>,
85    /// Whether the template name input dialog is showing
86    pub show_template_name_input: bool,
87    /// Current template name being entered
88    pub template_name_input: String,
89}
90
91impl Default for ToolbarState {
92    fn default() -> Self {
93        let mut category_last_tool = HashMap::new();
94        // Initialize with first tool from each category
95        category_last_tool.insert("Lines".to_string(), DrawingToolType::TrendLine);
96        category_last_tool.insert(
97            "Fibonacci".to_string(),
98            DrawingToolType::FibonacciRetracement,
99        );
100        category_last_tool.insert("Patterns".to_string(), DrawingToolType::XABCDPattern);
101        category_last_tool.insert("Projection".to_string(), DrawingToolType::LongPos);
102        category_last_tool.insert("Brushes/Shapes".to_string(), DrawingToolType::Brush);
103        category_last_tool.insert("Text/Annotations".to_string(), DrawingToolType::TextLabel);
104
105        Self {
106            sel_tool: None,
107            expanded: true,
108            expanded_category: None,
109            favorites: Vec::new(),
110            floating_visible: true,
111            floating_pos: None,
112            recent: VecDeque::with_capacity(5),
113            magnet_mode: false,
114            magnet_type: MagnetType::Strong, // Default to strong magnet
115            snap_to_indicators: true,
116            magnet_hint_dismissed: false,
117            stay_in_drawing_mode: false,
118            drawing_color: [242, 54, 69, 255], // Default red
119            show_color_picker: false,
120            category_last_tool,
121            search_open: false,
122            search_query: String::new(),
123            glyph_picker: Default::default(),
124            values_tooltip_on_long_press: true, // Default: enabled
125            eraser_mode_enabled: false,
126            lock_all: false,
127            hide_drawings: false,
128            hide_indicators: false,
129            hide_positions: false,
130            hide_orders: false,
131            has_zoom_history: false,
132            zoom_mode_active: false,
133            current_cursor_type: CursorType::Arrow, // Default: Arrow
134            templates: Vec::new(),
135            show_template_name_input: false,
136            template_name_input: String::new(),
137        }
138    }
139}
140
141impl ToolbarState {
142    /// Create new toolbar state with defaults
143    pub fn new() -> Self {
144        Self::default()
145    }
146
147    /// Select a drawing tool and add to recent
148    pub fn select_tool(&mut self, tool: DrawingToolType) {
149        self.sel_tool = Some(tool);
150        self.eraser_mode_enabled = false;
151        self.zoom_mode_active = false;
152        self.add_to_recent(tool);
153
154        // Update last selected tool for this tool's category
155        if let Some(category) = data::get_tool_category(tool) {
156            self.category_last_tool.insert(category.to_string(), tool);
157        }
158    }
159
160    /// Add a tool to recent list
161    pub fn add_to_recent(&mut self, tool: DrawingToolType) {
162        // Remove if already present
163        self.recent.retain(|t| *t != tool);
164        // Add to front
165        self.recent.push_front(tool);
166        // Keep max 5
167        while self.recent.len() > 5 {
168            self.recent.pop_back();
169        }
170    }
171
172    /// Clear tool selection (cursor mode)
173    pub fn clear_selection(&mut self) {
174        self.sel_tool = None;
175        self.zoom_mode_active = false;
176    }
177
178    /// Toggle favorite status of a tool
179    pub fn toggle_favorite(&mut self, tool: DrawingToolType) {
180        if self.favorites.contains(&tool) {
181            self.favorites.retain(|t| *t != tool);
182        } else {
183            self.favorites.push(tool);
184        }
185    }
186
187    /// Check if tool is favorited
188    pub fn is_favorite(&self, tool: &DrawingToolType) -> bool {
189        self.favorites.contains(tool)
190    }
191
192    /// Toggle magnet mode
193    pub fn toggle_magnet(&mut self) {
194        self.magnet_mode = !self.magnet_mode;
195    }
196
197    /// Toggle stay-in-drawing mode
198    pub fn toggle_stay_in_drawing(&mut self) {
199        self.stay_in_drawing_mode = !self.stay_in_drawing_mode;
200    }
201
202    /// Sync toolbar state from external drawing state.
203    pub fn sync_from(
204        &mut self,
205        active_tool: Option<DrawingToolType>,
206        magnet_mode: bool,
207        stay_in_drawing_mode: bool,
208        eraser_mode: bool,
209        drawing_color: [u8; 4],
210    ) {
211        self.sel_tool = active_tool;
212        self.magnet_mode = magnet_mode;
213        self.stay_in_drawing_mode = stay_in_drawing_mode;
214        self.eraser_mode_enabled = eraser_mode;
215        self.drawing_color = drawing_color;
216    }
217}