1use crate::{Contrast, Scheme};
6use rat_widget::button::ButtonStyle;
7use rat_widget::calendar::CalendarStyle;
8use rat_widget::checkbox::CheckboxStyle;
9use rat_widget::choice::ChoiceStyle;
10use rat_widget::clipper::ClipperStyle;
11use rat_widget::file_dialog::FileDialogStyle;
12use rat_widget::line_number::LineNumberStyle;
13use rat_widget::list::ListStyle;
14use rat_widget::menu::MenuStyle;
15use rat_widget::msgdialog::MsgDialogStyle;
16use rat_widget::pager::PagerStyle;
17use rat_widget::paragraph::ParagraphStyle;
18use rat_widget::popup::PopupStyle;
19use rat_widget::radio::{RadioLayout, RadioStyle};
20use rat_widget::scrolled::ScrollStyle;
21use rat_widget::shadow::{ShadowDirection, ShadowStyle};
22use rat_widget::splitter::SplitStyle;
23use rat_widget::tabbed::TabbedStyle;
24use rat_widget::table::TableStyle;
25use rat_widget::text::TextStyle;
26use rat_widget::view::ViewStyle;
27use ratatui::prelude::{Style, Stylize};
28use ratatui::style::Color;
29use ratatui::widgets::{Block, Borders};
30use std::time::Duration;
31
32#[derive(Debug, Clone)]
40pub struct DarkTheme {
41 s: Scheme,
42 name: String,
43}
44
45impl DarkTheme {
46 pub fn new(name: String, s: Scheme) -> Self {
47 Self { s, name }
48 }
49}
50
51impl DarkTheme {
52 pub fn name(&self) -> &str {
54 &self.name
55 }
56
57 pub fn dark_theme(&self) -> bool {
59 true
60 }
61
62 pub fn scheme(&self) -> &Scheme {
64 &self.s
65 }
66
67 pub fn style(&self, bg: Color) -> Style {
69 self.s.style(bg, Contrast::Normal)
70 }
71
72 pub fn high_style(&self, bg: Color) -> Style {
74 self.s.style(bg, Contrast::High)
75 }
76
77 pub fn white(&self, n: usize) -> Style {
80 self.s.style(self.s.white[n], Contrast::Normal)
81 }
82
83 pub fn black(&self, n: usize) -> Style {
86 self.s.style(self.s.black[n], Contrast::Normal)
87 }
88
89 pub fn gray(&self, n: usize) -> Style {
92 self.s.style(self.s.gray[n], Contrast::Normal)
93 }
94
95 pub fn red(&self, n: usize) -> Style {
98 self.s.style(self.s.red[n], Contrast::Normal)
99 }
100
101 pub fn orange(&self, n: usize) -> Style {
104 self.s.style(self.s.orange[n], Contrast::Normal)
105 }
106
107 pub fn yellow(&self, n: usize) -> Style {
110 self.s.style(self.s.yellow[n], Contrast::Normal)
111 }
112
113 pub fn limegreen(&self, n: usize) -> Style {
116 self.s.style(self.s.limegreen[n], Contrast::Normal)
117 }
118
119 pub fn green(&self, n: usize) -> Style {
122 self.s.style(self.s.green[n], Contrast::Normal)
123 }
124
125 pub fn bluegreen(&self, n: usize) -> Style {
128 self.s.style(self.s.bluegreen[n], Contrast::Normal)
129 }
130
131 pub fn cyan(&self, n: usize) -> Style {
134 self.s.style(self.s.cyan[n], Contrast::Normal)
135 }
136
137 pub fn blue(&self, n: usize) -> Style {
140 self.s.style(self.s.blue[n], Contrast::Normal)
141 }
142
143 pub fn deepblue(&self, n: usize) -> Style {
146 self.s.style(self.s.deepblue[n], Contrast::Normal)
147 }
148
149 pub fn purple(&self, n: usize) -> Style {
152 self.s.style(self.s.purple[n], Contrast::Normal)
153 }
154
155 pub fn magenta(&self, n: usize) -> Style {
158 self.s.style(self.s.magenta[n], Contrast::Normal)
159 }
160
161 pub fn redpink(&self, n: usize) -> Style {
164 self.s.style(self.s.redpink[n], Contrast::Normal)
165 }
166
167 pub fn primary(&self, n: usize) -> Style {
170 self.s.style(self.s.primary[n], Contrast::Normal)
171 }
172
173 pub fn secondary(&self, n: usize) -> Style {
176 self.s.style(self.s.secondary[n], Contrast::Normal)
177 }
178
179 pub fn focus(&self) -> Style {
181 self.high_style(self.s.primary[2])
182 }
183
184 pub fn select(&self) -> Style {
186 self.high_style(self.s.secondary[1])
187 }
188
189 pub fn text_input(&self) -> Style {
191 self.high_style(self.s.gray[3])
192 }
193
194 pub fn text_focus(&self) -> Style {
196 self.high_style(self.s.primary[1])
197 }
198
199 pub fn text_select(&self) -> Style {
201 self.high_style(self.s.secondary[1])
202 }
203
204 pub fn container_base(&self) -> Style {
206 self.style(self.s.black[1])
207 }
208
209 pub fn container_border(&self) -> Style {
211 self.container_base().fg(self.s.gray[0])
212 }
213
214 pub fn container_arrow(&self) -> Style {
216 self.container_base().fg(self.s.gray[0])
217 }
218
219 pub fn popup_base(&self) -> Style {
221 self.style(self.s.white[0])
222 }
223
224 pub fn popup_label(&self) -> Style {
226 self.style(self.s.white[0])
227 }
228
229 pub fn popup_border(&self) -> Style {
231 self.popup_base().fg(self.s.gray[0])
232 }
233
234 pub fn popup_arrow(&self) -> Style {
236 self.popup_base().fg(self.s.gray[0])
237 }
238
239 pub fn dialog_base(&self) -> Style {
241 self.style(self.s.gray[1])
242 }
243
244 pub fn dialog_label(&self) -> Style {
246 self.dialog_base()
247 }
248
249 pub fn dialog_border(&self) -> Style {
251 self.dialog_base().fg(self.s.white[0])
252 }
253
254 pub fn dialog_arrow(&self) -> Style {
256 self.dialog_base().fg(self.s.white[0])
257 }
258
259 pub fn status_base(&self) -> Style {
261 self.style(self.s.black[2])
262 }
263
264 pub fn button_base(&self) -> Style {
266 self.style(self.s.gray[2])
267 }
268
269 pub fn button_armed(&self) -> Style {
271 self.style(self.s.secondary[0])
272 }
273
274 pub fn month_style(&self) -> CalendarStyle {
276 CalendarStyle {
277 style: self.style(self.s.black[2]),
278 title: None,
279 weeknum: Some(Style::new().fg(self.s.limegreen[2])),
280 weekday: Some(Style::new().fg(self.s.limegreen[2])),
281 day: None,
282 select: Some(self.select()),
283 focus: Some(self.focus()),
284 ..CalendarStyle::default()
285 }
286 }
287
288 pub fn shadow_style(&self) -> ShadowStyle {
290 ShadowStyle {
291 style: Style::new().bg(self.s.black[0]),
292 dir: ShadowDirection::BottomRight,
293 ..ShadowStyle::default()
294 }
295 }
296
297 pub fn line_nr_style(&self) -> LineNumberStyle {
299 LineNumberStyle {
300 style: self.container_base().fg(self.s.gray[1]),
301 cursor: Some(self.text_select()),
302 ..LineNumberStyle::default()
303 }
304 }
305
306 pub fn textarea_style(&self) -> TextStyle {
308 TextStyle {
309 style: self.container_base(),
310 focus: Some(self.focus()),
311 select: Some(self.text_select()),
312 scroll: Some(self.scroll_style()),
313 border_style: Some(self.container_border()),
314 ..TextStyle::default()
315 }
316 }
317
318 pub fn text_style(&self) -> TextStyle {
320 TextStyle {
321 style: self.text_input(),
322 focus: Some(self.text_focus()),
323 select: Some(self.text_select()),
324 invalid: Some(Style::default().bg(self.s.red[3])),
325 ..TextStyle::default()
326 }
327 }
328
329 pub fn paragraph_style(&self) -> ParagraphStyle {
330 ParagraphStyle {
331 style: self.container_base(),
332 focus: Some(self.focus()),
333 scroll: Some(self.scroll_style()),
334 ..Default::default()
335 }
336 }
337
338 pub fn choice_style(&self) -> ChoiceStyle {
339 ChoiceStyle {
340 style: self.text_input(),
341 select: Some(self.text_select()),
342 focus: Some(self.text_focus()),
343 popup: PopupStyle {
344 style: self.popup_base(),
345 scroll: Some(self.popup_scroll_style()),
346 block: Some(
347 Block::bordered()
348 .borders(Borders::LEFT)
349 .border_style(self.popup_arrow()),
350 ),
351 ..Default::default()
352 },
353 ..Default::default()
354 }
355 }
356
357 pub fn radio_style(&self) -> RadioStyle {
358 RadioStyle {
359 layout: Some(RadioLayout::Stacked),
360 style: self.text_input(),
361 focus: Some(self.text_focus()),
362 ..Default::default()
363 }
364 }
365
366 pub fn checkbox_style(&self) -> CheckboxStyle {
368 CheckboxStyle {
369 style: self.text_input(),
370 focus: Some(self.text_focus()),
371 ..Default::default()
372 }
373 }
374
375 pub fn menu_style(&self) -> MenuStyle {
377 let menu = Style::default().fg(self.s.white[3]).bg(self.s.black[2]);
378 MenuStyle {
379 style: menu,
380 title: Some(Style::default().fg(self.s.black[0]).bg(self.s.yellow[2])),
381 select: Some(self.select()),
382 focus: Some(self.focus()),
383 right: Some(Style::default().fg(self.s.bluegreen[0])),
384 disabled: Some(Style::default().fg(self.s.gray[0])),
385 highlight: Some(Style::default().underlined()),
386 popup: PopupStyle {
387 style: menu,
388 block: Some(Block::bordered()),
389 ..Default::default()
390 },
391 ..Default::default()
392 }
393 }
394
395 pub fn button_style(&self) -> ButtonStyle {
397 ButtonStyle {
398 style: self.button_base(),
399 focus: Some(self.focus()),
400 armed: Some(self.select()),
401 armed_delay: Some(Duration::from_millis(50)),
402 ..Default::default()
403 }
404 }
405
406 pub fn table_style(&self) -> TableStyle {
408 TableStyle {
409 style: self.container_base(),
410 select_row: Some(self.select()),
411 show_row_focus: true,
412 focus_style: Some(self.focus()),
413 border_style: Some(self.container_border()),
414 scroll: Some(self.scroll_style()),
415 ..Default::default()
416 }
417 }
418
419 pub fn table_header(&self) -> Style {
420 self.style(self.s.blue[2])
421 }
422
423 pub fn table_footer(&self) -> Style {
424 self.style(self.s.blue[2])
425 }
426
427 pub fn list_style(&self) -> ListStyle {
429 ListStyle {
430 style: self.container_base(),
431 select: Some(self.select()),
432 focus: Some(self.focus()),
433 scroll: Some(self.scroll_style()),
434 ..Default::default()
435 }
436 }
437
438 pub fn scroll_style(&self) -> ScrollStyle {
440 ScrollStyle {
441 thumb_style: Some(self.container_border()),
442 track_style: Some(self.container_border()),
443 min_style: Some(self.container_border()),
444 begin_style: Some(self.container_arrow()),
445 end_style: Some(self.container_arrow()),
446 ..Default::default()
447 }
448 }
449
450 pub fn popup_scroll_style(&self) -> ScrollStyle {
452 ScrollStyle {
453 thumb_style: Some(self.popup_border()),
454 track_style: Some(self.popup_border()),
455 min_style: Some(self.popup_border()),
456 begin_style: Some(self.popup_arrow()),
457 end_style: Some(self.popup_arrow()),
458 ..Default::default()
459 }
460 }
461
462 pub fn dialog_scroll_style(&self) -> ScrollStyle {
464 ScrollStyle {
465 thumb_style: Some(self.dialog_border()),
466 track_style: Some(self.dialog_border()),
467 min_style: Some(self.dialog_border()),
468 begin_style: Some(self.dialog_arrow()),
469 end_style: Some(self.dialog_arrow()),
470 ..Default::default()
471 }
472 }
473
474 pub fn split_style(&self) -> SplitStyle {
476 SplitStyle {
477 style: self.container_border(),
478 arrow_style: Some(self.container_arrow()),
479 drag_style: Some(self.focus()),
480 ..Default::default()
481 }
482 }
483
484 pub fn view_style(&self) -> ViewStyle {
486 ViewStyle {
487 scroll: Some(self.scroll_style()),
488 ..Default::default()
489 }
490 }
491
492 pub fn tabbed_style(&self) -> TabbedStyle {
494 let style = self.high_style(self.s.black[1]);
495 TabbedStyle {
496 style,
497 tab: Some(self.gray(1)),
498 select: Some(self.gray(3)),
499 focus: Some(self.focus()),
500 ..Default::default()
501 }
502 }
503
504 pub fn statusline_style(&self) -> Vec<Style> {
509 vec![
510 self.status_base(),
511 self.s.normal_contrast(self.s.white[0]).bg(self.s.blue[3]),
512 self.s.normal_contrast(self.s.white[0]).bg(self.s.blue[2]),
513 self.s.normal_contrast(self.s.white[0]).bg(self.s.blue[1]),
514 ]
515 }
516
517 pub fn file_dialog_style(&self) -> FileDialogStyle {
519 FileDialogStyle {
520 style: self.dialog_base(),
521 list: Some(self.list_style()),
522 roots: Some(ListStyle {
523 style: self.dialog_base(),
524 ..self.list_style()
525 }),
526 text: Some(self.text_style()),
527 button: Some(self.button_style()),
528 block: Some(Block::bordered()),
529 ..Default::default()
530 }
531 }
532
533 pub fn msg_dialog_style(&self) -> MsgDialogStyle {
535 MsgDialogStyle {
536 style: self.dialog_base(),
537 button: Some(self.button_style()),
538 ..Default::default()
539 }
540 }
541
542 pub fn pager_style(&self) -> PagerStyle {
544 PagerStyle {
545 style: self.container_base(),
546 navigation: Some(self.container_arrow()),
547 block: Some(
548 Block::bordered()
549 .borders(Borders::TOP | Borders::BOTTOM)
550 .border_style(self.container_border()),
551 ),
552 ..Default::default()
553 }
554 }
555
556 pub fn clipper_style(&self) -> ClipperStyle {
558 ClipperStyle {
559 style: self.container_base(),
560 scroll: Some(self.scroll_style()),
561 ..Default::default()
562 }
563 }
564}