rat_theme4/
shell_theme.rs

1use crate::palette::Palette;
2use crate::{Category, SalsaTheme};
3use crate::{StyleName, WidgetStyle};
4use rat_widget::button::ButtonStyle;
5use rat_widget::calendar::CalendarStyle;
6use rat_widget::checkbox::CheckboxStyle;
7use rat_widget::choice::ChoiceStyle;
8use rat_widget::clipper::ClipperStyle;
9use rat_widget::combobox::ComboboxStyle;
10use rat_widget::dialog_frame::DialogFrameStyle;
11use rat_widget::file_dialog::FileDialogStyle;
12use rat_widget::form::FormStyle;
13use rat_widget::line_number::LineNumberStyle;
14use rat_widget::list::ListStyle;
15use rat_widget::menu::MenuStyle;
16use rat_widget::msgdialog::MsgDialogStyle;
17use rat_widget::paragraph::ParagraphStyle;
18use rat_widget::radio::{RadioLayout, RadioStyle};
19use rat_widget::scrolled::ScrollStyle;
20use rat_widget::shadow::{ShadowDirection, ShadowStyle};
21use rat_widget::slider::SliderStyle;
22use rat_widget::splitter::SplitStyle;
23use rat_widget::statusline::StatusLineStyle;
24use rat_widget::tabbed::TabbedStyle;
25use rat_widget::table::TableStyle;
26use rat_widget::text::TextStyle;
27use rat_widget::view::ViewStyle;
28use ratatui::layout::Alignment;
29use ratatui::style::{Style, Stylize};
30use ratatui::widgets::{Block, Borders};
31use std::time::Duration;
32
33/// A 'shell'-theme.
34///
35/// It uses almost no background colors and lets your shell
36/// bleed through.
37pub fn shell_theme(name: &str, p: Palette) -> SalsaTheme {
38    let mut th = SalsaTheme::new(name, Category::Shell, p);
39
40    th.define(Style::INPUT, th.p.gray(0));
41    th.define(Style::FOCUS, th.p.high_contrast(th.p.primary[2]));
42    th.define(Style::SELECT, th.p.high_contrast(th.p.secondary[1]));
43    th.define(Style::TEXT_FOCUS, th.p.high_contrast(th.p.gray[3]));
44    th.define(Style::TEXT_SELECT, th.p.high_contrast(th.p.secondary[0]));
45    th.define(Style::TEXT_SELECT, th.p.gray(2));
46    th.define(Style::BUTTON_BASE, th.p.gray(2));
47
48    th.define(Style::CONTAINER_BASE, Style::default());
49    th.define(Style::CONTAINER_BORDER, Style::default());
50    th.define(Style::CONTAINER_ARROWS, Style::default());
51
52    th.define(Style::POPUP_BASE, th.p.bg_gray(0));
53    th.define(Style::POPUP_BORDER, th.p.bg_gray(0));
54    th.define(Style::POPUP_ARROW, th.p.bg_gray(0));
55
56    th.define(Style::DIALOG_BASE, th.p.bg_gray(1));
57    th.define(Style::DIALOG_BORDER, th.p.bg_gray(1));
58    th.define(Style::DIALOG_ARROW, th.p.bg_gray(1));
59
60    th.define(Style::STATUS_BASE, Style::default());
61
62    th.define_fn(WidgetStyle::BUTTON, button);
63    th.define_fn(WidgetStyle::CHECKBOX, checkbox);
64    th.define_fn(WidgetStyle::CHOICE, choice);
65    th.define_fn(WidgetStyle::CLIPPER, clipper);
66    th.define_fn(WidgetStyle::COMBOBOX, combobox);
67    th.define_fn(WidgetStyle::DIALOG_FRAME, dialog_frame);
68    th.define_fn(WidgetStyle::FILE_DIALOG, file_dialog);
69    th.define_fn(WidgetStyle::FORM, form);
70    th.define_fn(WidgetStyle::LINE_NR, line_nr);
71    th.define_fn(WidgetStyle::LIST, list);
72    th.define_fn(WidgetStyle::MENU, menu);
73    th.define_fn(WidgetStyle::MONTH, month);
74    th.define_fn(WidgetStyle::MSG_DIALOG, msg_dialog);
75    th.define_fn(WidgetStyle::PARAGRAPH, paragraph);
76    th.define_fn(WidgetStyle::RADIO, radio);
77    th.define_fn(WidgetStyle::SCROLL, scroll);
78    th.define_fn(WidgetStyle::SCROLL_DIALOG, dialog_scroll);
79    th.define_fn(WidgetStyle::SCROLL_POPUP, popup_scroll);
80    th.define_fn(WidgetStyle::SHADOW, shadow);
81    th.define_fn(WidgetStyle::SLIDER, slider);
82    th.define_fn(WidgetStyle::SPLIT, split);
83    th.define_fn(WidgetStyle::STATUSLINE, statusline);
84    th.define_fn(WidgetStyle::TABBED, tabbed);
85    th.define_fn(WidgetStyle::TABLE, table);
86    th.define_fn(WidgetStyle::TEXT, text);
87    th.define_fn(WidgetStyle::TEXTAREA, textarea);
88    th.define_fn(WidgetStyle::TEXTVIEW, textview);
89    th.define_fn(WidgetStyle::VIEW, view);
90
91    th
92}
93
94fn button(th: &SalsaTheme) -> ButtonStyle {
95    ButtonStyle {
96        style: th.style(Style::BUTTON_BASE),
97        focus: Some(th.style(Style::FOCUS)),
98        armed: Some(th.style(Style::SELECT)),
99        hover: Some(th.style(Style::SELECT)),
100        armed_delay: Some(Duration::from_millis(50)),
101        ..Default::default()
102    }
103}
104
105fn checkbox(th: &SalsaTheme) -> CheckboxStyle {
106    CheckboxStyle {
107        style: th.style(Style::INPUT),
108        focus: Some(th.style(Style::TEXT_FOCUS)),
109        ..Default::default()
110    }
111}
112
113fn choice(th: &SalsaTheme) -> ChoiceStyle {
114    ChoiceStyle {
115        style: th.style(Style::INPUT),
116        select: Some(th.style(Style::TEXT_SELECT)),
117        focus: Some(th.style(Style::TEXT_FOCUS)),
118        popup_style: Some(th.style(Style::POPUP_BASE)),
119        popup_border: Some(th.style(Style::POPUP_BORDER)),
120        popup_scroll: Some(popup_scroll(th)),
121        popup_block: Some(
122            Block::bordered()
123                .borders(Borders::LEFT)
124                .border_style(th.style::<Style>(Style::POPUP_BORDER)),
125        ),
126        ..Default::default()
127    }
128}
129
130fn clipper(th: &SalsaTheme) -> ClipperStyle {
131    ClipperStyle {
132        style: th.style(Style::CONTAINER_BASE),
133        scroll: Some(scroll(th)),
134        ..Default::default()
135    }
136}
137
138fn combobox(th: &SalsaTheme) -> ComboboxStyle {
139    ComboboxStyle {
140        choice: choice(th),
141        text: text(th),
142        ..Default::default()
143    }
144}
145
146fn dialog_frame(th: &SalsaTheme) -> DialogFrameStyle {
147    DialogFrameStyle {
148        style: th.style(Style::DIALOG_BASE),
149        block: Some(Block::bordered().style(th.style::<Style>(Style::DIALOG_BORDER))),
150        button_style: Some(button(th)),
151        ..DialogFrameStyle::default()
152    }
153}
154
155fn file_dialog(th: &SalsaTheme) -> FileDialogStyle {
156    FileDialogStyle {
157        style: th.style(Style::DIALOG_BASE),
158        list: Some(list(th)),
159        roots: Some(ListStyle {
160            style: th.style(Style::DIALOG_BASE),
161            ..list(th)
162        }),
163        text: Some(text(th)),
164        button: Some(button(th)),
165        block: Some(Block::bordered()),
166        ..Default::default()
167    }
168}
169
170fn form(th: &SalsaTheme) -> FormStyle {
171    FormStyle {
172        style: th.style(Style::CONTAINER_BASE),
173        navigation: Some(th.style(Style::CONTAINER_ARROWS)),
174        block: Some(
175            Block::bordered()
176                .borders(Borders::TOP | Borders::BOTTOM)
177                .border_style(th.style::<Style>(Style::CONTAINER_BORDER)),
178        ),
179        ..Default::default()
180    }
181}
182
183fn line_nr(th: &SalsaTheme) -> LineNumberStyle {
184    LineNumberStyle {
185        style: th.style(Style::CONTAINER_BASE),
186        cursor: Some(th.style(Style::TEXT_SELECT)),
187        ..LineNumberStyle::default()
188    }
189}
190
191fn list(th: &SalsaTheme) -> ListStyle {
192    ListStyle {
193        style: th.style(Style::CONTAINER_BASE),
194        select: Some(th.style(Style::SELECT)),
195        focus: Some(th.style(Style::FOCUS)),
196        scroll: Some(scroll(th)),
197        ..Default::default()
198    }
199}
200
201fn menu(th: &SalsaTheme) -> MenuStyle {
202    MenuStyle {
203        style: th.style(Style::STATUS_BASE),
204        title: Some(th.p.bg_yellow(2)),
205        focus: Some(th.style(Style::FOCUS)),
206        right: Some(th.p.fg_green(3)),
207        disabled: Some(th.p.fg_gray(0)),
208        highlight: Some(Style::default().underlined()),
209        block: Some(Block::bordered()),
210        popup: Default::default(),
211        popup_border: Some(th.style(Style::STATUS_BASE)),
212        popup_style: Some(th.style(Style::STATUS_BASE)),
213        ..Default::default()
214    }
215}
216
217fn month(th: &SalsaTheme) -> CalendarStyle {
218    CalendarStyle {
219        style: Default::default(),
220        title: None,
221        weeknum: Some(th.p.fg_limegreen(0)),
222        weekday: Some(th.p.fg_limegreen(0)),
223        day: None,
224        select: Some(th.style(Style::SELECT)),
225        focus: Some(th.style(Style::FOCUS)),
226        ..CalendarStyle::default()
227    }
228}
229
230fn msg_dialog(th: &SalsaTheme) -> MsgDialogStyle {
231    MsgDialogStyle {
232        style: th.style(Style::DIALOG_BASE),
233        button: Some(button(th)),
234        ..Default::default()
235    }
236}
237
238fn paragraph(th: &SalsaTheme) -> ParagraphStyle {
239    ParagraphStyle {
240        style: th.style(Style::CONTAINER_BASE),
241        focus: Some(th.style(Style::FOCUS)),
242        scroll: Some(scroll(th)),
243        ..Default::default()
244    }
245}
246
247fn radio(th: &SalsaTheme) -> RadioStyle {
248    RadioStyle {
249        layout: Some(RadioLayout::Stacked),
250        style: th.style(Style::INPUT),
251        focus: Some(th.style(Style::TEXT_FOCUS)),
252        ..Default::default()
253    }
254}
255
256/// Scroll style
257fn scroll(th: &SalsaTheme) -> ScrollStyle {
258    ScrollStyle {
259        thumb_style: Some(th.style(Style::CONTAINER_BORDER)),
260        track_style: Some(th.style(Style::CONTAINER_BORDER)),
261        min_style: Some(th.style(Style::CONTAINER_BORDER)),
262        begin_style: Some(th.style(Style::CONTAINER_ARROWS)),
263        end_style: Some(th.style(Style::CONTAINER_ARROWS)),
264        ..Default::default()
265    }
266}
267
268fn dialog_scroll(th: &SalsaTheme) -> ScrollStyle {
269    ScrollStyle {
270        thumb_style: Some(th.style(Style::DIALOG_BORDER)),
271        track_style: Some(th.style(Style::DIALOG_BORDER)),
272        min_style: Some(th.style(Style::DIALOG_BORDER)),
273        begin_style: Some(th.style(Style::DIALOG_ARROW)),
274        end_style: Some(th.style(Style::DIALOG_ARROW)),
275        ..Default::default()
276    }
277}
278
279fn popup_scroll(th: &SalsaTheme) -> ScrollStyle {
280    ScrollStyle {
281        thumb_style: Some(th.style(Style::POPUP_BORDER)),
282        track_style: Some(th.style(Style::POPUP_BORDER)),
283        min_style: Some(th.style(Style::POPUP_BORDER)),
284        begin_style: Some(th.style(Style::POPUP_ARROW)),
285        end_style: Some(th.style(Style::POPUP_ARROW)),
286        ..Default::default()
287    }
288}
289
290fn shadow(th: &SalsaTheme) -> ShadowStyle {
291    ShadowStyle {
292        style: th.p.normal_contrast(th.p.black[0]),
293        dir: ShadowDirection::BottomRight,
294        ..ShadowStyle::default()
295    }
296}
297
298fn slider(th: &SalsaTheme) -> SliderStyle {
299    SliderStyle {
300        style: th.style(Style::INPUT),
301        bounds: Some(th.p.gray(2)),
302        knob: Some(th.style(Style::TEXT_SELECT)),
303        focus: Some(th.style(Style::TEXT_FOCUS)),
304        text_align: Some(Alignment::Center),
305        ..Default::default()
306    }
307}
308
309fn split(th: &SalsaTheme) -> SplitStyle {
310    SplitStyle {
311        style: th.style(Style::CONTAINER_BORDER),
312        arrow_style: Some(th.style(Style::CONTAINER_ARROWS)),
313        drag_style: Some(th.style(Style::FOCUS)),
314        ..Default::default()
315    }
316}
317
318fn statusline(th: &SalsaTheme) -> StatusLineStyle {
319    StatusLineStyle {
320        styles: vec![
321            th.style(Style::STATUS_BASE),
322            th.p.normal_contrast(th.p.blue[2]),
323            th.p.normal_contrast(th.p.blue[2]),
324            th.p.normal_contrast(th.p.blue[2]),
325        ],
326        ..Default::default()
327    }
328}
329
330fn tabbed(th: &SalsaTheme) -> TabbedStyle {
331    TabbedStyle {
332        style: th.style(Style::CONTAINER_BASE),
333        tab: Some(th.p.gray(2)),
334        select: Some(th.p.secondary(0)),
335        focus: Some(th.style(Style::FOCUS)),
336        ..Default::default()
337    }
338}
339
340fn table(th: &SalsaTheme) -> TableStyle {
341    TableStyle {
342        style: th.style(Style::CONTAINER_BASE),
343        select_row: Some(th.style(Style::SELECT)),
344        show_row_focus: true,
345        focus_style: Some(th.style(Style::FOCUS)),
346        border_style: Some(th.style(Style::CONTAINER_BORDER)),
347        scroll: Some(scroll(th)),
348        header: Some(th.p.green(2)),
349        footer: Some(th.p.green(2)),
350        ..Default::default()
351    }
352}
353
354fn text(th: &SalsaTheme) -> TextStyle {
355    TextStyle {
356        style: th.style(Style::INPUT),
357        focus: Some(th.style(Style::TEXT_FOCUS)),
358        select: Some(th.style(Style::TEXT_SELECT)),
359        invalid: Some(th.p.fg_red(3)),
360        ..TextStyle::default()
361    }
362}
363
364fn textarea(th: &SalsaTheme) -> TextStyle {
365    TextStyle {
366        style: th.style(Style::INPUT),
367        focus: Some(th.style(Style::TEXT_FOCUS)),
368        select: Some(th.style(Style::TEXT_SELECT)),
369        scroll: Some(scroll(th)),
370        border_style: Some(th.style(Style::CONTAINER_BORDER)),
371        ..TextStyle::default()
372    }
373}
374
375fn textview(th: &SalsaTheme) -> TextStyle {
376    TextStyle {
377        style: th.style(Style::CONTAINER_BASE),
378        focus: Some(th.style(Style::CONTAINER_BASE)),
379        select: Some(th.style(Style::TEXT_SELECT)),
380        scroll: Some(scroll(th)),
381        border_style: Some(th.style(Style::CONTAINER_BORDER)),
382        ..TextStyle::default()
383    }
384}
385
386fn view(th: &SalsaTheme) -> ViewStyle {
387    ViewStyle {
388        scroll: Some(scroll(th)),
389        ..Default::default()
390    }
391}