tui_vision/menus/
theme.rs

1use ratatui_core::style::{Color, Style};
2
3/// Color scheme for menu rendering.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct MenuTheme {
6    /// Style for the menu bar background and text.
7    pub menu_bar: Style,
8    /// Style for a focused menu title in the menu bar.
9    pub menu_bar_focused: Style,
10    /// Style for dropdown background and borders.
11    pub dropdown: Style,
12    /// Style for dropdown borders specifically.
13    pub dropdown_border: Style,
14    /// Style for normal menu items.
15    pub item: Style,
16    /// Style for focused/selected menu items.
17    pub item_focused: Style,
18    /// Style for disabled menu items.
19    pub item_disabled: Style,
20    /// Style for separators.
21    pub separator: Style,
22    /// Style for submenu indicators (arrow).
23    pub submenu_indicator: Style,
24}
25
26impl MenuTheme {
27    /// Creates a classic MS-DOS edit.com style theme (cyan/blue).
28    pub fn classic() -> Self {
29        Self {
30            menu_bar: Style::default().bg(Color::Cyan).fg(Color::Black),
31            menu_bar_focused: Style::default().bg(Color::Blue).fg(Color::White),
32            dropdown: Style::default().bg(Color::Blue).fg(Color::White),
33            dropdown_border: Style::default().bg(Color::Blue).fg(Color::White),
34            item: Style::default().bg(Color::Blue).fg(Color::White),
35            item_focused: Style::default().bg(Color::White).fg(Color::Black),
36            item_disabled: Style::default().bg(Color::Blue).fg(Color::DarkGray),
37            separator: Style::default().bg(Color::Blue).fg(Color::White),
38            submenu_indicator: Style::default().bg(Color::Blue).fg(Color::White),
39        }
40    }
41
42    /// Creates a modern dark theme.
43    pub fn dark() -> Self {
44        Self {
45            menu_bar: Style::default().bg(Color::Rgb(45, 45, 45)).fg(Color::White),
46            menu_bar_focused: Style::default()
47                .bg(Color::Rgb(70, 130, 180))
48                .fg(Color::White),
49            dropdown: Style::default().bg(Color::Rgb(60, 60, 60)).fg(Color::White),
50            dropdown_border: Style::default().bg(Color::Rgb(60, 60, 60)).fg(Color::White),
51            item: Style::default().bg(Color::Rgb(60, 60, 60)).fg(Color::White),
52            item_focused: Style::default()
53                .bg(Color::Rgb(70, 130, 180))
54                .fg(Color::White),
55            item_disabled: Style::default()
56                .bg(Color::Rgb(60, 60, 60))
57                .fg(Color::Rgb(120, 120, 120)),
58            separator: Style::default().bg(Color::Rgb(60, 60, 60)).fg(Color::White),
59            submenu_indicator: Style::default().bg(Color::Rgb(60, 60, 60)).fg(Color::White),
60        }
61    }
62
63    /// Creates a light modern theme.
64    pub fn light() -> Self {
65        Self {
66            menu_bar: Style::default()
67                .bg(Color::Rgb(248, 248, 248))
68                .fg(Color::Black),
69            menu_bar_focused: Style::default()
70                .bg(Color::Rgb(70, 130, 180))
71                .fg(Color::White),
72            dropdown: Style::default().bg(Color::White).fg(Color::Black),
73            dropdown_border: Style::default()
74                .bg(Color::Rgb(200, 200, 200))
75                .fg(Color::Black),
76            item: Style::default()
77                .bg(Color::Rgb(200, 200, 200))
78                .fg(Color::Black),
79            item_focused: Style::default()
80                .bg(Color::Rgb(70, 130, 180))
81                .fg(Color::White),
82            item_disabled: Style::default()
83                .bg(Color::White)
84                .fg(Color::Rgb(150, 150, 150)),
85            separator: Style::default()
86                .bg(Color::Rgb(200, 200, 200))
87                .fg(Color::Black),
88            submenu_indicator: Style::default().bg(Color::White).fg(Color::Black),
89        }
90    }
91
92    /// Creates a vibrant terminal theme with bright colors.
93    pub fn terminal() -> Self {
94        Self {
95            menu_bar: Style::default().bg(Color::Black).fg(Color::Green),
96            menu_bar_focused: Style::default().bg(Color::Green).fg(Color::Black),
97            dropdown: Style::default().bg(Color::Black).fg(Color::Green),
98            dropdown_border: Style::default().bg(Color::Black).fg(Color::Green),
99            item: Style::default().bg(Color::Black).fg(Color::Green),
100            item_focused: Style::default().bg(Color::Green).fg(Color::Black),
101            item_disabled: Style::default().bg(Color::Black).fg(Color::DarkGray),
102            separator: Style::default().bg(Color::Black).fg(Color::Green),
103            submenu_indicator: Style::default().bg(Color::Black).fg(Color::Green),
104        }
105    }
106}
107
108impl Default for MenuTheme {
109    fn default() -> Self {
110        Self::classic()
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn theme_presets_have_different_colors() {
120        let classic = MenuTheme::classic();
121        let dark = MenuTheme::dark();
122        let light = MenuTheme::light();
123        let terminal = MenuTheme::terminal();
124
125        // Ensure themes are actually different
126        assert_ne!(classic.menu_bar, dark.menu_bar);
127        assert_ne!(classic.menu_bar, light.menu_bar);
128        assert_ne!(classic.menu_bar, terminal.menu_bar);
129        assert_ne!(dark.menu_bar, light.menu_bar);
130    }
131
132    #[test]
133    fn default_theme_is_classic() {
134        assert_eq!(MenuTheme::default(), MenuTheme::classic());
135    }
136}