pixels_graphics_lib/ui/styles/
defaults.rs

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}