rat_theme4/themes/
dark.rs

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