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 COMBOBOX: &'static str = "combobox";
99    pub const DIALOG_FRAME: &'static str = "dialog-frame";
100    pub const FILE_DIALOG: &'static str = "file-dialog";
101    pub const FORM: &'static str = "form";
102    pub const LINE_NR: &'static str = "line-nr";
103    pub const LIST: &'static str = "list";
104    pub const MENU: &'static str = "menu";
105    pub const MONTH: &'static str = "month";
106    pub const MSG_DIALOG: &'static str = "msg-dialog";
107    pub const PARAGRAPH: &'static str = "paragraph";
108    pub const RADIO: &'static str = "radio";
109    pub const SCROLL: &'static str = "scroll";
110    pub const SCROLL_DIALOG: &'static str = "scroll.dialog";
111    pub const SCROLL_POPUP: &'static str = "scroll.popup";
112    pub const SHADOW: &'static str = "shadow";
113    pub const SLIDER: &'static str = "slider";
114    pub const SPLIT: &'static str = "split";
115    pub const STATUSLINE: &'static str = "statusline";
116    pub const TABBED: &'static str = "tabbed";
117    pub const TABLE: &'static str = "table";
118    pub const TEXT: &'static str = "text";
119    pub const TEXTAREA: &'static str = "textarea";
120    pub const TEXTVIEW: &'static str = "textview";
121    pub const VIEW: &'static str = "view";
122}
123
124/// Extension trait for [Style](ratatui::style::Style) that defines
125/// some standard names used by rat-theme.
126///
127/// Use as
128/// ```rust
129/// # use ratatui::style::Style;
130/// # use rat_theme4::{create_empty, SalsaTheme, StyleName, };
131/// # use rat_theme4::palettes::BLACKOUT;
132/// # let theme = create_empty("", BLACKOUT);
133///
134/// let s: Style = theme.style(Style::INPUT);
135/// ```
136pub trait StyleName {
137    const LABEL: &'static str = "label";
138    const INPUT: &'static str = "input";
139    const FOCUS: &'static str = "focus";
140    const SELECT: &'static str = "select";
141    const TEXT_FOCUS: &'static str = "text-focus";
142    const TEXT_SELECT: &'static str = "text-select";
143    const BUTTON_BASE: &'static str = "button-base";
144
145    const CONTAINER_BASE: &'static str = "container-base";
146    const CONTAINER_BORDER: &'static str = "container-border";
147    const CONTAINER_ARROWS: &'static str = "container-arrows";
148
149    const POPUP_BASE: &'static str = "popup-base";
150    const POPUP_BORDER: &'static str = "popup-border";
151    const POPUP_ARROW: &'static str = "popup-arrow";
152
153    const DIALOG_BASE: &'static str = "dialog-base";
154    const DIALOG_BORDER: &'static str = "dialog-border";
155    const DIALOG_ARROW: &'static str = "dialog-arrow";
156
157    const STATUS_BASE: &'static str = "status-base";
158}
159impl StyleName for Style {}
160
161static LOG_DEFINES: AtomicBool = AtomicBool::new(false);
162
163/// Log style definition.
164pub fn log_style_define(log: bool) {
165    LOG_DEFINES.store(log, Ordering::Release);
166}
167
168fn is_log_style_define() -> bool {
169    LOG_DEFINES.load(Ordering::Acquire)
170}
171
172const PALETTES: &[&str] = &[
173    "Imperial",
174    "Radium",
175    "Tundra",
176    "Ocean",
177    "Monochrome",
178    "Black & White",
179    "Base16",
180    "Base16 Relax",
181    "Monekai",
182    "Solarized",
183    "OxoCarbon",
184    "Rust",
185    "Blackout",
186    "Shell",
187    "VSCode",
188];
189
190/// All currently existing color palettes.
191pub fn salsa_palettes() -> Vec<&'static str> {
192    Vec::from(PALETTES)
193}
194
195/// Get a Palette by name.
196pub fn create_palette(name: &str) -> Option<Palette> {
197    use crate::palettes::*;
198    match name {
199        "Imperial" => Some(IMPERIAL),
200        "Radium" => Some(RADIUM),
201        "Tundra" => Some(TUNDRA),
202        "Ocean" => Some(OCEAN),
203        "Monochrome" => Some(MONOCHROME),
204        "Black & White" => Some(BLACKWHITE),
205        "Base16" => Some(BASE16),
206        "Base16 Relax" => Some(BASE16_RELAX),
207        "Monekai" => Some(MONEKAI),
208        "Solarized" => Some(SOLARIZED),
209        "OxoCarbon" => Some(OXOCARBON),
210        "Rust" => Some(RUST),
211        "Red" => Some(RED),
212        "Blackout" => Some(BLACKOUT),
213        "Shell" => Some(SHELL),
214        "VSCode" => Some(VSCODE_DARK),
215        _ => None,
216    }
217}
218
219const THEMES: &[&str] = &[
220    "Imperial Dark",
221    "Radium Dark",
222    "Tundra Dark",
223    "Ocean Dark",
224    "Monochrome Dark",
225    "Black & White Dark",
226    "Base16 Dark",
227    "Base16 Relax Dark",
228    "Monekai Dark",
229    "Solarized Dark",
230    "OxoCarbon Dark",
231    "Rust Dark",
232    "Red Dark",
233    "Shell Dark",
234    "VSCode Dark",
235    //
236    "Imperial Shell",
237    "Radium Shell",
238    "Tundra Shell",
239    "Ocean Shell",
240    "Monochrome Shell",
241    "Black & White Shell",
242    "Base16 Shell",
243    "Base16 Relax Shell",
244    "Monekai Shell",
245    "Solarized Shell",
246    "OxoCarbon Shell",
247    "Rust Shell",
248    "Red Shell",
249    "Shell Shell",
250    "VSCode Shell",
251    //
252    "Blackout Dark",
253    "Blackout Shell",
254    "Fallback",
255];
256
257/// Get all Salsa themes.
258pub fn salsa_themes() -> Vec<&'static str> {
259    Vec::from(THEMES)
260}
261
262/// Create a theme.
263pub fn create_theme(theme: &str) -> Option<SalsaTheme> {
264    use crate::palettes::*;
265    let theme = match theme {
266        "Imperial Dark" => dark_theme(theme, IMPERIAL),
267        "Radium Dark" => dark_theme(theme, RADIUM),
268        "Tundra Dark" => dark_theme(theme, TUNDRA),
269        "Ocean Dark" => dark_theme(theme, OCEAN),
270        "Monochrome Dark" => dark_theme(theme, MONOCHROME),
271        "Black & White Dark" => dark_theme(theme, BLACKWHITE),
272        "Base16 Dark" => dark_theme(theme, BASE16),
273        "Base16 Relax Dark" => dark_theme(theme, BASE16_RELAX),
274        "Monekai Dark" => dark_theme(theme, MONEKAI),
275        "Solarized Dark" => dark_theme(theme, SOLARIZED),
276        "OxoCarbon Dark" => dark_theme(theme, OXOCARBON),
277        "Rust Dark" => dark_theme(theme, RUST),
278        "Red Dark" => dark_theme(theme, RED),
279        "Shell Dark" => dark_theme(theme, SHELL),
280        "VSCode Dark" => dark_theme(theme, VSCODE_DARK),
281
282        "Imperial Shell" => shell_theme(theme, IMPERIAL),
283        "Radium Shell" => shell_theme(theme, RADIUM),
284        "Tundra Shell" => shell_theme(theme, TUNDRA),
285        "Ocean Shell" => shell_theme(theme, OCEAN),
286        "Monochrome Shell" => shell_theme(theme, MONOCHROME),
287        "Black & White Shell" => shell_theme(theme, BLACKWHITE),
288        "Base16 Shell" => shell_theme(theme, BASE16),
289        "Base16 Relax Shell" => shell_theme(theme, BASE16_RELAX),
290        "Monekai Shell" => shell_theme(theme, MONEKAI),
291        "Solarized Shell" => shell_theme(theme, SOLARIZED),
292        "OxoCarbon Shell" => shell_theme(theme, OXOCARBON),
293        "Rust Shell" => shell_theme(theme, RUST),
294        "Red Shell" => shell_theme(theme, RED),
295        "Shell Shell" => shell_theme(theme, SHELL),
296        "VSCode Shell" => shell_theme(theme, VSCODE_DARK),
297
298        "Blackout Dark" => dark_theme(theme, BLACKOUT),
299        "Blackout Shell" => shell_theme(theme, BLACKOUT),
300        "Fallback" => fallback_theme(theme, RED),
301
302        _ => return None,
303    };
304
305    Some(theme)
306}
307
308/// Create an empty SalsaTheme.
309pub fn create_empty(name: &str, p: Palette) -> SalsaTheme {
310    SalsaTheme::new(name, Category::Other, p)
311}