rat_theme4/themes/
shell.rs

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
37/// A 'shell'-theme.
38///
39/// It uses almost no background colors and lets your shell
40/// bleed through.
41pub 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
326/// Scroll style
327fn 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}