Skip to main content

datui_lib/widgets/
chart_export_modal.rs

1//! Chart export modal rendering: format (vertical radio), path, title, dimensions, buttons (right).
2
3use crate::chart_export::ChartExportFormat;
4use crate::chart_export_modal::{ChartExportFocus, ChartExportModal};
5use crate::widgets::radio_block::RadioBlock;
6use ratatui::layout::{Constraint, Direction, Layout, Rect};
7use ratatui::style::Style;
8use ratatui::widgets::{Block, BorderType, Borders, Clear, Paragraph, Widget};
9
10pub fn render_chart_export_modal(
11    area: Rect,
12    buf: &mut ratatui::buffer::Buffer,
13    modal: &mut ChartExportModal,
14    border_color: ratatui::style::Color,
15    active_color: ratatui::style::Color,
16) {
17    Clear.render(area, buf);
18    let block = Block::default()
19        .borders(Borders::ALL)
20        .border_type(BorderType::Rounded)
21        .border_style(Style::default().fg(border_color))
22        .title(" Export Chart ");
23    let inner = block.inner(area);
24    block.render(area, buf);
25
26    // Left: format list. Right: path, title, width x height, buttons.
27    let horz = Layout::default()
28        .direction(Direction::Horizontal)
29        .constraints([Constraint::Length(12), Constraint::Min(40)])
30        .split(inner);
31
32    let format_list_area = horz[0];
33    let format_selected = ChartExportFormat::ALL
34        .iter()
35        .position(|&f| f == modal.selected_format)
36        .unwrap_or(0);
37    let is_format_focused = modal.focus == ChartExportFocus::FormatSelector;
38    let format_labels: Vec<&str> = ChartExportFormat::ALL.iter().map(|f| f.as_str()).collect();
39    RadioBlock::new(
40        " Format ",
41        &format_labels,
42        format_selected,
43        is_format_focused,
44        1,
45        border_color,
46        active_color,
47    )
48    .render(format_list_area, buf);
49
50    let right = horz[1];
51    let right_chunks = Layout::default()
52        .direction(Direction::Vertical)
53        .constraints([
54            Constraint::Length(3), // File path
55            Constraint::Length(3), // Chart title
56            Constraint::Length(3), // Width x Height
57            Constraint::Length(1), // Spacer
58            Constraint::Length(3), // Buttons
59        ])
60        .split(right);
61
62    // File path (top)
63    let path_area = right_chunks[0];
64    let is_path_focused = modal.focus == ChartExportFocus::PathInput;
65    let path_block = Block::default()
66        .borders(Borders::ALL)
67        .border_type(BorderType::Rounded)
68        .border_style(Style::default().fg(if is_path_focused {
69            active_color
70        } else {
71            border_color
72        }))
73        .title(" File Path ");
74    let path_inner = path_block.inner(path_area);
75    path_block.render(path_area, buf);
76    modal.path_input.set_focused(is_path_focused);
77    (&modal.path_input).render(path_inner, buf);
78
79    // Chart title
80    let title_area = right_chunks[1];
81    let is_title_focused = modal.focus == ChartExportFocus::TitleInput;
82    let title_block = Block::default()
83        .borders(Borders::ALL)
84        .border_type(BorderType::Rounded)
85        .border_style(Style::default().fg(if is_title_focused {
86            active_color
87        } else {
88            border_color
89        }))
90        .title(" Chart Title ");
91    let title_inner = title_block.inner(title_area);
92    title_block.render(title_area, buf);
93    modal.title_input.set_focused(is_title_focused);
94    (&modal.title_input).render(title_inner, buf);
95
96    // Width x Height row
97    let size_area = right_chunks[2];
98    let size_row = Layout::default()
99        .direction(Direction::Horizontal)
100        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
101        .split(size_area);
102    let is_width_focused = modal.focus == ChartExportFocus::WidthInput;
103    let is_height_focused = modal.focus == ChartExportFocus::HeightInput;
104    let width_block = Block::default()
105        .borders(Borders::ALL)
106        .border_type(BorderType::Rounded)
107        .border_style(Style::default().fg(if is_width_focused {
108            active_color
109        } else {
110            border_color
111        }))
112        .title(" Width ");
113    let width_inner = width_block.inner(size_row[0]);
114    width_block.render(size_row[0], buf);
115    modal.width_input.set_focused(is_width_focused);
116    (&modal.width_input).render(width_inner, buf);
117    let height_block = Block::default()
118        .borders(Borders::ALL)
119        .border_type(BorderType::Rounded)
120        .border_style(Style::default().fg(if is_height_focused {
121            active_color
122        } else {
123            border_color
124        }))
125        .title(" Height ");
126    let height_inner = height_block.inner(size_row[1]);
127    height_block.render(size_row[1], buf);
128    modal.height_input.set_focused(is_height_focused);
129    (&modal.height_input).render(height_inner, buf);
130
131    // Buttons
132    let btn_area = right_chunks[4];
133    let btn_chunks = Layout::default()
134        .direction(Direction::Horizontal)
135        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
136        .split(btn_area);
137
138    let is_export_focused = modal.focus == ChartExportFocus::ExportButton;
139    Paragraph::new("Export")
140        .style(if is_export_focused {
141            Style::default().fg(active_color)
142        } else {
143            Style::default().fg(border_color)
144        })
145        .block(
146            Block::default()
147                .borders(Borders::ALL)
148                .border_type(BorderType::Rounded)
149                .border_style(if is_export_focused {
150                    Style::default().fg(active_color)
151                } else {
152                    Style::default().fg(border_color)
153                }),
154        )
155        .centered()
156        .render(btn_chunks[0], buf);
157
158    let is_cancel_focused = modal.focus == ChartExportFocus::CancelButton;
159    Paragraph::new("Cancel")
160        .style(if is_cancel_focused {
161            Style::default().fg(active_color)
162        } else {
163            Style::default().fg(border_color)
164        })
165        .block(
166            Block::default()
167                .borders(Borders::ALL)
168                .border_type(BorderType::Rounded)
169                .border_style(if is_cancel_focused {
170                    Style::default().fg(active_color)
171                } else {
172                    Style::default().fg(border_color)
173                }),
174        )
175        .centered()
176        .render(btn_chunks[1], buf);
177}