Skip to main content

gitkraft_gui/features/theme/
view.rs

1//! Theme selector widget for the GitKraft GUI.
2//!
3//! Provides a [`pick_list()`] drop-down that lets the user switch between
4//! "System" plus all unified themes defined in `gitkraft_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 core presets as [`ThemeChoice`] values, derived from the canonical
25/// core definitions.
26pub(crate) fn all_themes() -> Vec<ThemeChoice> {
27    gitkraft_core::THEME_NAMES
28        .iter()
29        .enumerate()
30        .map(|(i, name)| ThemeChoice { index: i, name })
31        .collect()
32}
33
34/// [`all_themes`] preceded by a "System" entry (index `THEME_COUNT`).
35pub(crate) fn theme_choices() -> Vec<ThemeChoice> {
36    let mut v = vec![ThemeChoice {
37        index: gitkraft_core::THEME_COUNT,
38        name: gitkraft_core::SYSTEM_THEME_NAME,
39    }];
40    v.extend(all_themes());
41    v
42}
43
44/// Create a theme selector [`pick_list()`] widget.
45///
46/// Lists "System" first, then every preset. Selecting an entry emits
47/// [`Message::ThemeChanged`] (`THEME_COUNT` for System, else the preset index).
48pub(crate) fn theme_selector(
49    current_theme_index: usize,
50    follow_system: bool,
51    width: f32,
52) -> Element<'static, Message> {
53    let choices = theme_choices();
54    let selected = if follow_system {
55        choices.first().cloned()
56    } else {
57        // +1: the "System" entry is listed first.
58        choices.get(current_theme_index + 1).cloned()
59    };
60
61    pick_list(choices, selected, |choice| {
62        Message::ThemeChanged(choice.index)
63    })
64    .placeholder("Select theme")
65    .text_size(13.0)
66    .width(Length::Fixed(width))
67    .into()
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn choices_lead_with_system() {
76        let c = theme_choices();
77        assert_eq!(c.len(), gitkraft_core::THEME_COUNT + 1);
78        assert_eq!(c[0].index, gitkraft_core::THEME_COUNT);
79        assert_eq!(c[0].name, "System");
80        assert_eq!(c[1].index, 0);
81    }
82
83    #[test]
84    fn all_themes_match_core() {
85        let t = all_themes();
86        assert_eq!(t.len(), gitkraft_core::THEME_COUNT);
87        assert!(t.iter().enumerate().all(|(i, c)| c.index == i));
88    }
89}