rust_kanban/ui/rendering/popup/
change_theme.rs

1use crate::{
2    app::{
3        state::{Focus, KeyBindingEnum},
4        App,
5    },
6    constants::LIST_SELECTED_SYMBOL,
7    ui::{
8        rendering::{
9            common::{render_blank_styled_canvas, render_close_button},
10            popup::ChangeTheme,
11            utils::{
12                centered_rect_with_percentage, check_if_active_and_get_style,
13                check_if_mouse_is_in_area,
14            },
15        },
16        Renderable,
17    },
18};
19use ratatui::{
20    layout::{Alignment, Constraint, Direction, Layout},
21    text::{Line, Span},
22    widgets::{Block, BorderType, Borders, List, ListItem, Paragraph},
23    Frame,
24};
25
26impl Renderable for ChangeTheme {
27    fn render(rect: &mut Frame, app: &mut App, is_active: bool) {
28        let general_style = check_if_active_and_get_style(
29            is_active,
30            app.current_theme.inactive_text_style,
31            app.current_theme.general_style,
32        );
33        let list_select_style = check_if_active_and_get_style(
34            is_active,
35            app.current_theme.inactive_text_style,
36            app.current_theme.list_select_style,
37        );
38        let keyboard_focus_style = check_if_active_and_get_style(
39            is_active,
40            app.current_theme.inactive_text_style,
41            app.current_theme.keyboard_focus_style,
42        );
43        let help_key_style = check_if_active_and_get_style(
44            is_active,
45            app.current_theme.inactive_text_style,
46            app.current_theme.help_key_style,
47        );
48        let help_text_style = check_if_active_and_get_style(
49            is_active,
50            app.current_theme.inactive_text_style,
51            app.current_theme.help_text_style,
52        );
53        let render_area = centered_rect_with_percentage(70, 70, rect.area());
54        let clear_area = centered_rect_with_percentage(80, 80, rect.area());
55        let clear_area_border = Block::default()
56            .title("Change Theme")
57            .style(general_style)
58            .borders(Borders::ALL)
59            .border_style(keyboard_focus_style)
60            .border_type(BorderType::Rounded);
61
62        let chunks = Layout::default()
63            .direction(Direction::Vertical)
64            .constraints([Constraint::Fill(1), Constraint::Length(5)].as_ref())
65            .split(render_area);
66
67        let theme_list = app
68            .all_themes
69            .iter()
70            .map(|t| ListItem::new(vec![Line::from(t.name.clone())]))
71            .collect::<Vec<ListItem>>();
72
73        if check_if_mouse_is_in_area(&app.state.current_mouse_coordinates, &chunks[0]) {
74            app.state.mouse_focus = Some(Focus::ThemeSelector);
75            app.state.set_focus(Focus::ThemeSelector);
76            let top_of_list = chunks[0].y + 1;
77            let mut bottom_of_list = chunks[0].y + theme_list.len() as u16;
78            if bottom_of_list > chunks[0].bottom() {
79                bottom_of_list = chunks[0].bottom();
80            }
81            let mouse_y = app.state.current_mouse_coordinates.1;
82            if mouse_y >= top_of_list && mouse_y <= bottom_of_list {
83                app.state
84                    .app_list_states
85                    .theme_selector
86                    .select(Some((mouse_y - top_of_list) as usize));
87                let selected_theme = app
88                    .all_themes
89                    .get(app.state.app_list_states.theme_selector.selected().unwrap())
90                    .unwrap();
91                app.current_theme = selected_theme.clone();
92            } else {
93                app.state.app_list_states.theme_selector.select(None);
94            }
95        };
96        let themes = List::new(theme_list)
97            .block(
98                Block::default()
99                    .style(general_style)
100                    .borders(Borders::ALL)
101                    .border_type(BorderType::Rounded),
102            )
103            .highlight_style(list_select_style)
104            .highlight_symbol(LIST_SELECTED_SYMBOL);
105
106        let up_key = app
107            .get_first_keybinding(KeyBindingEnum::Up)
108            .unwrap_or("".to_string());
109        let down_key = app
110            .get_first_keybinding(KeyBindingEnum::Down)
111            .unwrap_or("".to_string());
112        let accept_key = app
113            .get_first_keybinding(KeyBindingEnum::Accept)
114            .unwrap_or("".to_string());
115        let cancel_key = app
116            .get_first_keybinding(KeyBindingEnum::GoToPreviousViewOrCancel)
117            .unwrap_or("".to_string());
118
119        let help_spans = Line::from(vec![
120            Span::styled("Use ", help_text_style),
121            Span::styled(up_key, help_key_style),
122            Span::styled(" or ", help_text_style),
123            Span::styled(down_key, help_key_style),
124            Span::styled(
125                " to navigate or use the mouse cursor. Press ",
126                help_text_style,
127            ),
128            Span::styled(accept_key, help_key_style),
129            Span::styled(" or ", help_text_style),
130            Span::styled("<Mouse Left Click>", help_key_style),
131            Span::styled(" To select a Theme. Press ", help_text_style),
132            Span::styled(cancel_key, help_key_style),
133            Span::styled(" to cancel", help_text_style),
134        ]);
135
136        let change_theme_help = Paragraph::new(help_spans)
137            .alignment(Alignment::Left)
138            .block(
139                Block::default()
140                    .title("Help")
141                    .borders(Borders::ALL)
142                    .style(general_style)
143                    .border_type(BorderType::Rounded),
144            )
145            .alignment(Alignment::Center)
146            .wrap(ratatui::widgets::Wrap { trim: true });
147
148        render_blank_styled_canvas(rect, &app.current_theme, clear_area, is_active);
149        rect.render_widget(clear_area_border, clear_area);
150        rect.render_stateful_widget(
151            themes,
152            chunks[0],
153            &mut app.state.app_list_states.theme_selector,
154        );
155        rect.render_widget(change_theme_help, chunks[1]);
156        if app.config.enable_mouse_support {
157            render_close_button(rect, app, is_active)
158        }
159    }
160}