Skip to main content

ribir_widgets/buttons/
outlined_button.rs

1use ribir_core::prelude::*;
2
3use super::{ButtonImpl, ButtonTemplate, ButtonType, IconPosition};
4
5#[derive(Clone)]
6pub struct OutlinedButtonStyle {
7  pub height: f32,
8  pub icon_size: Size,
9  pub label_gap: f32,
10  pub icon_pos: IconPosition,
11  pub label_style: CowArc<TextStyle>,
12  pub radius: f32,
13  pub padding_style: EdgeInsets,
14  pub border_width: f32,
15}
16
17impl CustomStyle for OutlinedButtonStyle {
18  fn default_style(ctx: &BuildCtx) -> Self {
19    OutlinedButtonStyle {
20      height: 40.,
21      icon_size: Size::splat(18.),
22      label_gap: 8.,
23      icon_pos: IconPosition::Before,
24      label_style: TypographyTheme::of(ctx).label_large.text.clone(),
25      radius: 20.,
26      padding_style: EdgeInsets::horizontal(16.),
27      border_width: 1.,
28    }
29  }
30}
31
32#[derive(Clone, Declare)]
33pub struct OutlinedButtonDecorator {
34  #[allow(unused)]
35  pub button_type: ButtonType,
36  pub color: Color,
37}
38
39impl ComposeDecorator for OutlinedButtonDecorator {
40  fn compose_decorator(_: State<Self>, host: Widget) -> impl WidgetBuilder { fn_widget!(host) }
41}
42
43/// OutlinedButton usage
44///
45/// # example
46/// ```
47/// # use ribir_core::prelude::*;
48/// # use ribir_widgets::prelude::{OutlinedButton, Label};
49///
50/// // only icon
51/// let outlined_icon_button = fn_widget! {
52///   @OutlinedButton { @{ svgs::ADD } }
53/// };
54///
55/// // only label
56/// let outlined_label_button = fn_widget! {
57///   @OutlinedButton { @{ Label::new("outlined button") } }
58/// };
59///
60/// // both icon and label
61/// let outlined_button = fn_widget! {
62///    @OutlinedButton {
63///     @ { svgs::ADD }
64///     @ { Label::new("outlined button")}
65///   }
66/// };
67///
68/// // use custom color
69/// let custom_color_button = fn_widget! {
70///   @OutlinedButton {
71///     color: Color::RED,
72///     @ { svgs::ADD }
73///     @ { Label::new("outlined button") }
74///   }
75/// };
76/// ```
77#[derive(Default, Declare)]
78pub struct OutlinedButton {
79  #[declare(default=Palette::of(ctx!()).primary())]
80  color: Color,
81}
82
83impl ComposeChild for OutlinedButton {
84  type Child = ButtonTemplate;
85
86  fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> impl WidgetBuilder {
87    let ButtonTemplate { icon, label } = &child;
88    let button_type = match (&icon, &label) {
89      (Some(_), Some(_)) => ButtonType::BOTH,
90      (Some(_), None) => ButtonType::ICON,
91      (None, Some(_)) => ButtonType::LABEL,
92      (None, None) => panic!("Button content cannot be empty!"),
93    };
94
95    fn_widget! {
96      @ {
97        let OutlinedButtonStyle {
98          height,
99          icon_size,
100          label_gap,
101          icon_pos,
102          label_style,
103          radius,
104          padding_style,
105          border_width,
106        } = OutlinedButtonStyle::of(ctx!());
107
108        @OutlinedButtonDecorator {
109          button_type,
110          color: pipe!($this.color),
111          @ButtonImpl {
112            height,
113            icon_size,
114            label_gap,
115            icon_pos,
116            label_style,
117            background_color: None,
118            foreground_color: pipe!(Palette::of(ctx!()).base_of(&$this.color)),
119            radius,
120            border_style: pipe!(Border::all(BorderSide {
121              width: border_width,
122              color: Palette::of(ctx!()).base_of(&$this.color).into()
123            })),
124            padding_style,
125
126            @ { child }
127          }
128        }
129      }
130    }
131  }
132}