Skip to main content

cleansys_gui/
theme_selector.rs

1//! Theme selector widget for the CleanSys GUI.
2//!
3//! Provides a `pick_list()` drop-down that lets the user switch between
4//! all themes defined in `cleansys_core` at runtime.
5
6use iced::widget::pick_list;
7use iced::{Element, Length};
8
9use crate::message::Message;
10
11/// A wrapper around a theme index that implements `Display` for the pick-list.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct ThemeChoice {
14    pub index: usize,
15    pub name: &'static str,
16}
17
18impl std::fmt::Display for ThemeChoice {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        f.write_str(self.name)
21    }
22}
23
24/// All available themes as [`ThemeChoice`] values, derived from the canonical
25/// core definitions.
26pub fn all_themes() -> Vec<ThemeChoice> {
27    cleansys_core::THEME_NAMES
28        .iter()
29        .enumerate()
30        .map(|(i, name)| ThemeChoice { index: i, name })
31        .collect()
32}
33
34/// Create a theme selector `pick_list()` widget.
35///
36/// The widget displays the name of the current theme and, when opened, lists
37/// every theme returned by [`all_themes`]. Selecting a new entry emits
38/// [`Message::ThemeChanged`] with the chosen theme index.
39pub fn theme_selector(current_theme_index: usize) -> Element<'static, Message> {
40    let choices = all_themes();
41    let selected = choices.get(current_theme_index).cloned();
42
43    pick_list(choices, selected, |choice| {
44        Message::ThemeChanged(choice.index)
45    })
46    .placeholder("Select theme")
47    .text_size(13.0)
48    .width(Length::Fixed(200.0))
49    .into()
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn all_themes_matches_core_count() {
58        assert_eq!(all_themes().len(), cleansys_core::THEME_COUNT);
59    }
60
61    #[test]
62    fn all_themes_indices_are_sequential() {
63        for (i, choice) in all_themes().iter().enumerate() {
64            assert_eq!(choice.index, i);
65        }
66    }
67
68    #[test]
69    fn theme_choice_display_matches_name() {
70        let choice = ThemeChoice {
71            index: 9,
72            name: "Dracula",
73        };
74        assert_eq!(format!("{choice}"), "Dracula");
75    }
76}