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