1use crate::RatWidgetColor;
2use crate::palette::{Colors, Palette};
3use crate::theme::{Category, SalsaTheme};
4use crate::{StyleName, WidgetStyle};
5use rat_widget::button::ButtonStyle;
6use rat_widget::calendar::CalendarStyle;
7use rat_widget::checkbox::CheckboxStyle;
8use rat_widget::choice::ChoiceStyle;
9use rat_widget::clipper::ClipperStyle;
10use rat_widget::color_input::ColorInputStyle;
11use rat_widget::combobox::ComboboxStyle;
12use rat_widget::dialog_frame::DialogFrameStyle;
13use rat_widget::file_dialog::FileDialogStyle;
14use rat_widget::form::FormStyle;
15use rat_widget::line_number::LineNumberStyle;
16use rat_widget::list::ListStyle;
17use rat_widget::menu::MenuStyle;
18use rat_widget::msgdialog::MsgDialogStyle;
19use rat_widget::paragraph::ParagraphStyle;
20use rat_widget::radio::{RadioLayout, RadioStyle};
21use rat_widget::scrolled::{ScrollStyle, ScrollSymbols};
22use rat_widget::shadow::{ShadowDirection, ShadowStyle};
23use rat_widget::slider::SliderStyle;
24use rat_widget::splitter::SplitStyle;
25use rat_widget::statusline::StatusLineStyle;
26use rat_widget::tabbed::TabbedStyle;
27use rat_widget::table::TableStyle;
28use rat_widget::text::TextStyle;
29use rat_widget::view::ViewStyle;
30use ratatui::layout::Alignment;
31use ratatui::style::{Color, Style, Stylize};
32use ratatui::symbols;
33use ratatui::symbols::border;
34use ratatui::widgets::{Block, Borders};
35use std::time::Duration;
36
37pub fn create_shell(name: &str, p: Palette) -> SalsaTheme {
42 let mut th = SalsaTheme::new(name, Category::Shell, p);
43
44 th.define_style(Style::LABEL_FG, th.p.fg_style_alias(Color::LABEL_FG));
45 th.define_style(Style::INPUT, th.p.style_alias(Color::INPUT_BG));
46 th.define_style(Style::FOCUS, th.p.style_alias(Color::FOCUS_BG));
47 th.define_style(Style::SELECT, th.p.style_alias(Color::SELECT_BG));
48 th.define_style(Style::DISABLED, th.p.style_alias(Color::DISABLED_BG));
49 th.define_style(Style::INVALID, th.p.style_alias(Color::INVALID_BG));
50 th.define_style(Style::HOVER, th.p.fg_style_alias(Color::HOVER_BG));
51 th.define_style(Style::TITLE, th.p.fg_style_alias(Color::TITLE_FG));
52 th.define_style(Style::HEADER, th.p.fg_style_alias(Color::HEADER_FG));
53 th.define_style(Style::FOOTER, th.p.fg_style_alias(Color::FOOTER_FG));
54 th.define_style(
55 Style::WEEK_HEADER_FG,
56 th.p.fg_style_alias(Color::WEEK_HEADER_FG),
57 );
58 th.define_style(
59 Style::MONTH_HEADER_FG,
60 th.p.fg_style_alias(Color::MONTH_HEADER_FG),
61 );
62 th.define_style(Style::SHADOWS, th.p.style_alias(Color::SHADOW_BG));
63 th.define_style(Style::INPUT_FOCUS, th.p.style_alias(Color::INPUT_FOCUS_BG));
64 th.define_style(Style::INPUT_SELECT, th.p.style_alias(Color::SELECT_BG));
65 th.define_style(Style::KEY_BINDING, th.p.style_alias(Color::KEY_BINDING_BG));
66
67 th.define_style(Style::BUTTON_BASE, th.p.style_alias(Color::BUTTON_BASE_BG));
68 th.define_style(Style::MENU_BASE, th.p.fg_style(Colors::TextLight, 0));
69 th.define_style(Style::STATUS_BASE, th.p.fg_style(Colors::TextLight, 0));
70
71 th.define_style(Style::CONTAINER_BASE, th.p.fg_style(Colors::TextLight, 0));
72 th.define_style(
73 Style::CONTAINER_BORDER_FG,
74 th.p.fg_style_alias(Color::CONTAINER_BORDER_FG),
75 );
76 th.define_style(
77 Style::CONTAINER_ARROW_FG,
78 th.p.fg_style_alias(Color::CONTAINER_ARROW_FG),
79 );
80
81 th.define_style(Style::DOCUMENT_BASE, th.p.fg_style(Colors::TextLight, 0));
82 th.define_style(
83 Style::DOCUMENT_BORDER_FG,
84 th.p.fg_style_alias(Color::DOCUMENT_BORDER_FG),
85 );
86 th.define_style(
87 Style::DOCUMENT_ARROW_FG,
88 th.p.fg_style_alias(Color::DOCUMENT_ARROW_FG),
89 );
90
91 th.define_style(Style::POPUP_BASE, th.p.fg_style(Colors::TextLight, 0));
92 th.define_style(
93 Style::POPUP_BORDER_FG,
94 th.p.fg_style_alias(Color::POPUP_BORDER_FG),
95 );
96 th.define_style(
97 Style::POPUP_ARROW_FG,
98 th.p.fg_style_alias(Color::POPUP_ARROW_FG),
99 );
100
101 th.define_style(Style::DIALOG_BASE, th.p.fg_style(Colors::TextLight, 0));
102 th.define_style(
103 Style::DIALOG_BORDER_FG,
104 th.p.fg_style_alias(Color::DIALOG_BORDER_FG),
105 );
106 th.define_style(
107 Style::DIALOG_ARROW_FG,
108 th.p.fg_style_alias(Color::DIALOG_ARROW_FG),
109 );
110
111 th.define_fn(WidgetStyle::BUTTON, button);
112 th.define_fn(WidgetStyle::CALENDAR, month);
113 th.define_fn(WidgetStyle::CHECKBOX, checkbox);
114 th.define_fn(WidgetStyle::CHOICE, choice);
115 th.define_fn(WidgetStyle::CLIPPER, clipper);
116 th.define_fn(WidgetStyle::COMBOBOX, combobox);
117 th.define_fn(WidgetStyle::COLOR_INPUT, color_input);
118 th.define_fn(WidgetStyle::DIALOG_FRAME, dialog_frame);
119 th.define_fn(WidgetStyle::FILE_DIALOG, file_dialog);
120 th.define_fn(WidgetStyle::FORM, form);
121 th.define_fn(WidgetStyle::LINE_NR, line_nr);
122 th.define_fn(WidgetStyle::LIST, list);
123 th.define_fn(WidgetStyle::MENU, menu);
124 th.define_fn(WidgetStyle::MONTH, month);
125 th.define_fn(WidgetStyle::MSG_DIALOG, msg_dialog);
126 th.define_fn(WidgetStyle::PARAGRAPH, paragraph);
127 th.define_fn(WidgetStyle::RADIO, radio);
128 th.define_fn(WidgetStyle::SCROLL, scroll);
129 th.define_fn(WidgetStyle::SCROLL_DIALOG, dialog_scroll);
130 th.define_fn(WidgetStyle::SCROLL_POPUP, popup_scroll);
131 th.define_fn(WidgetStyle::SHADOW, shadow);
132 th.define_fn(WidgetStyle::SLIDER, slider);
133 th.define_fn(WidgetStyle::SPLIT, split);
134 th.define_fn(WidgetStyle::STATUSLINE, statusline);
135 th.define_fn(WidgetStyle::TABBED, tabbed);
136 th.define_fn(WidgetStyle::TABLE, table);
137 th.define_fn(WidgetStyle::TEXT, text);
138 th.define_fn(WidgetStyle::TEXTAREA, textarea);
139 th.define_fn(WidgetStyle::TEXTVIEW, textview);
140 th.define_fn(WidgetStyle::VIEW, view);
141
142 th
143}
144
145fn button(th: &SalsaTheme) -> ButtonStyle {
146 ButtonStyle {
147 style: th.style(Style::BUTTON_BASE),
148 focus: Some(th.style(Style::FOCUS)),
149 armed: Some(th.style(Style::SELECT)),
150 hover: Some(th.p.style_alias(Color::HOVER_BG)),
151 armed_delay: Some(Duration::from_millis(50)),
152 ..Default::default()
153 }
154}
155
156fn checkbox(th: &SalsaTheme) -> CheckboxStyle {
157 CheckboxStyle {
158 style: th.style(Style::INPUT),
159 focus: Some(th.style(Style::INPUT_FOCUS)),
160 ..Default::default()
161 }
162}
163
164fn combobox(th: &SalsaTheme) -> ComboboxStyle {
165 ComboboxStyle {
166 choice: th.style(WidgetStyle::CHOICE),
167 text: th.style(WidgetStyle::TEXT),
168 ..Default::default()
169 }
170}
171
172fn choice(th: &SalsaTheme) -> ChoiceStyle {
173 ChoiceStyle {
174 style: th.style(Style::INPUT),
175 select: Some(th.style(Style::INPUT_SELECT)),
176 focus: Some(th.style(Style::INPUT_FOCUS)),
177 popup_style: Some(th.style(Style::POPUP_BASE)),
178 popup_border: Some(th.style(Style::POPUP_BORDER_FG)),
179 popup_scroll: Some(th.style(WidgetStyle::SCROLL_POPUP)),
180 popup_block: Some(
181 Block::bordered()
182 .borders(Borders::LEFT | Borders::BOTTOM | Borders::RIGHT)
183 .border_set(border::Set {
184 top_left: "X",
185 top_right: "X",
186 bottom_left: "▀",
187 bottom_right: "▀",
188 vertical_left: "▌",
189 vertical_right: "▐",
190 horizontal_top: "X",
191 horizontal_bottom: "▀",
192 })
193 .border_style(th.style::<Style>(Style::POPUP_BORDER_FG)),
194 ),
195 ..Default::default()
196 }
197}
198
199fn clipper(th: &SalsaTheme) -> ClipperStyle {
200 ClipperStyle {
201 style: th.style(Style::CONTAINER_BASE),
202 label_style: Some(th.style(Style::LABEL_FG)),
203 scroll: Some(th.style(WidgetStyle::SCROLL)),
204 ..Default::default()
205 }
206}
207
208fn dialog_frame(th: &SalsaTheme) -> DialogFrameStyle {
209 DialogFrameStyle {
210 style: th.style(Style::DIALOG_BASE),
211 border_style: Some(th.style::<Style>(Style::DIALOG_BORDER_FG)),
212 button_style: Some(th.style(WidgetStyle::BUTTON)),
213 ..DialogFrameStyle::default()
214 }
215}
216
217fn file_dialog(th: &SalsaTheme) -> FileDialogStyle {
218 FileDialogStyle {
219 style: th.style(Style::DIALOG_BASE),
220 list: Some(th.style(WidgetStyle::LIST)),
221 roots: Some(ListStyle {
222 style: th.style(Style::DIALOG_BASE),
223 ..th.style(WidgetStyle::LIST)
224 }),
225 text: Some(th.style(WidgetStyle::TEXT)),
226 button: Some(th.style(WidgetStyle::BUTTON)),
227 block: Some(Block::bordered()),
228 ..Default::default()
229 }
230}
231
232fn form(th: &SalsaTheme) -> FormStyle {
233 FormStyle {
234 style: th.style(Style::CONTAINER_BASE),
235 label_style: Some(th.style(Style::LABEL_FG)),
236 navigation: Some(th.style(Style::CONTAINER_ARROW_FG)),
237 navigation_hover: Some(th.style(Style::HOVER)),
238 block: Some(
239 Block::bordered()
240 .borders(Borders::TOP | Borders::BOTTOM)
241 .border_set(border::EMPTY)
242 .border_style(th.style::<Style>(Style::CONTAINER_BORDER_FG)),
243 ),
244 border_style: Some(th.style::<Style>(Style::CONTAINER_BORDER_FG)),
245 ..Default::default()
246 }
247}
248
249fn line_nr(th: &SalsaTheme) -> LineNumberStyle {
250 LineNumberStyle {
251 style: th.style(Style::CONTAINER_BASE),
252 cursor: Some(th.style(Style::INPUT_SELECT)),
253 ..LineNumberStyle::default()
254 }
255}
256
257fn list(th: &SalsaTheme) -> ListStyle {
258 ListStyle {
259 style: th.style(Style::CONTAINER_BASE),
260 select: Some(th.style(Style::SELECT)),
261 focus: Some(th.style(Style::FOCUS)),
262 scroll: Some(th.style(WidgetStyle::SCROLL)),
263 ..Default::default()
264 }
265}
266
267fn menu(th: &SalsaTheme) -> MenuStyle {
268 MenuStyle {
269 style: th.style(Style::MENU_BASE),
270 title: Some(th.style(Style::TITLE)),
271 focus: Some(th.style(Style::FOCUS)),
272 right: Some(th.style(Style::KEY_BINDING)),
273 disabled: Some(th.style(Style::DISABLED)),
274 highlight: Some(Style::default().underlined()),
275 popup_block: Some(Block::bordered()),
276 popup: Default::default(),
277 popup_border: Some(th.style(Style::MENU_BASE)),
278 popup_style: Some(th.style(Style::MENU_BASE)),
279 popup_focus: Some(th.style(Style::FOCUS)),
280 popup_right: Some(th.style(Style::KEY_BINDING)),
281 popup_disabled: Some(th.style(Style::DISABLED)),
282 popup_highlight: Some(Style::default().underlined()),
283 ..Default::default()
284 }
285}
286
287fn month(th: &SalsaTheme) -> CalendarStyle {
288 CalendarStyle {
289 style: th.style(Style::CONTAINER_BASE),
290 title: Some(th.style(Style::MONTH_HEADER_FG)),
291 weeknum: Some(th.style(Style::WEEK_HEADER_FG)),
292 weekday: Some(th.style(Style::WEEK_HEADER_FG)),
293 day: None,
294 select: Some(th.style(Style::SELECT)),
295 focus: Some(th.style(Style::FOCUS)),
296 ..CalendarStyle::default()
297 }
298}
299
300fn msg_dialog(th: &SalsaTheme) -> MsgDialogStyle {
301 MsgDialogStyle {
302 style: th.style(Style::DIALOG_BASE),
303 button: Some(th.style(WidgetStyle::BUTTON)),
304 ..Default::default()
305 }
306}
307
308fn paragraph(th: &SalsaTheme) -> ParagraphStyle {
309 ParagraphStyle {
310 style: th.style(Style::CONTAINER_BASE),
311 focus: Some(th.style(Style::FOCUS)),
312 scroll: Some(th.style(WidgetStyle::SCROLL)),
313 ..Default::default()
314 }
315}
316
317fn radio(th: &SalsaTheme) -> RadioStyle {
318 RadioStyle {
319 layout: Some(RadioLayout::Stacked),
320 style: th.style(Style::INPUT),
321 focus: Some(th.style(Style::INPUT_FOCUS)),
322 ..Default::default()
323 }
324}
325
326fn scroll(th: &SalsaTheme) -> ScrollStyle {
328 ScrollStyle {
329 thumb_style: Some(th.style(Style::CONTAINER_BORDER_FG)),
330 track_style: Some(th.style(Style::CONTAINER_BORDER_FG)),
331 min_style: Some(th.style(Style::CONTAINER_BORDER_FG)),
332 begin_style: Some(th.style(Style::CONTAINER_ARROW_FG)),
333 end_style: Some(th.style(Style::CONTAINER_ARROW_FG)),
334 horizontal: Some(ScrollSymbols {
335 track: "▒",
336 thumb: symbols::block::FULL,
337 begin: "←",
338 end: "→",
339 min: "░",
340 }),
341 vertical: Some(ScrollSymbols {
342 track: "▒",
343 thumb: symbols::block::FULL,
344 begin: "↑",
345 end: "↓",
346 min: "░",
347 }),
348 ..Default::default()
349 }
350}
351
352fn popup_scroll(th: &SalsaTheme) -> ScrollStyle {
353 ScrollStyle {
354 thumb_style: Some(th.style(Style::POPUP_BORDER_FG)),
355 track_style: Some(th.style(Style::POPUP_BORDER_FG)),
356 min_style: Some(th.style(Style::POPUP_BORDER_FG)),
357 begin_style: Some(th.style(Style::POPUP_ARROW_FG)),
358 end_style: Some(th.style(Style::POPUP_ARROW_FG)),
359 horizontal: Some(ScrollSymbols {
360 track: "▒",
361 thumb: symbols::block::FULL,
362 begin: "←",
363 end: "→",
364 min: "░",
365 }),
366 vertical: Some(ScrollSymbols {
367 track: "▒",
368 thumb: symbols::block::FULL,
369 begin: "↑",
370 end: "↓",
371 min: "░",
372 }),
373 ..Default::default()
374 }
375}
376
377fn dialog_scroll(th: &SalsaTheme) -> ScrollStyle {
378 ScrollStyle {
379 thumb_style: Some(th.style(Style::DIALOG_BORDER_FG)),
380 track_style: Some(th.style(Style::DIALOG_BORDER_FG)),
381 min_style: Some(th.style(Style::DIALOG_BORDER_FG)),
382 begin_style: Some(th.style(Style::POPUP_ARROW_FG)),
383 end_style: Some(th.style(Style::POPUP_ARROW_FG)),
384 horizontal: Some(ScrollSymbols {
385 track: "▒",
386 thumb: symbols::block::FULL,
387 begin: "←",
388 end: "→",
389 min: "░",
390 }),
391 vertical: Some(ScrollSymbols {
392 track: "▒",
393 thumb: symbols::block::FULL,
394 begin: "↑",
395 end: "↓",
396 min: "░",
397 }),
398 ..Default::default()
399 }
400}
401
402fn shadow(th: &SalsaTheme) -> ShadowStyle {
403 ShadowStyle {
404 style: th.style(Style::SHADOWS),
405 dir: ShadowDirection::BottomRight,
406 ..ShadowStyle::default()
407 }
408}
409
410fn slider(th: &SalsaTheme) -> SliderStyle {
411 SliderStyle {
412 style: th.style(Style::INPUT),
413 bounds: Some(th.style(Style::INPUT)),
414 knob: Some(th.style(Style::INPUT_SELECT)),
415 focus: Some(th.style(Style::INPUT_FOCUS)),
416 text_align: Some(Alignment::Center),
417 ..Default::default()
418 }
419}
420
421fn split(th: &SalsaTheme) -> SplitStyle {
422 SplitStyle {
423 style: th.style(Style::CONTAINER_BORDER_FG),
424 arrow_style: Some(th.style(Style::CONTAINER_ARROW_FG)),
425 drag_style: Some(th.style(Style::HOVER)),
426 ..Default::default()
427 }
428}
429
430fn statusline(th: &SalsaTheme) -> StatusLineStyle {
431 StatusLineStyle {
432 styles: vec![
433 th.style(Style::STATUS_BASE),
434 th.p.style(Colors::Blue, 3),
435 th.p.style(Colors::Blue, 2),
436 th.p.style(Colors::Blue, 1),
437 ],
438 ..Default::default()
439 }
440}
441
442fn tabbed(th: &SalsaTheme) -> TabbedStyle {
443 TabbedStyle {
444 style: th.style(Style::CONTAINER_BASE),
445 border_style: Some(th.style(Style::CONTAINER_BORDER_FG)),
446 tab: Some(th.style(Style::INPUT)),
447 hover: Some(th.style(Style::HOVER)),
448 select: Some(th.style(Style::SELECT)),
449 focus: Some(th.style(Style::FOCUS)),
450 ..Default::default()
451 }
452}
453
454fn table(th: &SalsaTheme) -> TableStyle {
455 TableStyle {
456 style: th.style(Style::CONTAINER_BASE),
457 select_row: Some(th.style(Style::SELECT)),
458 show_row_focus: true,
459 focus_style: Some(th.style(Style::FOCUS)),
460 border_style: Some(th.style(Style::CONTAINER_BORDER_FG)),
461 scroll: Some(th.style(WidgetStyle::SCROLL)),
462 header: Some(th.style(Style::HEADER)),
463 footer: Some(th.style(Style::FOOTER)),
464 ..Default::default()
465 }
466}
467
468fn color_input(th: &SalsaTheme) -> ColorInputStyle {
469 ColorInputStyle {
470 text: TextStyle {
471 style: th.style(Style::INPUT),
472 focus: Some(th.style(Style::INPUT_FOCUS)),
473 select: Some(th.style(Style::INPUT_SELECT)),
474 invalid: Some(th.style(Style::INVALID)),
475 ..TextStyle::default()
476 },
477 ..Default::default()
478 }
479}
480
481fn text(th: &SalsaTheme) -> TextStyle {
482 TextStyle {
483 style: th.style(Style::INPUT),
484 focus: Some(th.style(Style::INPUT_FOCUS)),
485 select: Some(th.style(Style::INPUT_SELECT)),
486 invalid: Some(th.style(Style::INVALID)),
487 ..TextStyle::default()
488 }
489}
490
491fn textarea(th: &SalsaTheme) -> TextStyle {
492 TextStyle {
493 style: th.style(Style::INPUT),
494 focus: Some(th.style(Style::INPUT)),
495 select: Some(th.style(Style::INPUT_SELECT)),
496 scroll: Some(th.style(WidgetStyle::SCROLL)),
497 border_style: Some(th.style(Style::CONTAINER_BORDER_FG)),
498 ..TextStyle::default()
499 }
500}
501
502fn textview(th: &SalsaTheme) -> TextStyle {
503 TextStyle {
504 style: th.style(Style::CONTAINER_BASE),
505 focus: Some(th.style(Style::CONTAINER_BASE)),
506 select: Some(th.style(Style::INPUT_SELECT)),
507 scroll: Some(th.style(WidgetStyle::SCROLL)),
508 border_style: Some(th.style(Style::CONTAINER_BORDER_FG)),
509 ..TextStyle::default()
510 }
511}
512
513fn view(th: &SalsaTheme) -> ViewStyle {
514 ViewStyle {
515 scroll: Some(th.style(WidgetStyle::SCROLL)),
516 ..Default::default()
517 }
518}