ratatui_interact/components/hotkey_dialog/
style.rs1use ratatui::style::{Color, Modifier, Style};
6
7#[derive(Debug, Clone)]
9pub struct HotkeyDialogStyle {
10 pub title: String,
12 pub border_focused: Color,
14 pub border_unfocused: Color,
16 pub title_color: Color,
18 pub global_key_color: Color,
20 pub local_key_color: Color,
22 pub selected_bg: Color,
24 pub selected_fg: Color,
26 pub locked_color: Color,
28 pub cursor_color: Color,
30 pub placeholder_color: Color,
32 pub text_color: Color,
34 pub dim_color: Color,
36 pub width_percent: u16,
38 pub height_percent: u16,
40 pub max_width: u16,
42 pub max_height: u16,
44 pub min_width: u16,
46 pub min_height: u16,
48 pub category_width_percent: u16,
50 pub search_height: u16,
52 pub footer_height: u16,
54 pub global_indicator: String,
56 pub locked_indicator: String,
58 pub search_placeholder: String,
60}
61
62impl Default for HotkeyDialogStyle {
63 fn default() -> Self {
64 Self {
65 title: " Hotkey Configuration ".to_string(),
66 border_focused: Color::Yellow,
67 border_unfocused: Color::DarkGray,
68 title_color: Color::Yellow,
69 global_key_color: Color::Yellow,
70 local_key_color: Color::Cyan,
71 selected_bg: Color::Yellow,
72 selected_fg: Color::Black,
73 locked_color: Color::Red,
74 cursor_color: Color::Yellow,
75 placeholder_color: Color::DarkGray,
76 text_color: Color::White,
77 dim_color: Color::DarkGray,
78 width_percent: 85,
79 height_percent: 85,
80 max_width: 110,
81 max_height: 45,
82 min_width: 70,
83 min_height: 25,
84 category_width_percent: 28,
85 search_height: 3,
86 footer_height: 2,
87 global_indicator: "[G]".to_string(),
88 locked_indicator: "L".to_string(),
89 search_placeholder: "Type to filter hotkeys...".to_string(),
90 }
91 }
92}
93
94impl From<&crate::theme::Theme> for HotkeyDialogStyle {
95 fn from(theme: &crate::theme::Theme) -> Self {
96 let p = &theme.palette;
97 Self {
98 title: " Hotkey Configuration ".to_string(),
99 border_focused: p.border_focused,
100 border_unfocused: p.border_disabled,
101 title_color: p.primary,
102 global_key_color: p.primary,
103 local_key_color: p.secondary,
104 selected_bg: p.highlight_bg,
105 selected_fg: p.highlight_fg,
106 locked_color: p.error,
107 cursor_color: p.primary,
108 placeholder_color: p.text_placeholder,
109 text_color: p.text,
110 dim_color: p.text_disabled,
111 width_percent: 85,
112 height_percent: 85,
113 max_width: 110,
114 max_height: 45,
115 min_width: 70,
116 min_height: 25,
117 category_width_percent: 28,
118 search_height: 3,
119 footer_height: 2,
120 global_indicator: "[G]".to_string(),
121 locked_indicator: "L".to_string(),
122 search_placeholder: "Type to filter hotkeys...".to_string(),
123 }
124 }
125}
126
127impl HotkeyDialogStyle {
128 pub fn new() -> Self {
130 Self::default()
131 }
132
133 pub fn title(mut self, title: impl Into<String>) -> Self {
135 self.title = title.into();
136 self
137 }
138
139 pub fn border_focused(mut self, color: Color) -> Self {
141 self.border_focused = color;
142 self
143 }
144
145 pub fn border_unfocused(mut self, color: Color) -> Self {
147 self.border_unfocused = color;
148 self
149 }
150
151 pub fn size(
153 mut self,
154 width_percent: u16,
155 height_percent: u16,
156 max_width: u16,
157 max_height: u16,
158 ) -> Self {
159 self.width_percent = width_percent;
160 self.height_percent = height_percent;
161 self.max_width = max_width;
162 self.max_height = max_height;
163 self
164 }
165
166 pub fn min_size(mut self, min_width: u16, min_height: u16) -> Self {
168 self.min_width = min_width;
169 self.min_height = min_height;
170 self
171 }
172
173 pub fn search_placeholder(mut self, text: impl Into<String>) -> Self {
175 self.search_placeholder = text.into();
176 self
177 }
178
179 pub fn focused_border_style(&self) -> Style {
181 Style::default().fg(self.border_focused)
182 }
183
184 pub fn unfocused_border_style(&self) -> Style {
186 Style::default().fg(self.border_unfocused)
187 }
188
189 pub fn title_style(&self) -> Style {
191 Style::default()
192 .fg(self.title_color)
193 .add_modifier(Modifier::BOLD)
194 }
195
196 pub fn selected_style(&self) -> Style {
198 Style::default()
199 .fg(self.selected_fg)
200 .bg(self.selected_bg)
201 .add_modifier(Modifier::BOLD)
202 }
203
204 pub fn selected_text_style(&self) -> Style {
206 Style::default().fg(self.selected_fg).bg(self.selected_bg)
207 }
208
209 pub fn global_key_style(&self) -> Style {
211 Style::default()
212 .fg(self.global_key_color)
213 .add_modifier(Modifier::BOLD)
214 }
215
216 pub fn local_key_style(&self) -> Style {
218 Style::default()
219 .fg(self.local_key_color)
220 .add_modifier(Modifier::BOLD)
221 }
222
223 pub fn locked_style(&self) -> Style {
225 Style::default().fg(self.locked_color)
226 }
227
228 pub fn text_style(&self) -> Style {
230 Style::default().fg(self.text_color)
231 }
232
233 pub fn dim_style(&self) -> Style {
235 Style::default().fg(self.dim_color)
236 }
237
238 pub fn placeholder_style(&self) -> Style {
240 Style::default().fg(self.placeholder_color)
241 }
242
243 pub fn cursor_style(&self) -> Style {
245 Style::default().fg(self.cursor_color)
246 }
247
248 pub fn calculate_modal_area(
250 &self,
251 screen_width: u16,
252 screen_height: u16,
253 ) -> (u16, u16, u16, u16) {
254 let modal_width = (screen_width * self.width_percent / 100)
255 .min(self.max_width)
256 .max(self.min_width)
257 .min(screen_width.saturating_sub(4));
258
259 let modal_height = (screen_height * self.height_percent / 100)
260 .min(self.max_height)
261 .max(self.min_height)
262 .min(screen_height.saturating_sub(4));
263
264 let x = (screen_width.saturating_sub(modal_width)) / 2;
265 let y = (screen_height.saturating_sub(modal_height)) / 2;
266
267 (x, y, modal_width, modal_height)
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn test_default_style() {
277 let style = HotkeyDialogStyle::default();
278 assert_eq!(style.width_percent, 85);
279 assert_eq!(style.height_percent, 85);
280 assert_eq!(style.border_focused, Color::Yellow);
281 }
282
283 #[test]
284 fn test_builder_pattern() {
285 let style = HotkeyDialogStyle::new()
286 .title("My Hotkeys")
287 .border_focused(Color::Cyan)
288 .size(80, 80, 100, 40);
289
290 assert_eq!(style.title, "My Hotkeys");
291 assert_eq!(style.border_focused, Color::Cyan);
292 assert_eq!(style.width_percent, 80);
293 }
294
295 #[test]
296 fn test_calculate_modal_area() {
297 let style = HotkeyDialogStyle::default();
298 let (x, _y, w, _h) = style.calculate_modal_area(120, 40);
299
300 assert!(w <= 110);
302 assert!(w >= 70);
303 assert_eq!(x, (120 - w) / 2);
305 }
306}