1use crate::prelude::MIN_FILE_DIALOG_SIZE;
2use crate::ui::prelude::*;
3use buffer_graphics_lib::prelude::Positioning::LeftTop;
4use buffer_graphics_lib::prelude::*;
5
6impl Default for UiStyle {
7 fn default() -> Self {
8 Self {
9 checkbox: Default::default(),
10 button: Default::default(),
11 text_field: Default::default(),
12 toggle_button: Default::default(),
13 alert: Default::default(),
14 dialog: DialogStyle::new_default_size(MIN_FILE_DIALOG_SIZE),
15 background: Color {
16 r: 30,
17 g: 30,
18 b: 140,
19 a: 255,
20 },
21 title_text: TextFormat::new(
22 WrappingStrategy::None,
23 PixelFont::Standard8x10,
24 WHITE,
25 LeftTop,
26 ),
27 body_text: TextFormat::new(
28 WrappingStrategy::None,
29 PixelFont::Standard6x7,
30 WHITE,
31 LeftTop,
32 ),
33 tooltip: Default::default(),
34 icon_button: Default::default(),
35 toggle_icon_button: Default::default(),
36 menu: MenuBarStyle::default(),
37 }
38 }
39}
40
41impl Default for ButtonStyle {
42 fn default() -> Self {
43 Self {
44 text: ColorSet::new_values(WHITE, WHITE, WHITE, LIGHT_GRAY),
45 font: PixelFont::Standard6x7,
46 border: ColorSet::new_values(LIGHT_GRAY, CYAN, RED, DARK_GRAY),
47 shadow: ColorSet::new_same(DARK_GRAY),
48 rounding: 2,
49 }
50 }
51}
52
53impl Default for ToggleButtonStyle {
54 fn default() -> Self {
55 Self {
56 text: ToggleColorSet::new_same(WHITE),
57 font: PixelFont::Standard6x7,
58 border: ToggleColorSet::new_values(LIGHT_GRAY, CYAN, WHITE, CYAN, RED, DARK_GRAY),
59 shadow: ToggleColorSet::new_values(
60 DARK_GRAY, DARK_GRAY, WHITE, WHITE, DARK_GRAY, DARK_GRAY,
61 ),
62 rounding: 6,
63 }
64 }
65}
66
67impl Default for TextFieldStyle {
68 fn default() -> Self {
69 Self {
70 text_color: FocusColorSet::new_values(BLACK, BLACK, BLACK, RED, DARK_GRAY),
71 background_color: FocusColorSet::new_same(WHITE),
72 border_color: FocusColorSet::new_values(DARK_GRAY, DARK_GRAY, CYAN, RED, LIGHT_GRAY),
73 cursor: FocusColorSet::new_same(BLACK),
74 }
75 }
76}
77
78impl Default for AlertStyle {
79 fn default() -> Self {
80 Self {
81 background: Some(Color {
82 r: 20,
83 g: 20,
84 b: 120,
85 a: 255,
86 }),
87 text: WHITE,
88 warning_text: RED,
89 font: PixelFont::Standard6x7,
90 button: ButtonStyle::default(),
91 border: Some(LIGHT_GRAY),
92 shadow: Some(DARK_GRAY),
93 shade: Some(Color::new(0, 0, 0, 127)),
94 }
95 }
96}
97
98impl DialogStyle {
99 pub fn new_default_size(size: (usize, usize)) -> Self {
100 let bounds = Rect::new_with_size((0, 0), size.0, size.1);
101 Self::new_default(bounds.translate_by(Coord::from(size) / 2))
102 }
103
104 pub fn new_default(bounds: Rect) -> Self {
105 Self::new(
106 bounds,
107 Some(Color {
108 r: 30,
109 g: 30,
110 b: 140,
111 a: 255,
112 }),
113 WHITE,
114 Some(LIGHT_GRAY),
115 Some(DARK_GRAY),
116 Some(Color {
117 r: 0,
118 g: 0,
119 b: 0,
120 a: 150,
121 }),
122 )
123 }
124
125 #[allow(clippy::too_many_arguments)]
126 pub fn new(
127 bounds: Rect,
128 background: Option<Color>,
129 text: Color,
130 border: Option<Color>,
131 shadow: Option<Color>,
132 shade: Option<Color>,
133 ) -> Self {
134 Self {
135 bounds,
136 background,
137 text,
138 border,
139 shadow,
140 shade,
141 }
142 }
143}
144
145impl Default for TooltipStyle {
146 fn default() -> Self {
147 Self {
148 text: ColorSet::new_same(WHITE),
149 background: ColorSet::new_same(BLACK),
150 border: ColorSet::new_same(LIGHT_GRAY),
151 shadow: ColorSet::new_same(DARK_GRAY),
152 font: PixelFont::Standard4x5,
153 padding: 2,
154 }
155 }
156}
157
158impl Default for IconButtonStyle {
159 fn default() -> Self {
160 Self {
161 tooltip: TooltipStyle::default(),
162 border: ColorSet::new_values(LIGHT_GRAY, CYAN, RED, DARK_GRAY),
163 shadow: ColorSet::new_same(DARK_GRAY),
164 rounding: 2,
165 padding: 4,
166 }
167 }
168}
169
170impl Default for ToggleIconButtonStyle {
171 fn default() -> Self {
172 Self {
173 tooltip: TooltipStyle::default(),
174 border: ToggleColorSet::new_values(LIGHT_GRAY, CYAN, WHITE, CYAN, RED, DARK_GRAY),
175 shadow: ToggleColorSet::new_values(
176 DARK_GRAY, DARK_GRAY, WHITE, WHITE, DARK_GRAY, DARK_GRAY,
177 ),
178 rounding: 6,
179 padding: 4,
180 }
181 }
182}
183
184impl Default for MenuBarStyle {
185 fn default() -> Self {
186 Self {
187 background: ColorSet::new_same(BLUE.with_saturate(0.8)),
188 border: ColorSet::new_same(WHITE),
189 menu_item: MenuItemStyle::default(),
190 dropdown_item: DropdownItemStyle::default(),
191 }
192 }
193}
194
195impl Default for MenuItemStyle {
196 fn default() -> Self {
197 Self {
198 background: FocusColorSet::menu(BLUE.with_saturate(0.8), TRANSPARENT, TRANSPARENT),
199 text: FocusColorSet::new_values(OFF_WHITE, WHITE, WHITE, LIGHT_GRAY, MID_GRAY),
200 font: Default::default(),
201 dropdown_background: Some(BLUE.with_saturate(0.8)),
202 padding: Padding::new(2, 2, 2, 1),
203 }
204 }
205}
206
207impl Default for DropdownItemStyle {
208 fn default() -> Self {
209 Self {
210 background: FocusColorSet::menu(BLUE.with_saturate(0.8), TRANSPARENT, TRANSPARENT),
211 text: FocusColorSet::new_values(OFF_WHITE, WHITE, WHITE, LIGHT_GRAY, MID_GRAY),
212 font: PixelFont::default(),
213 arrow: DropdownItemStyle::dropdown_arrow_for_font(
214 PixelFont::default(),
215 FocusColorSet::new_values(OFF_WHITE, LIGHT_GRAY, WHITE, LIGHT_GRAY, MID_GRAY),
216 ),
217 padding: Padding::new(2, 2, 2, 1),
218 }
219 }
220}
221
222impl DropdownItemStyle {
223 fn dropdown_arrow_for_font(font: PixelFont, colors: FocusColorSet) -> IconSet {
224 let mut buffer = Graphics::create_buffer_u8(font.size().0, font.size().1);
225 let mut graphics = Graphics::new_u8_rgba(&mut buffer, font.size().0, font.size().1)
226 .unwrap_or_else(|err| {
227 panic!(
228 "Unable to create graphics using {font:?} when generating menu arrow: {err:?}"
229 )
230 });
231
232 graphics.draw_triangle(
233 Triangle::right_angle(
234 (0, 0),
235 font.size().0.min(font.size().1),
236 AnglePosition::Right,
237 )
238 .move_center_to(coord!(font.size().0 / 2, font.size().1 / 2)),
239 fill(WHITE),
240 );
241 let icon = graphics
242 .copy_to_indexed_image(false)
243 .unwrap_or_else(|err| panic!("Unable to create menu arrow icon: {err:?}"));
244
245 let idx = icon.get_palette().iter().position(|c| c == &WHITE).unwrap_or_else(|| panic!("Unable to find color in menubar arrow, please raise an issue on Github emmabritton/pixel-graphics-lib"));
246
247 let recolor = |image: &IndexedImage, color: Color| {
248 let mut img = image.clone();
249 img.set_color_unchecked(idx as u8, color);
250 img
251 };
252
253 IconSet {
254 normal: Some(recolor(&icon, colors.normal.unwrap_or(WHITE))),
255 focused: Some(recolor(
256 &icon,
257 colors.focused.unwrap_or(colors.normal.unwrap_or(WHITE)),
258 )),
259 hover: Some(recolor(
260 &icon,
261 colors.hover.unwrap_or(colors.normal.unwrap_or(WHITE)),
262 )),
263 error: Some(recolor(
264 &icon,
265 colors.error.unwrap_or(colors.disabled.unwrap_or(MID_GRAY)),
266 )),
267 disabled: Some(recolor(
268 &icon,
269 colors.disabled.unwrap_or(colors.error.unwrap_or(MID_GRAY)),
270 )),
271 }
272 }
273}
274
275impl Default for CheckboxStyle {
276 fn default() -> Self {
277 let [checked_icon, check_box] = CheckboxStyle::icons();
278
279 CheckboxStyle {
280 checked_icon,
281 check_box,
282 text: ColorSet::new_values(WHITE, WHITE, WHITE, LIGHT_GRAY),
283 icon: ColorSet::new_values(WHITE, WHITE, WHITE, LIGHT_GRAY),
284 font: PixelFont::Standard6x7,
285 spacing: 4,
286 }
287 }
288}
289
290impl CheckboxStyle {
291 fn icons() -> [IndexedImage; 2] {
292 let size = 9;
293 let mut box_buffer = Graphics::create_buffer_u8(size, size);
294 let mut check_buffer = Graphics::create_buffer_u8(size, size);
295 let mut box_graphics = Graphics::new_u8_rgba(&mut box_buffer, size, size).unwrap();
296 let mut check_graphics = Graphics::new_u8_rgba(&mut check_buffer, size, size).unwrap();
297 box_graphics.draw_rect(Rect::new((0, 0), (size - 1, size - 1)), stroke(WHITE));
298 check_graphics.draw_line((1, 4), (3, 5), WHITE);
299 check_graphics.draw_line((1, 4), (3, 6), WHITE);
300 check_graphics.draw_line((1, 5), (3, 7), WHITE);
301 check_graphics.draw_line((3, 5), (7, 1), WHITE);
302 check_graphics.draw_line((3, 6), (8, 1), WHITE);
303 check_graphics.draw_line((3, 7), (8, 2), WHITE);
304 [
305 check_graphics.copy_to_indexed_image(false).unwrap(),
306 box_graphics.copy_to_indexed_image(false).unwrap(),
307 ]
308 }
309}