1use crate::Color;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10#[non_exhaustive]
11pub struct TitleBar {
12 pub height: i32,
14 pub font: String,
16 pub font_size: i32,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22#[allow(
23 clippy::exhaustive_structs,
24 reason = "built by callers with `..Default::default()`, which a new field does not break"
25)]
26pub struct Colors {
27 pub panel_top: Color,
29 pub panel_bottom: Color,
31 pub rim_focused: Color,
33 pub rim_blurred: Color,
36 pub shadow: Color,
38 pub title_text: Color,
40 pub title_shadow: Color,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
46#[allow(
47 clippy::exhaustive_structs,
48 reason = "built by callers with `..Default::default()`, which a new field does not break"
49)]
50pub struct Button {
51 pub fill: Color,
53 pub hover: Color,
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
59#[allow(
60 clippy::exhaustive_structs,
61 reason = "built by callers with `..Default::default()`, which a new field does not break"
62)]
63pub struct Buttons {
64 pub close: Button,
66 pub minimize: Button,
68 pub maximize: Button,
70}
71
72#[derive(Debug, Clone, PartialEq)]
74#[allow(
75 clippy::exhaustive_structs,
76 reason = "built by callers with `..Default::default()`, which a new field does not break"
77)]
78pub struct Theme {
79 pub name: String,
81 pub corner_radius: i32,
83 pub title_bar: TitleBar,
85 pub colors: Colors,
87 pub buttons: Buttons,
89 pub noise_amplitude: f64,
95 pub shadow_extent: i32,
97 pub animation_duration_ms: i32,
99}
100
101impl Default for Theme {
102 fn default() -> Self {
103 Self {
104 name: String::new(),
105 corner_radius: 0,
106 title_bar: TitleBar {
107 height: 0,
108 font: String::new(),
109 font_size: 0,
110 },
111 colors: Colors::default(),
112 buttons: Buttons::default(),
113 noise_amplitude: 0.0,
114 shadow_extent: 0,
115 animation_duration_ms: 0,
116 }
117 }
118}
119
120#[must_use]
122pub fn glass_default() -> Theme {
123 Theme {
124 name: "glass-default".to_owned(),
125 corner_radius: 8,
126 title_bar: TitleBar {
127 height: 28,
128 font: "Inter, sans-serif".to_owned(),
129 font_size: 13,
130 },
131 colors: Colors {
132 panel_top: Color::new(0xFF, 0xFF, 0xFF, 0x73),
133 panel_bottom: Color::new(0xFF, 0xFF, 0xFF, 0x26),
134 rim_focused: Color::new(0xFF, 0xFF, 0xFF, 0x99),
135 rim_blurred: Color::new(0xC8, 0xC8, 0xC8, 0x4C),
136 shadow: Color::new(0x00, 0x00, 0x00, 0x8C),
137 title_text: Color::new(0x1E, 0x1E, 0x1E, 0xFF),
138 title_shadow: Color::new(0xFF, 0xFF, 0xFF, 0x66),
139 },
140 buttons: Buttons {
141 close: Button {
142 fill: Color::new(0xFF, 0x5F, 0x56, 0xFF),
143 hover: Color::new(0xFF, 0x8A, 0x82, 0xFF),
144 },
145 minimize: Button {
146 fill: Color::new(0xFF, 0xBD, 0x2E, 0xFF),
147 hover: Color::new(0xFF, 0xD1, 0x66, 0xFF),
148 },
149 maximize: Button {
150 fill: Color::new(0x28, 0xC9, 0x40, 0xFF),
151 hover: Color::new(0x5E, 0xE0, 0x71, 0xFF),
152 },
153 },
154 noise_amplitude: 0.04,
155 shadow_extent: 24,
156 animation_duration_ms: 180,
157 }
158}
159
160#[must_use]
166pub fn glass_lite() -> Theme {
167 Theme {
168 name: "glass-lite".to_owned(),
169 noise_amplitude: 0.02,
170 shadow_extent: 12,
171 animation_duration_ms: 120,
172 ..glass_default()
173 }
174}
175
176#[must_use]
182pub fn glass_minimal() -> Theme {
183 let base = glass_default();
184 Theme {
185 name: "glass-minimal".to_owned(),
186 noise_amplitude: 0.0,
187 shadow_extent: 0,
188 animation_duration_ms: 0,
189 colors: Colors {
190 shadow: Color::default(),
191 ..base.colors
192 },
193 ..base
194 }
195}