Skip to main content

azul_layout/widgets/
button.rs

1use std::vec::Vec;
2
3use azul_core::{
4    callbacks::{CoreCallbackData, Update},
5    dom::{Dom, IdOrClass, IdOrClass::Class, IdOrClassVec, TabIndex},
6    refany::RefAny,
7    resources::{ImageRef, OptionImageRef},
8};
9use azul_css::{
10    dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec},
11    props::{
12        basic::{
13            color::ColorU,
14            font::{StyleFontFamily, StyleFontFamilyVec},
15            *,
16        },
17        layout::*,
18        property::{CssProperty, *},
19        style::*,
20    },
21    *,
22};
23
24use crate::callbacks::{Callback, CallbackInfo};
25
26#[repr(C)]
27#[derive(Debug, Clone, PartialEq, PartialOrd)]
28pub struct Button {
29    /// Content (image or text) of this button, centered by default
30    pub label: AzString,
31    /// Optional image that is displayed next to the label
32    pub image: OptionImageRef,
33    /// Style for this button container
34    pub container_style: CssPropertyWithConditionsVec,
35    /// Style of the label
36    pub label_style: CssPropertyWithConditionsVec,
37    /// Style of the image
38    pub image_style: CssPropertyWithConditionsVec,
39    /// Optional: Function to call when the button is clicked
40    pub on_click: OptionButtonOnClick,
41}
42
43pub type ButtonOnClickCallbackType = extern "C" fn(RefAny, CallbackInfo) -> Update;
44impl_widget_callback!(
45    ButtonOnClick,
46    OptionButtonOnClick,
47    ButtonOnClickCallback,
48    ButtonOnClickCallbackType
49);
50
51const SANS_SERIF_STR: &str = "sans-serif";
52const SANS_SERIF: AzString = AzString::from_const_str(SANS_SERIF_STR);
53const SANS_SERIF_FAMILIES: &[StyleFontFamily] = &[StyleFontFamily::System(SANS_SERIF)];
54const SANS_SERIF_FAMILY: StyleFontFamilyVec =
55    StyleFontFamilyVec::from_const_slice(SANS_SERIF_FAMILIES);
56
57// macOS: Helvetica with sans-serif fallback
58const HELVETICA_STR: &str = "Helvetica Neue";
59const HELVETICA: AzString = AzString::from_const_str(HELVETICA_STR);
60const MAC_FONT_FAMILIES: &[StyleFontFamily] = &[
61    StyleFontFamily::System(HELVETICA),
62    StyleFontFamily::System(SANS_SERIF),
63];
64const MAC_FONT_FAMILY: StyleFontFamilyVec = StyleFontFamilyVec::from_const_slice(MAC_FONT_FAMILIES);
65
66const RGB_172: ColorU = ColorU {
67    r: 172,
68    g: 172,
69    b: 172,
70    a: 255,
71};
72const RGB_239: ColorU = ColorU {
73    r: 239,
74    g: 239,
75    b: 239,
76    a: 255,
77};
78const RGB_229: ColorU = ColorU {
79    r: 229,
80    g: 229,
81    b: 229,
82    a: 255,
83};
84
85const WINDOWS_HOVER_START: ColorU = ColorU {
86    r: 234,
87    g: 243,
88    b: 252,
89    a: 255,
90};
91const WINDOWS_HOVER_END: ColorU = ColorU {
92    r: 126,
93    g: 180,
94    b: 234,
95    a: 255,
96};
97const WINDOWS_HOVER_BORDER: ColorU = ColorU {
98    r: 126,
99    g: 180,
100    b: 234,
101    a: 255,
102};
103
104const WINDOWS_ACTIVE_START: ColorU = ColorU {
105    r: 217,
106    g: 235,
107    b: 252,
108    a: 255,
109};
110const WINDOWS_ACTIVE_END: ColorU = ColorU {
111    r: 86,
112    g: 157,
113    b: 229,
114    a: 255,
115};
116const WINDOWS_ACTIVE_BORDER: ColorU = ColorU {
117    r: 86,
118    g: 157,
119    b: 229,
120    a: 255,
121};
122
123const WINDOWS_FOCUS_BORDER: ColorU = ColorU {
124    r: 51,
125    g: 153,
126    b: 255,
127    a: 255,
128};
129
130const BUTTON_NOMRAL_BACKGROUND_COLOR_STOPS: &[NormalizedLinearColorStop] = &[
131    NormalizedLinearColorStop {
132        offset: PercentageValue::const_new(0),
133        color: RGB_239,
134    },
135    NormalizedLinearColorStop {
136        offset: PercentageValue::const_new(100),
137        color: RGB_229,
138    },
139];
140// Temporarily use simple color for testing inline rendering
141const BUTTON_NORMAL_BACKGROUND: &[StyleBackgroundContent] =
142    &[StyleBackgroundContent::Color(RGB_229)];
143
144const BUTTON_HOVER_BACKGROUND_WINDOWS_COLOR_STOPS: &[NormalizedLinearColorStop] = &[
145    NormalizedLinearColorStop {
146        offset: PercentageValue::const_new(0),
147        color: WINDOWS_HOVER_START,
148    },
149    NormalizedLinearColorStop {
150        offset: PercentageValue::const_new(100),
151        color: WINDOWS_HOVER_END,
152    },
153];
154const BUTTON_HOVER_BACKGROUND_WINDOWS: &[StyleBackgroundContent] =
155    &[StyleBackgroundContent::LinearGradient(LinearGradient {
156        direction: Direction::FromTo(DirectionCorners {
157            dir_from: DirectionCorner::Top,
158            dir_to: DirectionCorner::Bottom,
159        }),
160        extend_mode: ExtendMode::Clamp,
161        stops: NormalizedLinearColorStopVec::from_const_slice(
162            BUTTON_HOVER_BACKGROUND_WINDOWS_COLOR_STOPS,
163        ),
164    })];
165const BUTTON_ACTIVE_BACKGROUND_WINDOWS_COLOR_STOPS: &[NormalizedLinearColorStop] = &[
166    NormalizedLinearColorStop {
167        offset: PercentageValue::const_new(0),
168        color: WINDOWS_ACTIVE_START,
169    },
170    NormalizedLinearColorStop {
171        offset: PercentageValue::const_new(100),
172        color: WINDOWS_ACTIVE_END,
173    },
174];
175const BUTTON_ACTIVE_BACKGROUND_WINDOWS: &[StyleBackgroundContent] =
176    &[StyleBackgroundContent::LinearGradient(LinearGradient {
177        direction: Direction::FromTo(DirectionCorners {
178            dir_from: DirectionCorner::Top,
179            dir_to: DirectionCorner::Bottom,
180        }),
181        extend_mode: ExtendMode::Clamp,
182        stops: NormalizedLinearColorStopVec::from_const_slice(
183            BUTTON_ACTIVE_BACKGROUND_WINDOWS_COLOR_STOPS,
184        ),
185    })];
186
187static BUTTON_CONTAINER_WINDOWS: &[CssPropertyWithConditions] = &[
188    CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineBlock)),
189    CssPropertyWithConditions::simple(CssProperty::const_background_content(
190        StyleBackgroundContentVec::from_const_slice(BUTTON_NORMAL_BACKGROUND),
191    )),
192    CssPropertyWithConditions::simple(CssProperty::const_flex_direction(
193        LayoutFlexDirection::Column,
194    )),
195    CssPropertyWithConditions::simple(CssProperty::const_justify_content(
196        LayoutJustifyContent::Center,
197    )),
198    CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
199    CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
200    //     border: 1px solid rgb(172, 172, 172);
201    CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
202        LayoutBorderTopWidth::const_px(1),
203    )),
204    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
205        LayoutBorderBottomWidth::const_px(1),
206    )),
207    CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
208        LayoutBorderLeftWidth::const_px(1),
209    )),
210    CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
211        LayoutBorderRightWidth::const_px(1),
212    )),
213    CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
214        inner: BorderStyle::Solid,
215    })),
216    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
217        StyleBorderBottomStyle {
218            inner: BorderStyle::Solid,
219        },
220    )),
221    CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
222        inner: BorderStyle::Solid,
223    })),
224    CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
225        StyleBorderRightStyle {
226            inner: BorderStyle::Solid,
227        },
228    )),
229    CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
230        inner: RGB_172,
231    })),
232    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
233        StyleBorderBottomColor { inner: RGB_172 },
234    )),
235    CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
236        inner: RGB_172,
237    })),
238    CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
239        StyleBorderRightColor { inner: RGB_172 },
240    )),
241    // padding: 5px
242    CssPropertyWithConditions::simple(CssProperty::const_padding_left(
243        LayoutPaddingLeft::const_px(5),
244    )),
245    CssPropertyWithConditions::simple(CssProperty::const_padding_right(
246        LayoutPaddingRight::const_px(5),
247    )),
248    CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
249        3,
250    ))),
251    CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
252        LayoutPaddingBottom::const_px(3),
253    )),
254    CssPropertyWithConditions::on_hover(CssProperty::const_background_content(
255        StyleBackgroundContentVec::from_const_slice(BUTTON_HOVER_BACKGROUND_WINDOWS),
256    )),
257    CssPropertyWithConditions::on_hover(CssProperty::const_border_top_color(StyleBorderTopColor {
258        inner: WINDOWS_HOVER_BORDER,
259    })),
260    CssPropertyWithConditions::on_hover(CssProperty::const_border_bottom_color(
261        StyleBorderBottomColor {
262            inner: WINDOWS_HOVER_BORDER,
263        },
264    )),
265    CssPropertyWithConditions::on_hover(CssProperty::const_border_left_color(
266        StyleBorderLeftColor {
267            inner: WINDOWS_HOVER_BORDER,
268        },
269    )),
270    CssPropertyWithConditions::on_hover(CssProperty::const_border_right_color(
271        StyleBorderRightColor {
272            inner: WINDOWS_HOVER_BORDER,
273        },
274    )),
275    CssPropertyWithConditions::on_active(CssProperty::const_background_content(
276        StyleBackgroundContentVec::from_const_slice(BUTTON_ACTIVE_BACKGROUND_WINDOWS),
277    )),
278    CssPropertyWithConditions::on_active(CssProperty::const_border_top_color(
279        StyleBorderTopColor {
280            inner: WINDOWS_ACTIVE_BORDER,
281        },
282    )),
283    CssPropertyWithConditions::on_active(CssProperty::const_border_bottom_color(
284        StyleBorderBottomColor {
285            inner: WINDOWS_ACTIVE_BORDER,
286        },
287    )),
288    CssPropertyWithConditions::on_active(CssProperty::const_border_left_color(
289        StyleBorderLeftColor {
290            inner: WINDOWS_ACTIVE_BORDER,
291        },
292    )),
293    CssPropertyWithConditions::on_active(CssProperty::const_border_right_color(
294        StyleBorderRightColor {
295            inner: WINDOWS_ACTIVE_BORDER,
296        },
297    )),
298    CssPropertyWithConditions::on_focus(CssProperty::const_border_top_color(StyleBorderTopColor {
299        inner: WINDOWS_FOCUS_BORDER,
300    })),
301    CssPropertyWithConditions::on_focus(CssProperty::const_border_bottom_color(
302        StyleBorderBottomColor {
303            inner: WINDOWS_FOCUS_BORDER,
304        },
305    )),
306    CssPropertyWithConditions::on_focus(CssProperty::const_border_left_color(
307        StyleBorderLeftColor {
308            inner: WINDOWS_FOCUS_BORDER,
309        },
310    )),
311    CssPropertyWithConditions::on_focus(CssProperty::const_border_right_color(
312        StyleBorderRightColor {
313            inner: WINDOWS_FOCUS_BORDER,
314        },
315    )),
316];
317
318// Linux button background gradients
319const LINUX_NORMAL_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
320    NormalizedLinearColorStop {
321        offset: PercentageValue::const_new(0),
322        color: ColorU {
323            r: 252,
324            g: 252,
325            b: 252,
326            a: 255,
327        },
328    },
329    NormalizedLinearColorStop {
330        offset: PercentageValue::const_new(100),
331        color: ColorU {
332            r: 239,
333            g: 239,
334            b: 239,
335            a: 255,
336        },
337    },
338];
339const LINUX_NORMAL_BACKGROUND: &[StyleBackgroundContent] =
340    &[StyleBackgroundContent::LinearGradient(LinearGradient {
341        direction: Direction::FromTo(DirectionCorners {
342            dir_from: DirectionCorner::Top,
343            dir_to: DirectionCorner::Bottom,
344        }),
345        extend_mode: ExtendMode::Clamp,
346        stops: NormalizedLinearColorStopVec::from_const_slice(LINUX_NORMAL_GRADIENT_STOPS),
347    })];
348
349const LINUX_HOVER_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
350    NormalizedLinearColorStop {
351        offset: PercentageValue::const_new(0),
352        color: ColorU {
353            r: 255,
354            g: 255,
355            b: 255,
356            a: 255,
357        },
358    },
359    NormalizedLinearColorStop {
360        offset: PercentageValue::const_new(100),
361        color: ColorU {
362            r: 245,
363            g: 245,
364            b: 245,
365            a: 255,
366        },
367    },
368];
369const LINUX_HOVER_BACKGROUND: &[StyleBackgroundContent] =
370    &[StyleBackgroundContent::LinearGradient(LinearGradient {
371        direction: Direction::FromTo(DirectionCorners {
372            dir_from: DirectionCorner::Top,
373            dir_to: DirectionCorner::Bottom,
374        }),
375        extend_mode: ExtendMode::Clamp,
376        stops: NormalizedLinearColorStopVec::from_const_slice(LINUX_HOVER_GRADIENT_STOPS),
377    })];
378
379const LINUX_ACTIVE_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
380    NormalizedLinearColorStop {
381        offset: PercentageValue::const_new(0),
382        color: ColorU {
383            r: 220,
384            g: 220,
385            b: 220,
386            a: 255,
387        },
388    },
389    NormalizedLinearColorStop {
390        offset: PercentageValue::const_new(100),
391        color: ColorU {
392            r: 200,
393            g: 200,
394            b: 200,
395            a: 255,
396        },
397    },
398];
399const LINUX_ACTIVE_BACKGROUND: &[StyleBackgroundContent] =
400    &[StyleBackgroundContent::LinearGradient(LinearGradient {
401        direction: Direction::FromTo(DirectionCorners {
402            dir_from: DirectionCorner::Top,
403            dir_to: DirectionCorner::Bottom,
404        }),
405        extend_mode: ExtendMode::Clamp,
406        stops: NormalizedLinearColorStopVec::from_const_slice(LINUX_ACTIVE_GRADIENT_STOPS),
407    })];
408
409const LINUX_BORDER_COLOR: ColorU = ColorU {
410    r: 183,
411    g: 183,
412    b: 183,
413    a: 255,
414};
415
416static BUTTON_CONTAINER_LINUX: &[CssPropertyWithConditions] = &[
417    // Linux/GTK-style button styling
418    CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineBlock)),
419    CssPropertyWithConditions::simple(CssProperty::const_flex_direction(
420        LayoutFlexDirection::Column,
421    )),
422    CssPropertyWithConditions::simple(CssProperty::const_justify_content(
423        LayoutJustifyContent::Center,
424    )),
425    CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
426    CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
427    // background: linear-gradient(#fcfcfc, #efefef)
428    CssPropertyWithConditions::simple(CssProperty::const_background_content(
429        StyleBackgroundContentVec::from_const_slice(LINUX_NORMAL_BACKGROUND),
430    )),
431    // border: 1px solid #b7b7b7
432    CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
433        LayoutBorderTopWidth::const_px(1),
434    )),
435    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
436        LayoutBorderBottomWidth::const_px(1),
437    )),
438    CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
439        LayoutBorderLeftWidth::const_px(1),
440    )),
441    CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
442        LayoutBorderRightWidth::const_px(1),
443    )),
444    CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
445        inner: BorderStyle::Solid,
446    })),
447    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
448        StyleBorderBottomStyle {
449            inner: BorderStyle::Solid,
450        },
451    )),
452    CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
453        inner: BorderStyle::Solid,
454    })),
455    CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
456        StyleBorderRightStyle {
457            inner: BorderStyle::Solid,
458        },
459    )),
460    CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
461        inner: LINUX_BORDER_COLOR,
462    })),
463    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
464        StyleBorderBottomColor {
465            inner: LINUX_BORDER_COLOR,
466        },
467    )),
468    CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
469        inner: LINUX_BORDER_COLOR,
470    })),
471    CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
472        StyleBorderRightColor {
473            inner: LINUX_BORDER_COLOR,
474        },
475    )),
476    // border-radius: 4px
477    CssPropertyWithConditions::simple(CssProperty::const_border_top_left_radius(
478        StyleBorderTopLeftRadius::const_px(4),
479    )),
480    CssPropertyWithConditions::simple(CssProperty::const_border_top_right_radius(
481        StyleBorderTopRightRadius::const_px(4),
482    )),
483    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_left_radius(
484        StyleBorderBottomLeftRadius::const_px(4),
485    )),
486    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_right_radius(
487        StyleBorderBottomRightRadius::const_px(4),
488    )),
489    // padding: 5px 10px
490    CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
491        5,
492    ))),
493    CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
494        LayoutPaddingBottom::const_px(5),
495    )),
496    CssPropertyWithConditions::simple(CssProperty::const_padding_left(
497        LayoutPaddingLeft::const_px(10),
498    )),
499    CssPropertyWithConditions::simple(CssProperty::const_padding_right(
500        LayoutPaddingRight::const_px(10),
501    )),
502    // Hover state
503    CssPropertyWithConditions::on_hover(CssProperty::const_background_content(
504        StyleBackgroundContentVec::from_const_slice(LINUX_HOVER_BACKGROUND),
505    )),
506    // Active state
507    CssPropertyWithConditions::on_active(CssProperty::const_background_content(
508        StyleBackgroundContentVec::from_const_slice(LINUX_ACTIVE_BACKGROUND),
509    )),
510];
511
512// macOS button background gradients
513const MAC_NORMAL_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
514    NormalizedLinearColorStop {
515        offset: PercentageValue::const_new(0),
516        color: ColorU {
517            r: 252,
518            g: 252,
519            b: 252,
520            a: 255,
521        },
522    },
523    NormalizedLinearColorStop {
524        offset: PercentageValue::const_new(100),
525        color: ColorU {
526            r: 239,
527            g: 239,
528            b: 239,
529            a: 255,
530        },
531    },
532];
533// Temporarily use simple color for testing inline rendering on macOS
534const MAC_NORMAL_BACKGROUND: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(ColorU {
535    r: 239,
536    g: 239,
537    b: 239,
538    a: 255,
539})];
540
541const MAC_HOVER_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
542    NormalizedLinearColorStop {
543        offset: PercentageValue::const_new(0),
544        color: ColorU {
545            r: 255,
546            g: 255,
547            b: 255,
548            a: 255,
549        },
550    },
551    NormalizedLinearColorStop {
552        offset: PercentageValue::const_new(100),
553        color: ColorU {
554            r: 245,
555            g: 245,
556            b: 245,
557            a: 255,
558        },
559    },
560];
561const MAC_HOVER_BACKGROUND: &[StyleBackgroundContent] =
562    &[StyleBackgroundContent::LinearGradient(LinearGradient {
563        direction: Direction::FromTo(DirectionCorners {
564            dir_from: DirectionCorner::Top,
565            dir_to: DirectionCorner::Bottom,
566        }),
567        extend_mode: ExtendMode::Clamp,
568        stops: NormalizedLinearColorStopVec::from_const_slice(MAC_HOVER_GRADIENT_STOPS),
569    })];
570
571const MAC_ACTIVE_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
572    NormalizedLinearColorStop {
573        offset: PercentageValue::const_new(0),
574        color: ColorU {
575            r: 220,
576            g: 220,
577            b: 220,
578            a: 255,
579        },
580    },
581    NormalizedLinearColorStop {
582        offset: PercentageValue::const_new(100),
583        color: ColorU {
584            r: 200,
585            g: 200,
586            b: 200,
587            a: 255,
588        },
589    },
590];
591const MAC_ACTIVE_BACKGROUND: &[StyleBackgroundContent] =
592    &[StyleBackgroundContent::LinearGradient(LinearGradient {
593        direction: Direction::FromTo(DirectionCorners {
594            dir_from: DirectionCorner::Top,
595            dir_to: DirectionCorner::Bottom,
596        }),
597        extend_mode: ExtendMode::Clamp,
598        stops: NormalizedLinearColorStopVec::from_const_slice(MAC_ACTIVE_GRADIENT_STOPS),
599    })];
600
601const MAC_BORDER_COLOR: ColorU = ColorU {
602    r: 183,
603    g: 183,
604    b: 183,
605    a: 255,
606};
607
608static BUTTON_CONTAINER_MAC: &[CssPropertyWithConditions] = &[
609    // macOS native button styling
610    CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineBlock)),
611    CssPropertyWithConditions::simple(CssProperty::const_flex_direction(
612        LayoutFlexDirection::Column,
613    )),
614    CssPropertyWithConditions::simple(CssProperty::const_justify_content(
615        LayoutJustifyContent::Center,
616    )),
617    CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
618    CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
619    // background: linear-gradient(#fcfcfc, #efefef)
620    CssPropertyWithConditions::simple(CssProperty::const_background_content(
621        StyleBackgroundContentVec::from_const_slice(MAC_NORMAL_BACKGROUND),
622    )),
623    // border: 1px solid #b7b7b7
624    CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
625        LayoutBorderTopWidth::const_px(1),
626    )),
627    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
628        LayoutBorderBottomWidth::const_px(1),
629    )),
630    CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
631        LayoutBorderLeftWidth::const_px(1),
632    )),
633    CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
634        LayoutBorderRightWidth::const_px(1),
635    )),
636    CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
637        inner: BorderStyle::Solid,
638    })),
639    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
640        StyleBorderBottomStyle {
641            inner: BorderStyle::Solid,
642        },
643    )),
644    CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
645        inner: BorderStyle::Solid,
646    })),
647    CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
648        StyleBorderRightStyle {
649            inner: BorderStyle::Solid,
650        },
651    )),
652    CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
653        inner: MAC_BORDER_COLOR,
654    })),
655    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
656        StyleBorderBottomColor {
657            inner: MAC_BORDER_COLOR,
658        },
659    )),
660    CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
661        inner: MAC_BORDER_COLOR,
662    })),
663    CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
664        StyleBorderRightColor {
665            inner: MAC_BORDER_COLOR,
666        },
667    )),
668    // border-radius: 4px
669    CssPropertyWithConditions::simple(CssProperty::const_border_top_left_radius(
670        StyleBorderTopLeftRadius::const_px(4),
671    )),
672    CssPropertyWithConditions::simple(CssProperty::const_border_top_right_radius(
673        StyleBorderTopRightRadius::const_px(4),
674    )),
675    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_left_radius(
676        StyleBorderBottomLeftRadius::const_px(4),
677    )),
678    CssPropertyWithConditions::simple(CssProperty::const_border_bottom_right_radius(
679        StyleBorderBottomRightRadius::const_px(4),
680    )),
681    // padding: 5px 10px
682    CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
683        5,
684    ))),
685    CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
686        LayoutPaddingBottom::const_px(5),
687    )),
688    CssPropertyWithConditions::simple(CssProperty::const_padding_left(
689        LayoutPaddingLeft::const_px(10),
690    )),
691    CssPropertyWithConditions::simple(CssProperty::const_padding_right(
692        LayoutPaddingRight::const_px(10),
693    )),
694    // Hover state
695    CssPropertyWithConditions::on_hover(CssProperty::const_background_content(
696        StyleBackgroundContentVec::from_const_slice(MAC_HOVER_BACKGROUND),
697    )),
698    // Active state
699    CssPropertyWithConditions::on_active(CssProperty::const_background_content(
700        StyleBackgroundContentVec::from_const_slice(MAC_ACTIVE_BACKGROUND),
701    )),
702];
703
704static BUTTON_CONTAINER_OTHER: &[CssPropertyWithConditions] = &[];
705
706static BUTTON_LABEL_WINDOWS: &[CssPropertyWithConditions] = &[
707    CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
708    CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Center)),
709    CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
710        inner: ColorU::BLACK,
711    })),
712    CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
713];
714
715static BUTTON_LABEL_LINUX: &[CssPropertyWithConditions] = &[
716    CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(13))),
717    CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Center)),
718    CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
719        inner: ColorU {
720            r: 76,
721            g: 76,
722            b: 76,
723            a: 255,
724        },
725    })),
726    CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
727];
728
729static BUTTON_LABEL_MAC: &[CssPropertyWithConditions] = &[
730    CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(13))),
731    CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Center)),
732    CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
733        inner: ColorU {
734            r: 76,
735            g: 76,
736            b: 76,
737            a: 255,
738        },
739    })),
740    CssPropertyWithConditions::simple(CssProperty::const_font_family(MAC_FONT_FAMILY)),
741];
742
743static BUTTON_LABEL_OTHER: &[CssPropertyWithConditions] = &[];
744
745impl Button {
746    #[inline]
747    pub fn create(label: AzString) -> Self {
748        Self {
749            label,
750            image: None.into(),
751            on_click: None.into(),
752
753            #[cfg(target_os = "windows")]
754            container_style: CssPropertyWithConditionsVec::from_const_slice(
755                BUTTON_CONTAINER_WINDOWS,
756            ),
757            #[cfg(target_os = "linux")]
758            container_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_CONTAINER_LINUX),
759            #[cfg(target_os = "macos")]
760            container_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_CONTAINER_MAC),
761            #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
762            container_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_CONTAINER_OTHER),
763
764            #[cfg(target_os = "windows")]
765            label_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_WINDOWS),
766            #[cfg(target_os = "linux")]
767            label_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_LINUX),
768            #[cfg(target_os = "macos")]
769            label_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_MAC),
770            #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
771            label_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_OTHER),
772
773            #[cfg(target_os = "windows")]
774            image_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_WINDOWS),
775            #[cfg(target_os = "linux")]
776            image_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_LINUX),
777            #[cfg(target_os = "macos")]
778            image_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_MAC),
779            #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
780            image_style: CssPropertyWithConditionsVec::from_const_slice(BUTTON_LABEL_OTHER),
781        }
782    }
783
784    #[inline(always)]
785    pub fn swap_with_default(&mut self) -> Self {
786        let mut m = Self::create(AzString::from_const_str(""));
787        core::mem::swap(&mut m, self);
788        m
789    }
790
791    #[inline]
792    pub fn set_image(&mut self, image: ImageRef) {
793        self.image = Some(image).into();
794    }
795
796    #[inline]
797    pub fn set_on_click<C: Into<ButtonOnClickCallback>>(&mut self, data: RefAny, on_click: C) {
798        self.on_click = Some(ButtonOnClick {
799            refany: data,
800            callback: on_click.into(),
801        })
802        .into();
803    }
804
805    #[inline]
806    pub fn with_on_click<C: Into<ButtonOnClickCallback>>(
807        mut self,
808        data: RefAny,
809        on_click: C,
810    ) -> Self {
811        self.set_on_click(data, on_click);
812        self
813    }
814
815    #[inline]
816    pub fn dom(self) -> Dom {
817        use azul_core::{
818            callbacks::{CoreCallback, CoreCallbackData},
819            dom::{EventFilter, HoverEventFilter},
820        };
821
822        let callbacks = match self.on_click.into_option() {
823            Some(ButtonOnClick {
824                refany: data,
825                callback,
826            }) => vec![CoreCallbackData {
827                event: EventFilter::Hover(HoverEventFilter::MouseUp),
828                callback: CoreCallback {
829                    cb: callback.cb as usize,
830                    ctx: callback.ctx,
831                },
832                refany: data,
833            }],
834            None => Vec::new(),
835        };
836
837        static BUTTON_CLASS: &[IdOrClass] =
838            &[Class(AzString::from_const_str("__azul-native-button"))];
839
840        Dom::create_button(self.label)
841            .with_ids_and_classes(IdOrClassVec::from_const_slice(BUTTON_CLASS))
842            .with_css_props(self.container_style)
843            .with_callbacks(callbacks.into())
844            .with_tab_index(TabIndex::Auto)
845    }
846}