Skip to main content

datui_lib/
chart_export_modal.rs

1//! Chart export modal: format (PNG/EPS), optional chart title, and file path. Used from Chart view only.
2
3use crate::chart_export::ChartExportFormat;
4use crate::widgets::text_input::TextInput;
5use std::path::Path;
6
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
8pub enum ChartExportFocus {
9    #[default]
10    FormatSelector,
11    PathInput,
12    TitleInput,
13    WidthInput,
14    HeightInput,
15    ExportButton,
16    CancelButton,
17}
18
19pub struct ChartExportModal {
20    pub active: bool,
21    pub focus: ChartExportFocus,
22    pub selected_format: ChartExportFormat,
23    pub title_input: TextInput,
24    pub path_input: TextInput,
25    pub width_input: TextInput,
26    pub height_input: TextInput,
27}
28
29impl ChartExportModal {
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    pub fn open(&mut self, theme: &crate::config::Theme, history_limit: usize) {
35        self.active = true;
36        self.focus = ChartExportFocus::PathInput;
37        self.title_input = TextInput::new().with_theme(theme);
38        self.title_input.clear();
39        self.path_input = TextInput::new()
40            .with_history_limit(history_limit)
41            .with_theme(theme);
42        self.path_input.clear();
43        self.width_input = TextInput::new().with_theme(theme);
44        self.width_input.set_value("1024".to_string());
45        self.height_input = TextInput::new().with_theme(theme);
46        self.height_input.set_value("768".to_string());
47    }
48
49    /// Reopen the modal with path pre-filled (e.g. after cancel overwrite or export error). Focus is PathInput.
50    pub fn reopen_with_path(&mut self, path: &Path, format: ChartExportFormat) {
51        self.active = true;
52        self.focus = ChartExportFocus::PathInput;
53        self.selected_format = format;
54        self.title_input.clear();
55        self.path_input.set_value(path.display().to_string());
56    }
57
58    pub fn close(&mut self) {
59        self.active = false;
60        self.focus = ChartExportFocus::FormatSelector;
61        self.title_input.clear();
62        self.path_input.clear();
63    }
64
65    pub fn next_focus(&mut self) {
66        self.focus = match self.focus {
67            ChartExportFocus::FormatSelector => ChartExportFocus::PathInput,
68            ChartExportFocus::PathInput => ChartExportFocus::TitleInput,
69            ChartExportFocus::TitleInput => ChartExportFocus::WidthInput,
70            ChartExportFocus::WidthInput => ChartExportFocus::HeightInput,
71            ChartExportFocus::HeightInput => ChartExportFocus::ExportButton,
72            ChartExportFocus::ExportButton => ChartExportFocus::CancelButton,
73            ChartExportFocus::CancelButton => ChartExportFocus::FormatSelector,
74        };
75    }
76
77    pub fn prev_focus(&mut self) {
78        self.focus = match self.focus {
79            ChartExportFocus::FormatSelector => ChartExportFocus::CancelButton,
80            ChartExportFocus::PathInput => ChartExportFocus::FormatSelector,
81            ChartExportFocus::TitleInput => ChartExportFocus::PathInput,
82            ChartExportFocus::WidthInput => ChartExportFocus::TitleInput,
83            ChartExportFocus::HeightInput => ChartExportFocus::WidthInput,
84            ChartExportFocus::ExportButton => ChartExportFocus::HeightInput,
85            ChartExportFocus::CancelButton => ChartExportFocus::ExportButton,
86        };
87    }
88
89    /// Parse width/height from inputs; default to 1024x768 on parse error, clamped to 1..=8192.
90    pub fn export_dimensions(&self) -> (u32, u32) {
91        const MIN: u32 = 1;
92        const MAX: u32 = 8192;
93        const DEFAULT_W: u32 = 1024;
94        const DEFAULT_H: u32 = 768;
95        let w = self
96            .width_input
97            .value()
98            .trim()
99            .parse::<u32>()
100            .ok()
101            .map(|n| n.clamp(MIN, MAX))
102            .unwrap_or(DEFAULT_W);
103        let h = self
104            .height_input
105            .value()
106            .trim()
107            .parse::<u32>()
108            .ok()
109            .map(|n| n.clamp(MIN, MAX))
110            .unwrap_or(DEFAULT_H);
111        (w, h)
112    }
113}
114
115impl Default for ChartExportModal {
116    fn default() -> Self {
117        Self {
118            active: false,
119            focus: ChartExportFocus::FormatSelector,
120            selected_format: ChartExportFormat::Png,
121            title_input: TextInput::new(),
122            path_input: TextInput::new(),
123            width_input: TextInput::new(),
124            height_input: TextInput::new(),
125        }
126    }
127}