1use crate::buffer::CellStyle;
2use crate::geom::Insets;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum Theme {
7 Dark,
8 Light,
9}
10
11thread_local! {
12 pub static CURRENT_THEME: std::cell::RefCell<Theme> = std::cell::RefCell::new(Theme::Dark);
14}
15
16pub fn set_theme(theme: Theme) {
18 CURRENT_THEME.with(|t| *t.borrow_mut() = theme);
19 crate::runtime::FORCE_FULL_PAINT.with(|f| *f.borrow_mut() = true);
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum Color {
26 Black,
27 Red,
28 Green,
29 Yellow,
30 Blue,
31 Magenta,
32 Cyan,
33 White,
34 Gray,
35}
36
37impl From<Color> for crossterm::style::Color {
38 fn from(c: Color) -> Self {
39 let dark = CURRENT_THEME.with(|t| *t.borrow() == Theme::Dark);
40 match (c, dark) {
41 (Color::Black, _) => crossterm::style::Color::Black,
42 (Color::Red, true) => crossterm::style::Color::DarkRed,
43 (Color::Red, false) => crossterm::style::Color::Red,
44 (Color::Green, true) => crossterm::style::Color::DarkGreen,
45 (Color::Green, false) => crossterm::style::Color::Green,
46 (Color::Yellow, true) => crossterm::style::Color::DarkYellow,
47 (Color::Yellow, false) => crossterm::style::Color::Yellow,
48 (Color::Blue, true) => crossterm::style::Color::DarkBlue,
49 (Color::Blue, false) => crossterm::style::Color::Blue,
50 (Color::Magenta, true) => crossterm::style::Color::DarkMagenta,
51 (Color::Magenta, false) => crossterm::style::Color::Magenta,
52 (Color::Cyan, true) => crossterm::style::Color::DarkCyan,
53 (Color::Cyan, false) => crossterm::style::Color::Cyan,
54 (Color::White, _) => crossterm::style::Color::Grey,
55 (Color::Gray, true) => crossterm::style::Color::DarkGrey,
56 (Color::Gray, false) => crossterm::style::Color::Grey,
57 }
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum Length {
64 Auto,
66 Fixed(u16),
68 Percent(u16),
70 Fraction(u16),
72}
73
74impl Default for Length {
75 fn default() -> Self {
76 Length::Auto
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum Layout {
83 None,
84 Vertical,
85 Horizontal,
86}
87
88impl Default for Layout {
89 fn default() -> Self {
90 Layout::None
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
96pub enum TextWrap {
97 #[default]
99 None,
100 Char,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
106pub enum TextAlign {
107 #[default]
108 Left,
109 Center,
110 Right,
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
115pub enum TextTruncate {
116 #[default]
118 None,
119 Ellipsis,
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
125pub enum Border {
126 #[default]
127 None,
128 Plain,
129 Rounded,
130 Double,
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct Style {
136 pub fg: Option<Color>,
138 pub bg: Option<Color>,
139 pub bold: bool,
140 pub italic: bool,
141 pub underline: bool,
142
143 pub width: Length,
145 pub height: Length,
146 pub padding: Insets,
147 pub margin: Insets,
148 pub layout: Layout,
149 pub gap: u16,
150 pub flex_grow: u16,
151 pub flex_shrink: bool,
152 pub border: Border,
153}
154
155impl Default for Style {
156 fn default() -> Self {
157 Self {
158 fg: None,
159 bg: None,
160 bold: false,
161 italic: false,
162 underline: false,
163 width: Length::Auto,
164 height: Length::Auto,
165 padding: Insets::ZERO,
166 margin: Insets::ZERO,
167 layout: Layout::None,
168 gap: 0,
169 flex_grow: 0,
170 flex_shrink: true,
171 border: Border::None,
172 }
173 }
174}
175
176impl Style {
177 pub fn fg(mut self, color: Color) -> Self {
179 self.fg = Some(color);
180 self
181 }
182
183 pub fn bg(mut self, color: Color) -> Self {
185 self.bg = Some(color);
186 self
187 }
188
189 pub fn bold(mut self) -> Self {
191 self.bold = true;
192 self
193 }
194
195 pub fn italic(mut self) -> Self {
197 self.italic = true;
198 self
199 }
200
201 pub fn underline(mut self) -> Self {
203 self.underline = true;
204 self
205 }
206
207 pub fn width(mut self, width: Length) -> Self {
209 self.width = width;
210 self
211 }
212
213 pub fn height(mut self, height: Length) -> Self {
215 self.height = height;
216 self
217 }
218
219 pub fn padding(mut self, value: u16) -> Self {
221 self.padding = Insets::all(value);
222 self
223 }
224
225 pub fn margin(mut self, value: u16) -> Self {
227 self.margin = Insets::all(value);
228 self
229 }
230
231 pub fn layout(mut self, layout: Layout) -> Self {
233 self.layout = layout;
234 self
235 }
236
237 pub fn gap(mut self, gap: u16) -> Self {
239 self.gap = gap;
240 self
241 }
242
243 pub fn flex_grow(mut self, grow: u16) -> Self {
245 self.flex_grow = grow;
246 self
247 }
248
249 pub fn flex_shrink(mut self, shrink: bool) -> Self {
251 self.flex_shrink = shrink;
252 self
253 }
254
255 pub fn border(mut self, border: Border) -> Self {
257 self.border = border;
258 self
259 }
260
261 pub fn into_cell_style(&self) -> CellStyle {
263 CellStyle {
264 fg: self.fg,
265 bg: self.bg,
266 bold: self.bold,
267 italic: self.italic,
268 underline: self.underline,
269 }
270 }
271}