1use std::vec::Vec;
2
3use azul_core::{
4 callbacks::{CoreCallbackData, Update},
5 dom::{Dom, IdOrClass, IdOrClass::Class, IdOrClassVec, NodeType, TabIndex},
6 refany::RefAny,
7 resources::{ImageRef, OptionImageRef},
8};
9use azul_css::{
10 dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec},
11 props::{
12 basic::{
13 color::{ColorU, ColorOrSystem, SystemColorRef},
14 font::{StyleFontFamily, StyleFontFamilyVec},
15 *,
16 },
17 layout::*,
18 property::{CssProperty, *},
19 style::*,
20 },
21 system::SystemFontType,
22 *,
23};
24
25use crate::callbacks::{Callback, CallbackInfo};
26
27#[repr(C)]
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
33pub enum ButtonType {
34 #[default]
36 Default,
37 Primary,
39 Secondary,
41 Success,
43 Danger,
45 Warning,
47 Info,
49 Link,
51}
52
53impl ButtonType {
54 pub fn class_name(&self) -> &'static str {
56 match self {
57 ButtonType::Default => "__azul-btn-default",
58 ButtonType::Primary => "__azul-btn-primary",
59 ButtonType::Secondary => "__azul-btn-secondary",
60 ButtonType::Success => "__azul-btn-success",
61 ButtonType::Danger => "__azul-btn-danger",
62 ButtonType::Warning => "__azul-btn-warning",
63 ButtonType::Info => "__azul-btn-info",
64 ButtonType::Link => "__azul-btn-link",
65 }
66 }
67}
68
69#[repr(C)]
70#[derive(Debug, Clone, PartialEq, PartialOrd)]
71pub struct Button {
72 pub label: AzString,
74 pub image: OptionImageRef,
76 pub button_type: ButtonType,
78 pub container_style: CssPropertyWithConditionsVec,
80 pub label_style: CssPropertyWithConditionsVec,
82 pub image_style: CssPropertyWithConditionsVec,
84 pub on_click: OptionButtonOnClick,
86}
87
88pub type ButtonOnClickCallbackType = extern "C" fn(RefAny, CallbackInfo) -> Update;
89impl_widget_callback!(
90 ButtonOnClick,
91 OptionButtonOnClick,
92 ButtonOnClickCallback,
93 ButtonOnClickCallbackType
94);
95
96const SANS_SERIF_STR: &str = "sans-serif";
97const SANS_SERIF: AzString = AzString::from_const_str(SANS_SERIF_STR);
98const SANS_SERIF_FAMILIES: &[StyleFontFamily] = &[StyleFontFamily::System(SANS_SERIF)];
99const SANS_SERIF_FAMILY: StyleFontFamilyVec =
100 StyleFontFamilyVec::from_const_slice(SANS_SERIF_FAMILIES);
101
102const HELVETICA_STR: &str = "Helvetica Neue";
104const HELVETICA: AzString = AzString::from_const_str(HELVETICA_STR);
105const MAC_FONT_FAMILIES: &[StyleFontFamily] = &[
106 StyleFontFamily::System(HELVETICA),
107 StyleFontFamily::System(SANS_SERIF),
108];
109const MAC_FONT_FAMILY: StyleFontFamilyVec = StyleFontFamilyVec::from_const_slice(MAC_FONT_FAMILIES);
110
111const RGB_172: ColorU = ColorU {
112 r: 172,
113 g: 172,
114 b: 172,
115 a: 255,
116};
117const RGB_239: ColorU = ColorU {
118 r: 239,
119 g: 239,
120 b: 239,
121 a: 255,
122};
123const RGB_229: ColorU = ColorU {
124 r: 229,
125 g: 229,
126 b: 229,
127 a: 255,
128};
129
130const WINDOWS_HOVER_START: ColorU = ColorU {
131 r: 234,
132 g: 243,
133 b: 252,
134 a: 255,
135};
136const WINDOWS_HOVER_END: ColorU = ColorU {
137 r: 126,
138 g: 180,
139 b: 234,
140 a: 255,
141};
142const WINDOWS_HOVER_BORDER: ColorU = ColorU {
143 r: 126,
144 g: 180,
145 b: 234,
146 a: 255,
147};
148
149const WINDOWS_ACTIVE_START: ColorU = ColorU {
150 r: 217,
151 g: 235,
152 b: 252,
153 a: 255,
154};
155const WINDOWS_ACTIVE_END: ColorU = ColorU {
156 r: 86,
157 g: 157,
158 b: 229,
159 a: 255,
160};
161const WINDOWS_ACTIVE_BORDER: ColorU = ColorU {
162 r: 86,
163 g: 157,
164 b: 229,
165 a: 255,
166};
167
168const WINDOWS_FOCUS_BORDER: ColorU = ColorU {
169 r: 51,
170 g: 153,
171 b: 255,
172 a: 255,
173};
174
175const BUTTON_NOMRAL_BACKGROUND_COLOR_STOPS: &[NormalizedLinearColorStop] = &[
176 NormalizedLinearColorStop {
177 offset: PercentageValue::const_new(0),
178 color: ColorOrSystem::color(RGB_239),
179 },
180 NormalizedLinearColorStop {
181 offset: PercentageValue::const_new(100),
182 color: ColorOrSystem::color(RGB_229),
183 },
184];
185const BUTTON_NORMAL_BACKGROUND: &[StyleBackgroundContent] =
187 &[StyleBackgroundContent::Color(RGB_229)];
188
189const BUTTON_HOVER_BACKGROUND_WINDOWS_COLOR_STOPS: &[NormalizedLinearColorStop] = &[
190 NormalizedLinearColorStop {
191 offset: PercentageValue::const_new(0),
192 color: ColorOrSystem::color(WINDOWS_HOVER_START),
193 },
194 NormalizedLinearColorStop {
195 offset: PercentageValue::const_new(100),
196 color: ColorOrSystem::color(WINDOWS_HOVER_END),
197 },
198];
199const BUTTON_HOVER_BACKGROUND_WINDOWS: &[StyleBackgroundContent] =
200 &[StyleBackgroundContent::LinearGradient(LinearGradient {
201 direction: Direction::FromTo(DirectionCorners {
202 dir_from: DirectionCorner::Top,
203 dir_to: DirectionCorner::Bottom,
204 }),
205 extend_mode: ExtendMode::Clamp,
206 stops: NormalizedLinearColorStopVec::from_const_slice(
207 BUTTON_HOVER_BACKGROUND_WINDOWS_COLOR_STOPS,
208 ),
209 })];
210const BUTTON_ACTIVE_BACKGROUND_WINDOWS_COLOR_STOPS: &[NormalizedLinearColorStop] = &[
211 NormalizedLinearColorStop {
212 offset: PercentageValue::const_new(0),
213 color: ColorOrSystem::color(WINDOWS_ACTIVE_START),
214 },
215 NormalizedLinearColorStop {
216 offset: PercentageValue::const_new(100),
217 color: ColorOrSystem::color(WINDOWS_ACTIVE_END),
218 },
219];
220const BUTTON_ACTIVE_BACKGROUND_WINDOWS: &[StyleBackgroundContent] =
221 &[StyleBackgroundContent::LinearGradient(LinearGradient {
222 direction: Direction::FromTo(DirectionCorners {
223 dir_from: DirectionCorner::Top,
224 dir_to: DirectionCorner::Bottom,
225 }),
226 extend_mode: ExtendMode::Clamp,
227 stops: NormalizedLinearColorStopVec::from_const_slice(
228 BUTTON_ACTIVE_BACKGROUND_WINDOWS_COLOR_STOPS,
229 ),
230 })];
231
232static BUTTON_CONTAINER_WINDOWS: &[CssPropertyWithConditions] = &[
233 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineFlex)),
235 CssPropertyWithConditions::simple(CssProperty::align_self(LayoutAlignSelf::Start)),
236 CssPropertyWithConditions::simple(CssProperty::const_background_content(
237 StyleBackgroundContentVec::from_const_slice(BUTTON_NORMAL_BACKGROUND),
238 )),
239 CssPropertyWithConditions::simple(CssProperty::const_flex_direction(
240 LayoutFlexDirection::Row,
241 )),
242 CssPropertyWithConditions::simple(CssProperty::const_justify_content(
243 LayoutJustifyContent::Center,
244 )),
245 CssPropertyWithConditions::simple(CssProperty::const_align_items(
246 LayoutAlignItems::Center,
247 )),
248 CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
249 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
250 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
252 LayoutBorderTopWidth::const_px(1),
253 )),
254 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
255 LayoutBorderBottomWidth::const_px(1),
256 )),
257 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
258 LayoutBorderLeftWidth::const_px(1),
259 )),
260 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
261 LayoutBorderRightWidth::const_px(1),
262 )),
263 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
264 inner: BorderStyle::Solid,
265 })),
266 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
267 StyleBorderBottomStyle {
268 inner: BorderStyle::Solid,
269 },
270 )),
271 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
272 inner: BorderStyle::Solid,
273 })),
274 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
275 StyleBorderRightStyle {
276 inner: BorderStyle::Solid,
277 },
278 )),
279 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
280 inner: RGB_172,
281 })),
282 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
283 StyleBorderBottomColor { inner: RGB_172 },
284 )),
285 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
286 inner: RGB_172,
287 })),
288 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
289 StyleBorderRightColor { inner: RGB_172 },
290 )),
291 CssPropertyWithConditions::simple(CssProperty::const_padding_left(
293 LayoutPaddingLeft::const_px(5),
294 )),
295 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
296 LayoutPaddingRight::const_px(5),
297 )),
298 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
299 3,
300 ))),
301 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
302 LayoutPaddingBottom::const_px(3),
303 )),
304 CssPropertyWithConditions::on_hover(CssProperty::const_background_content(
305 StyleBackgroundContentVec::from_const_slice(BUTTON_HOVER_BACKGROUND_WINDOWS),
306 )),
307 CssPropertyWithConditions::on_hover(CssProperty::const_border_top_color(StyleBorderTopColor {
308 inner: WINDOWS_HOVER_BORDER,
309 })),
310 CssPropertyWithConditions::on_hover(CssProperty::const_border_bottom_color(
311 StyleBorderBottomColor {
312 inner: WINDOWS_HOVER_BORDER,
313 },
314 )),
315 CssPropertyWithConditions::on_hover(CssProperty::const_border_left_color(
316 StyleBorderLeftColor {
317 inner: WINDOWS_HOVER_BORDER,
318 },
319 )),
320 CssPropertyWithConditions::on_hover(CssProperty::const_border_right_color(
321 StyleBorderRightColor {
322 inner: WINDOWS_HOVER_BORDER,
323 },
324 )),
325 CssPropertyWithConditions::on_active(CssProperty::const_background_content(
326 StyleBackgroundContentVec::from_const_slice(BUTTON_ACTIVE_BACKGROUND_WINDOWS),
327 )),
328 CssPropertyWithConditions::on_active(CssProperty::const_border_top_color(
329 StyleBorderTopColor {
330 inner: WINDOWS_ACTIVE_BORDER,
331 },
332 )),
333 CssPropertyWithConditions::on_active(CssProperty::const_border_bottom_color(
334 StyleBorderBottomColor {
335 inner: WINDOWS_ACTIVE_BORDER,
336 },
337 )),
338 CssPropertyWithConditions::on_active(CssProperty::const_border_left_color(
339 StyleBorderLeftColor {
340 inner: WINDOWS_ACTIVE_BORDER,
341 },
342 )),
343 CssPropertyWithConditions::on_active(CssProperty::const_border_right_color(
344 StyleBorderRightColor {
345 inner: WINDOWS_ACTIVE_BORDER,
346 },
347 )),
348 CssPropertyWithConditions::on_focus(CssProperty::const_border_top_color(StyleBorderTopColor {
349 inner: WINDOWS_FOCUS_BORDER,
350 })),
351 CssPropertyWithConditions::on_focus(CssProperty::const_border_bottom_color(
352 StyleBorderBottomColor {
353 inner: WINDOWS_FOCUS_BORDER,
354 },
355 )),
356 CssPropertyWithConditions::on_focus(CssProperty::const_border_left_color(
357 StyleBorderLeftColor {
358 inner: WINDOWS_FOCUS_BORDER,
359 },
360 )),
361 CssPropertyWithConditions::on_focus(CssProperty::const_border_right_color(
362 StyleBorderRightColor {
363 inner: WINDOWS_FOCUS_BORDER,
364 },
365 )),
366];
367
368const LINUX_NORMAL_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
370 NormalizedLinearColorStop {
371 offset: PercentageValue::const_new(0),
372 color: ColorOrSystem::color(ColorU {
373 r: 252,
374 g: 252,
375 b: 252,
376 a: 255,
377 }),
378 },
379 NormalizedLinearColorStop {
380 offset: PercentageValue::const_new(100),
381 color: ColorOrSystem::color(ColorU {
382 r: 239,
383 g: 239,
384 b: 239,
385 a: 255,
386 }),
387 },
388];
389const LINUX_NORMAL_BACKGROUND: &[StyleBackgroundContent] =
390 &[StyleBackgroundContent::LinearGradient(LinearGradient {
391 direction: Direction::FromTo(DirectionCorners {
392 dir_from: DirectionCorner::Top,
393 dir_to: DirectionCorner::Bottom,
394 }),
395 extend_mode: ExtendMode::Clamp,
396 stops: NormalizedLinearColorStopVec::from_const_slice(LINUX_NORMAL_GRADIENT_STOPS),
397 })];
398
399const LINUX_HOVER_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
400 NormalizedLinearColorStop {
401 offset: PercentageValue::const_new(0),
402 color: ColorOrSystem::color(ColorU {
403 r: 255,
404 g: 255,
405 b: 255,
406 a: 255,
407 }),
408 },
409 NormalizedLinearColorStop {
410 offset: PercentageValue::const_new(100),
411 color: ColorOrSystem::color(ColorU {
412 r: 245,
413 g: 245,
414 b: 245,
415 a: 255,
416 }),
417 },
418];
419const LINUX_HOVER_BACKGROUND: &[StyleBackgroundContent] =
420 &[StyleBackgroundContent::LinearGradient(LinearGradient {
421 direction: Direction::FromTo(DirectionCorners {
422 dir_from: DirectionCorner::Top,
423 dir_to: DirectionCorner::Bottom,
424 }),
425 extend_mode: ExtendMode::Clamp,
426 stops: NormalizedLinearColorStopVec::from_const_slice(LINUX_HOVER_GRADIENT_STOPS),
427 })];
428
429const LINUX_ACTIVE_GRADIENT_STOPS: &[NormalizedLinearColorStop] = &[
430 NormalizedLinearColorStop {
431 offset: PercentageValue::const_new(0),
432 color: ColorOrSystem::color(ColorU {
433 r: 220,
434 g: 220,
435 b: 220,
436 a: 255,
437 }),
438 },
439 NormalizedLinearColorStop {
440 offset: PercentageValue::const_new(100),
441 color: ColorOrSystem::color(ColorU {
442 r: 200,
443 g: 200,
444 b: 200,
445 a: 255,
446 }),
447 },
448];
449const LINUX_ACTIVE_BACKGROUND: &[StyleBackgroundContent] =
450 &[StyleBackgroundContent::LinearGradient(LinearGradient {
451 direction: Direction::FromTo(DirectionCorners {
452 dir_from: DirectionCorner::Top,
453 dir_to: DirectionCorner::Bottom,
454 }),
455 extend_mode: ExtendMode::Clamp,
456 stops: NormalizedLinearColorStopVec::from_const_slice(LINUX_ACTIVE_GRADIENT_STOPS),
457 })];
458
459const LINUX_BORDER_COLOR: ColorU = ColorU {
460 r: 183,
461 g: 183,
462 b: 183,
463 a: 255,
464};
465
466static BUTTON_CONTAINER_LINUX: &[CssPropertyWithConditions] = &[
467 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineFlex)),
469 CssPropertyWithConditions::simple(CssProperty::align_self(LayoutAlignSelf::Start)),
470 CssPropertyWithConditions::simple(CssProperty::const_flex_direction(
471 LayoutFlexDirection::Row,
472 )),
473 CssPropertyWithConditions::simple(CssProperty::const_justify_content(
474 LayoutJustifyContent::Center,
475 )),
476 CssPropertyWithConditions::simple(CssProperty::const_align_items(
477 LayoutAlignItems::Center,
478 )),
479 CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
480 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
481 CssPropertyWithConditions::simple(CssProperty::const_background_content(
483 StyleBackgroundContentVec::from_const_slice(LINUX_NORMAL_BACKGROUND),
484 )),
485 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
487 LayoutBorderTopWidth::const_px(1),
488 )),
489 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
490 LayoutBorderBottomWidth::const_px(1),
491 )),
492 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
493 LayoutBorderLeftWidth::const_px(1),
494 )),
495 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
496 LayoutBorderRightWidth::const_px(1),
497 )),
498 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
499 inner: BorderStyle::Solid,
500 })),
501 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
502 StyleBorderBottomStyle {
503 inner: BorderStyle::Solid,
504 },
505 )),
506 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
507 inner: BorderStyle::Solid,
508 })),
509 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
510 StyleBorderRightStyle {
511 inner: BorderStyle::Solid,
512 },
513 )),
514 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
515 inner: LINUX_BORDER_COLOR,
516 })),
517 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
518 StyleBorderBottomColor {
519 inner: LINUX_BORDER_COLOR,
520 },
521 )),
522 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
523 inner: LINUX_BORDER_COLOR,
524 })),
525 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
526 StyleBorderRightColor {
527 inner: LINUX_BORDER_COLOR,
528 },
529 )),
530 CssPropertyWithConditions::simple(CssProperty::const_border_top_left_radius(
532 StyleBorderTopLeftRadius::const_px(4),
533 )),
534 CssPropertyWithConditions::simple(CssProperty::const_border_top_right_radius(
535 StyleBorderTopRightRadius::const_px(4),
536 )),
537 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_left_radius(
538 StyleBorderBottomLeftRadius::const_px(4),
539 )),
540 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_right_radius(
541 StyleBorderBottomRightRadius::const_px(4),
542 )),
543 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
545 5,
546 ))),
547 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
548 LayoutPaddingBottom::const_px(5),
549 )),
550 CssPropertyWithConditions::simple(CssProperty::const_padding_left(
551 LayoutPaddingLeft::const_px(10),
552 )),
553 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
554 LayoutPaddingRight::const_px(10),
555 )),
556 CssPropertyWithConditions::on_hover(CssProperty::const_background_content(
558 StyleBackgroundContentVec::from_const_slice(LINUX_HOVER_BACKGROUND),
559 )),
560 CssPropertyWithConditions::on_active(CssProperty::const_background_content(
562 StyleBackgroundContentVec::from_const_slice(LINUX_ACTIVE_BACKGROUND),
563 )),
564];
565
566const MAC_NORMAL_BACKGROUND: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(ColorU {
569 r: 255,
570 g: 255,
571 b: 255,
572 a: 255,
573})];
574
575const MAC_HOVER_BACKGROUND: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(ColorU {
577 r: 250,
578 g: 250,
579 b: 250,
580 a: 255,
581})];
582
583const MAC_ACTIVE_BACKGROUND: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(ColorU {
585 r: 220,
586 g: 220,
587 b: 220,
588 a: 255,
589})];
590
591const MAC_BORDER_COLOR: ColorU = ColorU {
593 r: 200,
594 g: 200,
595 b: 200,
596 a: 255,
597};
598
599const MAC_BOX_SHADOW: &[StyleBoxShadow] = &[StyleBoxShadow {
601 offset_x: PixelValueNoPercent { inner: PixelValue::const_px(0) },
602 offset_y: PixelValueNoPercent { inner: PixelValue::const_px(1) },
603 color: ColorU { r: 0, g: 0, b: 0, a: 15 },
604 blur_radius: PixelValueNoPercent { inner: PixelValue::const_px(1) },
605 spread_radius: PixelValueNoPercent { inner: PixelValue::const_px(0) },
606 clip_mode: BoxShadowClipMode::Outset,
607}];
608
609static BUTTON_CONTAINER_MAC: &[CssPropertyWithConditions] = &[
610 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineFlex)),
612 CssPropertyWithConditions::simple(CssProperty::align_self(LayoutAlignSelf::Start)),
613 CssPropertyWithConditions::simple(CssProperty::const_flex_direction(
614 LayoutFlexDirection::Row,
615 )),
616 CssPropertyWithConditions::simple(CssProperty::const_justify_content(
617 LayoutJustifyContent::Center,
618 )),
619 CssPropertyWithConditions::simple(CssProperty::const_align_items(
620 LayoutAlignItems::Center,
621 )),
622 CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
623 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
624 CssPropertyWithConditions::simple(CssProperty::const_background_content(
626 StyleBackgroundContentVec::from_const_slice(MAC_NORMAL_BACKGROUND),
627 )),
628 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
630 LayoutBorderTopWidth::const_px(1),
631 )),
632 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
633 LayoutBorderBottomWidth::const_px(1),
634 )),
635 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
636 LayoutBorderLeftWidth::const_px(1),
637 )),
638 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
639 LayoutBorderRightWidth::const_px(1),
640 )),
641 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
642 inner: BorderStyle::Solid,
643 })),
644 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
645 StyleBorderBottomStyle {
646 inner: BorderStyle::Solid,
647 },
648 )),
649 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
650 inner: BorderStyle::Solid,
651 })),
652 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
653 StyleBorderRightStyle {
654 inner: BorderStyle::Solid,
655 },
656 )),
657 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
658 inner: MAC_BORDER_COLOR,
659 })),
660 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
661 StyleBorderBottomColor {
662 inner: MAC_BORDER_COLOR,
663 },
664 )),
665 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
666 inner: MAC_BORDER_COLOR,
667 })),
668 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
669 StyleBorderRightColor {
670 inner: MAC_BORDER_COLOR,
671 },
672 )),
673 CssPropertyWithConditions::simple(CssProperty::const_border_top_left_radius(
675 StyleBorderTopLeftRadius::const_px(4),
676 )),
677 CssPropertyWithConditions::simple(CssProperty::const_border_top_right_radius(
678 StyleBorderTopRightRadius::const_px(4),
679 )),
680 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_left_radius(
681 StyleBorderBottomLeftRadius::const_px(4),
682 )),
683 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_right_radius(
684 StyleBorderBottomRightRadius::const_px(4),
685 )),
686 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
688 5,
689 ))),
690 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
691 LayoutPaddingBottom::const_px(5),
692 )),
693 CssPropertyWithConditions::simple(CssProperty::const_padding_left(
694 LayoutPaddingLeft::const_px(10),
695 )),
696 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
697 LayoutPaddingRight::const_px(10),
698 )),
699 CssPropertyWithConditions::on_hover(CssProperty::const_background_content(
701 StyleBackgroundContentVec::from_const_slice(MAC_HOVER_BACKGROUND),
702 )),
703 CssPropertyWithConditions::on_active(CssProperty::const_background_content(
705 StyleBackgroundContentVec::from_const_slice(MAC_ACTIVE_BACKGROUND),
706 )),
707];
708
709static BUTTON_CONTAINER_OTHER: &[CssPropertyWithConditions] = &[];
710
711static BUTTON_LABEL_WINDOWS: &[CssPropertyWithConditions] = &[
712 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
713 CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Center)),
714 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
715 inner: ColorU::BLACK,
716 })),
717 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
718];
719
720static BUTTON_LABEL_LINUX: &[CssPropertyWithConditions] = &[
721 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(13))),
722 CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Center)),
723 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
724 inner: ColorU {
725 r: 76,
726 g: 76,
727 b: 76,
728 a: 255,
729 },
730 })),
731 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
732];
733
734static BUTTON_LABEL_MAC: &[CssPropertyWithConditions] = &[
735 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(13))),
736 CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Center)),
737 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
738 inner: ColorU {
739 r: 76,
740 g: 76,
741 b: 76,
742 a: 255,
743 },
744 })),
745 CssPropertyWithConditions::simple(CssProperty::const_font_family(MAC_FONT_FAMILY)),
746];
747
748static BUTTON_LABEL_OTHER: &[CssPropertyWithConditions] = &[];
749
750fn get_button_colors(button_type: ButtonType) -> (ColorU, ColorU, ColorU) {
756 match button_type {
758 ButtonType::Default => (
759 ColorU::rgb(248, 249, 250), ColorU::rgb(233, 236, 239), ColorU::rgb(218, 222, 226), ),
763 ButtonType::Primary => (
764 ColorU::bootstrap_primary(),
765 ColorU::bootstrap_primary_hover(),
766 ColorU::bootstrap_primary_active(),
767 ),
768 ButtonType::Secondary => (
769 ColorU::bootstrap_secondary(),
770 ColorU::bootstrap_secondary_hover(),
771 ColorU::bootstrap_secondary_active(),
772 ),
773 ButtonType::Success => (
774 ColorU::bootstrap_success(),
775 ColorU::bootstrap_success_hover(),
776 ColorU::bootstrap_success_active(),
777 ),
778 ButtonType::Danger => (
779 ColorU::bootstrap_danger(),
780 ColorU::bootstrap_danger_hover(),
781 ColorU::bootstrap_danger_active(),
782 ),
783 ButtonType::Warning => (
784 ColorU::bootstrap_warning(),
785 ColorU::bootstrap_warning_hover(),
786 ColorU::bootstrap_warning_active(),
787 ),
788 ButtonType::Info => (
789 ColorU::bootstrap_info(),
790 ColorU::bootstrap_info_hover(),
791 ColorU::bootstrap_info_active(),
792 ),
793 ButtonType::Link => (
794 ColorU::TRANSPARENT,
795 ColorU::TRANSPARENT,
796 ColorU::TRANSPARENT,
797 ),
798 }
799}
800
801fn get_button_text_color(button_type: ButtonType) -> ColorU {
803 match button_type {
804 ButtonType::Default => ColorU::rgb(33, 37, 41), ButtonType::Warning => ColorU::BLACK, ButtonType::Link => ColorU::bootstrap_link(), _ => ColorU::WHITE, }
809}
810
811fn build_button_container_style(button_type: ButtonType) -> Vec<CssPropertyWithConditions> {
813 let (bg_normal, bg_hover, bg_active) = get_button_colors(button_type);
814 let text_color = get_button_text_color(button_type);
815
816 let focus_outline_color = ColorU::bootstrap_primary();
818
819 let mut props = Vec::with_capacity(40);
820
821 props.push(CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineFlex)));
823 props.push(CssPropertyWithConditions::simple(CssProperty::const_flex_direction(LayoutFlexDirection::Row)));
824 props.push(CssPropertyWithConditions::simple(CssProperty::const_justify_content(LayoutJustifyContent::Center)));
825 props.push(CssPropertyWithConditions::simple(CssProperty::const_align_items(LayoutAlignItems::Center)));
826 props.push(CssPropertyWithConditions::simple(CssProperty::align_self(LayoutAlignSelf::Start)));
828 props.push(CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)));
829 props.push(CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))));
830
831 props.push(CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor { inner: text_color })));
833
834 props.push(CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(6))));
836 props.push(CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(LayoutPaddingBottom::const_px(6))));
837 props.push(CssPropertyWithConditions::simple(CssProperty::const_padding_left(LayoutPaddingLeft::const_px(12))));
838 props.push(CssPropertyWithConditions::simple(CssProperty::const_padding_right(LayoutPaddingRight::const_px(12))));
839
840 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_top_left_radius(StyleBorderTopLeftRadius::const_px(4))));
842 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_top_right_radius(StyleBorderTopRightRadius::const_px(4))));
843 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_bottom_left_radius(StyleBorderBottomLeftRadius::const_px(4))));
844 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_bottom_right_radius(StyleBorderBottomRightRadius::const_px(4))));
845
846 if button_type == ButtonType::Link {
847 props.push(CssPropertyWithConditions::simple(CssProperty::const_background_content(
849 StyleBackgroundContentVec::from_const_slice(&[StyleBackgroundContent::Color(ColorU::TRANSPARENT)]),
850 )));
851
852 props.push(CssPropertyWithConditions::on_hover(CssProperty::TextDecoration(StyleTextDecoration::Underline.into())));
854 } else {
855 props.push(CssPropertyWithConditions::simple(CssProperty::const_background_content(
857 StyleBackgroundContentVec::from_vec(vec![StyleBackgroundContent::Color(bg_normal)]),
858 )));
859
860 let border_color = if button_type == ButtonType::Default {
862 ColorU::rgb(206, 212, 218)
863 } else {
864 bg_normal
865 };
866 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_top_width(LayoutBorderTopWidth::const_px(1))));
867 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(LayoutBorderBottomWidth::const_px(1))));
868 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_left_width(LayoutBorderLeftWidth::const_px(1))));
869 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_right_width(LayoutBorderRightWidth::const_px(1))));
870 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle { inner: BorderStyle::Solid })));
871 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(StyleBorderBottomStyle { inner: BorderStyle::Solid })));
872 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle { inner: BorderStyle::Solid })));
873 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_right_style(StyleBorderRightStyle { inner: BorderStyle::Solid })));
874 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor { inner: border_color })));
875 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(StyleBorderBottomColor { inner: border_color })));
876 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor { inner: border_color })));
877 props.push(CssPropertyWithConditions::simple(CssProperty::const_border_right_color(StyleBorderRightColor { inner: border_color })));
878
879 props.push(CssPropertyWithConditions::on_hover(CssProperty::BackgroundContent(
881 StyleBackgroundContentVec::from_vec(vec![StyleBackgroundContent::Color(bg_hover)]).into(),
882 )));
883 if button_type == ButtonType::Default {
884 let hover_border = ColorU::rgb(173, 181, 189);
885 props.push(CssPropertyWithConditions::on_hover(CssProperty::BorderTopColor(StyleBorderTopColor { inner: hover_border }.into())));
886 props.push(CssPropertyWithConditions::on_hover(CssProperty::BorderBottomColor(StyleBorderBottomColor { inner: hover_border }.into())));
887 props.push(CssPropertyWithConditions::on_hover(CssProperty::BorderLeftColor(StyleBorderLeftColor { inner: hover_border }.into())));
888 props.push(CssPropertyWithConditions::on_hover(CssProperty::BorderRightColor(StyleBorderRightColor { inner: hover_border }.into())));
889 }
890
891 props.push(CssPropertyWithConditions::on_active(CssProperty::BackgroundContent(
893 StyleBackgroundContentVec::from_vec(vec![StyleBackgroundContent::Color(bg_active)]).into(),
894 )));
895
896 props.push(CssPropertyWithConditions::on_focus(CssProperty::BorderTopColor(StyleBorderTopColor { inner: focus_outline_color }.into())));
899 props.push(CssPropertyWithConditions::on_focus(CssProperty::BorderBottomColor(StyleBorderBottomColor { inner: focus_outline_color }.into())));
900 props.push(CssPropertyWithConditions::on_focus(CssProperty::BorderLeftColor(StyleBorderLeftColor { inner: focus_outline_color }.into())));
901 props.push(CssPropertyWithConditions::on_focus(CssProperty::BorderRightColor(StyleBorderRightColor { inner: focus_outline_color }.into())));
902 }
903
904 props
905}
906
907fn build_button_label_style() -> Vec<CssPropertyWithConditions> {
909 let font_family = StyleFontFamilyVec::from_vec(vec![
911 StyleFontFamily::SystemType(SystemFontType::Ui),
912 ]);
913
914 vec![
915 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(14))),
916 CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Center)),
917 CssPropertyWithConditions::simple(CssProperty::const_font_family(font_family)),
918 CssPropertyWithConditions::simple(CssProperty::user_select(StyleUserSelect::None)),
919 ]
920}
921
922impl Button {
923 #[inline]
924 pub fn create(label: AzString) -> Self {
925 Self::with_type(label, ButtonType::Default)
926 }
927
928 #[inline]
930 pub fn with_type(label: AzString, button_type: ButtonType) -> Self {
931 let container_style = build_button_container_style(button_type);
932 let label_style = build_button_label_style();
933
934 Self {
935 label,
936 image: None.into(),
937 button_type,
938 on_click: None.into(),
939 container_style: CssPropertyWithConditionsVec::from_vec(container_style),
940 label_style: CssPropertyWithConditionsVec::from_vec(label_style.clone()),
941 image_style: CssPropertyWithConditionsVec::from_vec(label_style),
942 }
943 }
944
945 #[inline]
947 pub fn set_button_type(&mut self, button_type: ButtonType) {
948 self.button_type = button_type;
949 self.container_style = CssPropertyWithConditionsVec::from_vec(build_button_container_style(button_type));
950 }
951
952 #[inline]
954 pub fn with_button_type(mut self, button_type: ButtonType) -> Self {
955 self.set_button_type(button_type);
956 self
957 }
958
959 #[inline(always)]
960 pub fn swap_with_default(&mut self) -> Self {
961 let mut m = Self::create(AzString::from_const_str(""));
962 core::mem::swap(&mut m, self);
963 m
964 }
965
966 #[inline]
967 pub fn set_image(&mut self, image: ImageRef) {
968 self.image = Some(image).into();
969 }
970
971 #[inline]
972 pub fn set_on_click<C: Into<ButtonOnClickCallback>>(&mut self, data: RefAny, on_click: C) {
973 self.on_click = Some(ButtonOnClick {
974 refany: data,
975 callback: on_click.into(),
976 })
977 .into();
978 }
979
980 #[inline]
981 pub fn with_on_click<C: Into<ButtonOnClickCallback>>(
982 mut self,
983 data: RefAny,
984 on_click: C,
985 ) -> Self {
986 self.set_on_click(data, on_click);
987 self
988 }
989
990 #[inline]
991 pub fn dom(self) -> Dom {
992 use azul_core::{
993 callbacks::{CoreCallback, CoreCallbackData},
994 dom::{EventFilter, HoverEventFilter},
995 };
996
997 let callbacks = match self.on_click.into_option() {
998 Some(ButtonOnClick {
999 refany: data,
1000 callback,
1001 }) => vec![CoreCallbackData {
1002 event: EventFilter::Hover(HoverEventFilter::MouseUp),
1003 callback: CoreCallback {
1004 cb: callback.cb as usize,
1005 ctx: callback.ctx,
1006 },
1007 refany: data,
1008 }],
1009 None => Vec::new(),
1010 };
1011
1012 let type_class = self.button_type.class_name();
1014 let classes: Vec<IdOrClass> = vec![
1015 Class(AzString::from_const_str("__azul-native-button")),
1016 Class(AzString::from_const_str(type_class)),
1017 ];
1018
1019 let label_dom = Dom::create_text(self.label)
1021 .with_css_props(self.label_style);
1022
1023 Dom::create_node(NodeType::Button)
1025 .with_child(label_dom)
1026 .with_ids_and_classes(IdOrClassVec::from_vec(classes))
1027 .with_css_props(self.container_style)
1028 .with_callbacks(callbacks.into())
1029 .with_tab_index(TabIndex::Auto)
1030 }
1031}