rat_theme4/
lib.rs

1//!
2//! SalsaTheme provides a styling system for ratatui apps.
3//!
4//! It has a simple flat naming scheme.
5//!
6//! But it can store
7//! * [ratatui Style](ratatui::style::Style)
8//! * composite styles as used by [rat-widget](rat_widget).
9//!   eg [CheckboxStyle](rat_widget::checkbox::CheckboxStyle)
10//! * practically anything else.
11//!
12//! ## Naming styles
13//!
14//! * It has an extension trait for [Style](ratatui::style::Style) that
15//!   adds constants for known styles. In the same manner you can add your
16//!   application specific styles and have them with code completion.
17//!
18//! * For [rat-widget](rat_widget) composite style it defines an anchor struct
19//!   [WidgetStyle] that performs the same purpose.
20//!
21//! ## Usage
22//!
23//! ```rust
24//! # use ratatui::buffer::Buffer;
25//! # use ratatui::layout::Rect;
26//! # use ratatui::style::Style;
27//! # use ratatui::widgets::StatefulWidget;
28//! # use rat_theme4::{create_empty, SalsaTheme, StyleName, WidgetStyle, };
29//! # use rat_theme4::palettes::BLACKOUT;
30//! # use rat_widget::checkbox::{Checkbox, CheckboxState, CheckboxStyle};
31//! # let theme = create_empty("", BLACKOUT);
32//! # let area = Rect::default();
33//! # let mut buf = Buffer::default();
34//! # let buf = &mut buf;
35//! # let mut state = CheckboxState::default();
36//!
37//! Checkbox::new()
38//!     .styles(theme.style(WidgetStyle::CHECKBOX))
39//!     .render(area, buf, &mut state);
40//! ```
41
42use ratatui::style::Style;
43use std::sync::atomic::{AtomicBool, Ordering};
44
45mod dark_theme;
46mod fallback_theme;
47mod palette;
48pub mod palettes;
49mod salsa_theme;
50mod shell_theme;
51
52pub use dark_theme::dark_theme;
53pub use fallback_theme::fallback_theme;
54pub use palette::Palette;
55pub use salsa_theme::{Category, SalsaTheme};
56pub use shell_theme::shell_theme;
57
58/// Anchor struct for the names of composite styles used
59/// by rat-widget's.
60///
61/// Use as
62/// ```rust
63/// # use ratatui::style::Style;
64/// # use rat_theme4::{create_empty, SalsaTheme, StyleName, WidgetStyle};
65/// # use rat_theme4::palettes::BLACKOUT;
66/// # use rat_widget::checkbox::CheckboxStyle;
67/// # let theme = create_empty("", BLACKOUT);
68///
69/// let s: CheckboxStyle = theme.style(WidgetStyle::CHECKBOX);
70/// ```
71/// or more likely
72/// ```rust
73/// # use ratatui::buffer::Buffer;
74/// # use ratatui::layout::Rect;
75/// # use ratatui::style::Style;
76/// # use ratatui::widgets::StatefulWidget;
77/// # use rat_theme4::{create_empty, SalsaTheme, StyleName, WidgetStyle, };
78/// # use rat_theme4::palettes::BLACKOUT;
79/// # use rat_widget::checkbox::{Checkbox, CheckboxState, CheckboxStyle};
80/// # let theme = create_empty("", BLACKOUT);
81/// # let area = Rect::default();
82/// # let mut buf = Buffer::default();
83/// # let buf = &mut buf;
84/// # let mut state = CheckboxState::default();
85///
86/// Checkbox::new()
87///     .styles(theme.style(WidgetStyle::CHECKBOX))
88///     .render(area, buf, &mut state);
89/// ```
90pub struct WidgetStyle;
91
92impl WidgetStyle {
93    pub const BUTTON: &'static str = "button";
94    pub const CALENDAR: &'static str = "calendar";
95    pub const CHECKBOX: &'static str = "checkbox";
96    pub const CHOICE: &'static str = "choice";
97    pub const CLIPPER: &'static str = "clipper";
98    pub const COLOR_INPUT: &'static str = "color-input";
99    pub const COMBOBOX: &'static str = "combobox";
100    pub const DIALOG_FRAME: &'static str = "dialog-frame";
101    pub const FILE_DIALOG: &'static str = "file-dialog";
102    pub const FORM: &'static str = "form";
103    pub const LINE_NR: &'static str = "line-nr";
104    pub const LIST: &'static str = "list";
105    pub const MENU: &'static str = "menu";
106    pub const MONTH: &'static str = "month";
107    pub const MSG_DIALOG: &'static str = "msg-dialog";
108    pub const PARAGRAPH: &'static str = "paragraph";
109    pub const RADIO: &'static str = "radio";
110    pub const SCROLL: &'static str = "scroll";
111    pub const SCROLL_DIALOG: &'static str = "scroll.dialog";
112    pub const SCROLL_POPUP: &'static str = "scroll.popup";
113    pub const SHADOW: &'static str = "shadow";
114    pub const SLIDER: &'static str = "slider";
115    pub const SPLIT: &'static str = "split";
116    pub const STATUSLINE: &'static str = "statusline";
117    pub const TABBED: &'static str = "tabbed";
118    pub const TABLE: &'static str = "table";
119    pub const TEXT: &'static str = "text";
120    pub const TEXTAREA: &'static str = "textarea";
121    pub const TEXTVIEW: &'static str = "textview";
122    pub const VIEW: &'static str = "view";
123}
124
125/// Extension trait for [Style](ratatui::style::Style) that defines
126/// some standard names used by rat-theme.
127///
128/// Use as
129/// ```rust
130/// # use ratatui::style::Style;
131/// # use rat_theme4::{create_empty, SalsaTheme, StyleName, };
132/// # use rat_theme4::palettes::BLACKOUT;
133/// # let theme = create_empty("", BLACKOUT);
134///
135/// let s: Style = theme.style(Style::INPUT);
136/// ```
137pub trait StyleName {
138    const LABEL: &'static str = "label";
139    const INPUT: &'static str = "input";
140    const FOCUS: &'static str = "focus";
141    const SELECT: &'static str = "select";
142    const TEXT_FOCUS: &'static str = "text-focus";
143    const TEXT_SELECT: &'static str = "text-select";
144    const BUTTON_BASE: &'static str = "button-base";
145
146    const CONTAINER_BASE: &'static str = "container-base";
147    const CONTAINER_BORDER: &'static str = "container-border";
148    const CONTAINER_ARROWS: &'static str = "container-arrows";
149
150    const POPUP_BASE: &'static str = "popup-base";
151    const POPUP_BORDER: &'static str = "popup-border";
152    const POPUP_ARROW: &'static str = "popup-arrow";
153
154    const DIALOG_BASE: &'static str = "dialog-base";
155    const DIALOG_BORDER: &'static str = "dialog-border";
156    const DIALOG_ARROW: &'static str = "dialog-arrow";
157
158    const STATUS_BASE: &'static str = "status-base";
159}
160impl StyleName for Style {}
161
162static LOG_DEFINES: AtomicBool = AtomicBool::new(false);
163
164/// Log style definition.
165pub fn log_style_define(log: bool) {
166    LOG_DEFINES.store(log, Ordering::Release);
167}
168
169fn is_log_style_define() -> bool {
170    LOG_DEFINES.load(Ordering::Acquire)
171}
172
173const PALETTES: &[&str] = &[
174    "Imperial",
175    "Radium",
176    "Tundra",
177    "Ocean",
178    "Monochrome",
179    "Black & White",
180    "Base16",
181    "Base16 Relax",
182    "Monekai",
183    "Solarized",
184    "OxoCarbon",
185    "Rust",
186    "Blackout",
187    "Shell",
188    "VSCode",
189];
190
191/// All currently existing color palettes.
192pub fn salsa_palettes() -> Vec<&'static str> {
193    Vec::from(PALETTES)
194}
195
196/// Get a Palette by name.
197pub fn create_palette(name: &str) -> Option<Palette> {
198    use crate::palettes::*;
199    match name {
200        "Imperial" => Some(IMPERIAL),
201        "Radium" => Some(RADIUM),
202        "Tundra" => Some(TUNDRA),
203        "Ocean" => Some(OCEAN),
204        "Monochrome" => Some(MONOCHROME),
205        "Black & White" => Some(BLACKWHITE),
206        "Base16" => Some(BASE16),
207        "Base16 Relax" => Some(BASE16_RELAX),
208        "Monekai" => Some(MONEKAI),
209        "Solarized" => Some(SOLARIZED),
210        "OxoCarbon" => Some(OXOCARBON),
211        "Rust" => Some(RUST),
212        "Red" => Some(RED),
213        "Blackout" => Some(BLACKOUT),
214        "Shell" => Some(SHELL),
215        "VSCode" => Some(VSCODE_DARK),
216        _ => None,
217    }
218}
219
220const THEMES: &[&str] = &[
221    "Imperial Dark",
222    "Radium Dark",
223    "Tundra Dark",
224    "Ocean Dark",
225    "Monochrome Dark",
226    "Black & White Dark",
227    "Base16 Dark",
228    "Base16 Relax Dark",
229    "Monekai Dark",
230    "Solarized Dark",
231    "OxoCarbon Dark",
232    "Rust Dark",
233    "Red Dark",
234    "Shell Dark",
235    "VSCode Dark",
236    //
237    "Imperial Shell",
238    "Radium Shell",
239    "Tundra Shell",
240    "Ocean Shell",
241    "Monochrome Shell",
242    "Black & White Shell",
243    "Base16 Shell",
244    "Base16 Relax Shell",
245    "Monekai Shell",
246    "Solarized Shell",
247    "OxoCarbon Shell",
248    "Rust Shell",
249    "Red Shell",
250    "Shell Shell",
251    "VSCode Shell",
252    //
253    "Blackout Dark",
254    "Blackout Shell",
255    "Fallback",
256];
257
258/// Get all Salsa themes.
259pub fn salsa_themes() -> Vec<&'static str> {
260    Vec::from(THEMES)
261}
262
263/// Create a theme.
264pub fn create_theme(theme: &str) -> Option<SalsaTheme> {
265    use crate::palettes::*;
266    let theme = match theme {
267        "Imperial Dark" => dark_theme(theme, IMPERIAL),
268        "Radium Dark" => dark_theme(theme, RADIUM),
269        "Tundra Dark" => dark_theme(theme, TUNDRA),
270        "Ocean Dark" => dark_theme(theme, OCEAN),
271        "Monochrome Dark" => dark_theme(theme, MONOCHROME),
272        "Black & White Dark" => dark_theme(theme, BLACKWHITE),
273        "Base16 Dark" => dark_theme(theme, BASE16),
274        "Base16 Relax Dark" => dark_theme(theme, BASE16_RELAX),
275        "Monekai Dark" => dark_theme(theme, MONEKAI),
276        "Solarized Dark" => dark_theme(theme, SOLARIZED),
277        "OxoCarbon Dark" => dark_theme(theme, OXOCARBON),
278        "Rust Dark" => dark_theme(theme, RUST),
279        "Red Dark" => dark_theme(theme, RED),
280        "Shell Dark" => dark_theme(theme, SHELL),
281        "VSCode Dark" => dark_theme(theme, VSCODE_DARK),
282
283        "Imperial Shell" => shell_theme(theme, IMPERIAL),
284        "Radium Shell" => shell_theme(theme, RADIUM),
285        "Tundra Shell" => shell_theme(theme, TUNDRA),
286        "Ocean Shell" => shell_theme(theme, OCEAN),
287        "Monochrome Shell" => shell_theme(theme, MONOCHROME),
288        "Black & White Shell" => shell_theme(theme, BLACKWHITE),
289        "Base16 Shell" => shell_theme(theme, BASE16),
290        "Base16 Relax Shell" => shell_theme(theme, BASE16_RELAX),
291        "Monekai Shell" => shell_theme(theme, MONEKAI),
292        "Solarized Shell" => shell_theme(theme, SOLARIZED),
293        "OxoCarbon Shell" => shell_theme(theme, OXOCARBON),
294        "Rust Shell" => shell_theme(theme, RUST),
295        "Red Shell" => shell_theme(theme, RED),
296        "Shell Shell" => shell_theme(theme, SHELL),
297        "VSCode Shell" => shell_theme(theme, VSCODE_DARK),
298
299        "Blackout Dark" => dark_theme(theme, BLACKOUT),
300        "Blackout Shell" => shell_theme(theme, BLACKOUT),
301        "Fallback" => fallback_theme(theme, RED),
302
303        _ => return None,
304    };
305
306    Some(theme)
307}
308
309/// Create an empty SalsaTheme.
310pub fn create_empty(name: &str, p: Palette) -> SalsaTheme {
311    SalsaTheme::new(name, Category::Other, p)
312}