1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
use palette::Srgba;
use serde::{Deserialize, Serialize};

use crate::composite::over;

/// Theme Container colors of a theme, can be a theme background container, primary container, or secondary container
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)]
#[must_use]
pub struct Container {
    /// the color of the container
    pub base: Srgba,
    /// the color of components in the container
    pub component: Component,
    /// the color of dividers in the container
    pub divider: Srgba,
    /// the color of text in the container
    pub on: Srgba,
    /// the color of @small_widget_container
    pub small_widget: Srgba,
}

impl Container {
    pub(crate) fn new(
        component: Component,
        base: Srgba,
        on: Srgba,
        mut small_widget: Srgba,
    ) -> Self {
        let mut divider_c = on;
        divider_c.alpha = 0.2;

        small_widget.alpha = 0.25;

        Self {
            base,
            component,
            divider: over(divider_c, base),
            on,
            small_widget,
        }
    }
}

/// The colors for a widget of the Cosmic theme
#[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize)]
#[must_use]
pub struct Component {
    /// The base color of the widget
    pub base: Srgba,
    /// The color of the widget when it is hovered
    pub hover: Srgba,
    /// the color of the widget when it is pressed
    pub pressed: Srgba,
    /// the color of the widget when it is selected
    pub selected: Srgba,
    /// the color of the widget when it is selected
    pub selected_text: Srgba,
    /// the color of the widget when it is focused
    pub focus: Srgba,
    /// the color of dividers for this widget
    pub divider: Srgba,
    /// the color of text for this widget
    pub on: Srgba,
    // the color of text with opacity 80 for this widget
    // pub text_opacity_80: Srgba,
    /// the color of the widget when it is disabled
    pub disabled: Srgba,
    /// the color of text in the widget when it is disabled
    pub on_disabled: Srgba,
    /// the color of the border for the widget
    pub border: Srgba,
    /// the color of the border for the widget when it is disabled
    pub disabled_border: Srgba,
}

#[allow(clippy::must_use_candidate)]
#[allow(clippy::doc_markdown)]
impl Component {
    /// get @hover_state_color
    pub fn hover_state_color(&self) -> Srgba {
        self.hover
    }

    /// get @pressed_state_color
    pub fn pressed_state_color(&self) -> Srgba {
        self.pressed
    }

    /// get @selected_state_color
    pub fn selected_state_color(&self) -> Srgba {
        self.selected
    }

    /// get @selected_state_text_color
    pub fn selected_state_text_color(&self) -> Srgba {
        self.selected_text
    }

    /// get @focus_color
    pub fn focus_color(&self) -> Srgba {
        self.focus
    }

    /// helper for producing a component from a base color a neutral and an accent
    pub fn colored_component(
        base: Srgba,
        neutral: Srgba,
        accent: Srgba,
        hovered: Srgba,
        pressed: Srgba,
    ) -> Self {
        let base: Srgba = base;
        let mut base_50 = base;
        base_50.alpha *= 0.5;

        let on_20 = neutral;
        let mut on_50: Srgba = on_20;
        on_50.alpha = 0.5;

        Component {
            base,
            hover: over(hovered, base),
            pressed: over(pressed, base),
            selected: over(hovered, base),
            selected_text: accent,
            divider: on_20,
            on: neutral,
            disabled: over(base_50, base),
            on_disabled: over(on_50, base),
            focus: accent,
            border: base,
            disabled_border: base_50,
        }
    }

    /// helper for producing a button component
    pub fn colored_button(
        base: Srgba,
        overlay: Srgba,
        on_button: Srgba,
        accent: Srgba,
        hovered: Srgba,
        pressed: Srgba,
    ) -> Self {
        let mut component = Component::colored_component(base, overlay, accent, hovered, pressed);
        component.on = on_button;

        let mut on_disabled = on_button;
        on_disabled.alpha = 0.5;
        component.on_disabled = on_disabled;

        component
    }

    /// helper for producing a component color theme
    #[allow(clippy::self_named_constructors)]
    pub fn component(
        base: Srgba,
        accent: Srgba,
        on_component: Srgba,
        hovered: Srgba,
        pressed: Srgba,
        is_high_contrast: bool,
        border: Srgba,
    ) -> Self {
        let mut base_50 = base;
        base_50.alpha *= 0.5;

        let mut on_20 = on_component;
        let mut on_50 = on_20;

        on_20.alpha = 0.2;
        on_50.alpha = 0.5;

        let mut disabled_border = border;
        disabled_border.alpha *= 0.5;

        Component {
            base,
            hover: if base.alpha < 0.001 {
                hovered
            } else {
                over(hovered, base)
            },
            pressed: if base.alpha < 0.001 {
                pressed
            } else {
                over(pressed, base)
            },
            selected: if base.alpha < 0.001 {
                hovered
            } else {
                over(hovered, base)
            },
            selected_text: accent,
            focus: accent,
            divider: if is_high_contrast { on_50 } else { on_20 },
            on: on_component,
            disabled: over(base_50, base),
            on_disabled: over(on_50, base),
            border,
            disabled_border,
        }
    }
}