datui_lib/widgets/
chart_export_modal.rs1use crate::chart_export::ChartExportFormat;
4use crate::chart_export_modal::{ChartExportFocus, ChartExportModal};
5use ratatui::layout::{Constraint, Direction, Layout, Rect};
6use ratatui::style::Style;
7use ratatui::text::{Line, Span};
8use ratatui::widgets::{Block, BorderType, Borders, Clear, Paragraph, Widget};
9
10const FORMAT_COLS: u16 = 3;
11
12pub fn render_chart_export_modal(
13 area: Rect,
14 buf: &mut ratatui::buffer::Buffer,
15 modal: &mut ChartExportModal,
16 border_color: ratatui::style::Color,
17 active_color: ratatui::style::Color,
18) {
19 Clear.render(area, buf);
20 let block = Block::default()
21 .borders(Borders::ALL)
22 .border_type(BorderType::Rounded)
23 .border_style(Style::default().fg(border_color))
24 .title(" Export Chart ");
25 let inner = block.inner(area);
26 block.render(area, buf);
27
28 let chunks = Layout::default()
29 .direction(Direction::Vertical)
30 .constraints([
31 Constraint::Length(3), Constraint::Length(3), Constraint::Length(3), Constraint::Length(3), ])
36 .split(inner);
37
38 let format_area = chunks[0];
40 let is_format_focused = modal.focus == ChartExportFocus::FormatSelector;
41 let format_block = Block::default()
42 .borders(Borders::ALL)
43 .border_type(BorderType::Rounded)
44 .border_style(Style::default().fg(if is_format_focused {
45 active_color
46 } else {
47 border_color
48 }))
49 .title(" Format ");
50 let format_inner = format_block.inner(format_area);
51 format_block.render(format_area, buf);
52
53 let col_width = format_inner.width / FORMAT_COLS;
54 for (i, &format) in ChartExportFormat::ALL.iter().enumerate() {
55 let row = i / FORMAT_COLS as usize;
56 let col = i % FORMAT_COLS as usize;
57 let cell_x = format_inner.x + (col as u16 * col_width);
58 let cell_y = format_inner.y + row as u16;
59 if cell_y >= format_inner.bottom() {
60 break;
61 }
62 let cell_area = Rect {
63 x: cell_x,
64 y: cell_y,
65 width: col_width,
66 height: 1,
67 };
68 let marker = if modal.selected_format == format {
69 "●"
70 } else {
71 "○"
72 };
73 let style = if modal.selected_format == format {
74 Style::default().fg(active_color)
75 } else {
76 Style::default().fg(border_color)
77 };
78 Paragraph::new(Line::from(Span::styled(
79 format!("{} {}", marker, format.as_str()),
80 style,
81 )))
82 .render(cell_area, buf);
83 }
84
85 let title_area = chunks[1];
87 let is_title_focused = modal.focus == ChartExportFocus::TitleInput;
88 let title_block = Block::default()
89 .borders(Borders::ALL)
90 .border_type(BorderType::Rounded)
91 .border_style(Style::default().fg(if is_title_focused {
92 active_color
93 } else {
94 border_color
95 }))
96 .title(" Chart Title ");
97 let title_inner = title_block.inner(title_area);
98 title_block.render(title_area, buf);
99 modal.title_input.set_focused(is_title_focused);
100 (&modal.title_input).render(title_inner, buf);
101
102 let path_area = chunks[2];
104 let is_path_focused = modal.focus == ChartExportFocus::PathInput;
105 let path_block = Block::default()
106 .borders(Borders::ALL)
107 .border_type(BorderType::Rounded)
108 .border_style(Style::default().fg(if is_path_focused {
109 active_color
110 } else {
111 border_color
112 }))
113 .title(" File Path ");
114 let path_inner = path_block.inner(path_area);
115 path_block.render(path_area, buf);
116 modal.path_input.set_focused(is_path_focused);
117 (&modal.path_input).render(path_inner, buf);
118
119 let btn_area = chunks[3];
121 let btn_chunks = Layout::default()
122 .direction(Direction::Horizontal)
123 .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
124 .split(btn_area);
125
126 let is_export_focused = modal.focus == ChartExportFocus::ExportButton;
127 Paragraph::new("Export")
128 .style(if is_export_focused {
129 Style::default().fg(active_color)
130 } else {
131 Style::default().fg(border_color)
132 })
133 .block(
134 Block::default()
135 .borders(Borders::ALL)
136 .border_type(BorderType::Rounded)
137 .border_style(if is_export_focused {
138 Style::default().fg(active_color)
139 } else {
140 Style::default().fg(border_color)
141 }),
142 )
143 .centered()
144 .render(btn_chunks[0], buf);
145
146 let is_cancel_focused = modal.focus == ChartExportFocus::CancelButton;
147 Paragraph::new("Cancel")
148 .style(if is_cancel_focused {
149 Style::default().fg(active_color)
150 } else {
151 Style::default().fg(border_color)
152 })
153 .block(
154 Block::default()
155 .borders(Borders::ALL)
156 .border_type(BorderType::Rounded)
157 .border_style(if is_cancel_focused {
158 Style::default().fg(active_color)
159 } else {
160 Style::default().fg(border_color)
161 }),
162 )
163 .centered()
164 .render(btn_chunks[1], buf);
165}