Skip to main content

iced_m3/style/
button.rs

1use crate::{
2    DIM_ALPHA, FOCUS_STATE_LAYER_OPACITY, PRESSED_STATE_LAYER_OPACITY, style::mix_colors,
3    theme::ColorScheme,
4};
5use iced::{Color, border::Radius};
6
7pub enum Button {
8    Primary,
9    InversePrimary,
10    Secondary,
11    InverseSecondary,
12    Tertiary,
13    InverseTertiary,
14    Outlined,
15    Error,
16}
17
18pub fn button(
19    status: iced_widget::button::Status,
20    theme: &impl ColorScheme,
21    style: Button,
22) -> iced_widget::button::Style {
23    let (color_regular, color_hovered, color_pressed, content_color, border_color) = match style {
24        Button::Primary => (
25            theme.primary(),
26            mix_colors(
27                theme.primary(),
28                theme.surface(),
29                1.0 - FOCUS_STATE_LAYER_OPACITY,
30            ),
31            mix_colors(
32                theme.primary(),
33                theme.surface(),
34                1.0 - PRESSED_STATE_LAYER_OPACITY,
35            ),
36            theme.on_primary(),
37            None,
38        ),
39        Button::InversePrimary => (
40            theme.on_primary(),
41            mix_colors(
42                theme.on_primary(),
43                theme.surface(),
44                1.0 - FOCUS_STATE_LAYER_OPACITY,
45            ),
46            mix_colors(
47                theme.on_primary(),
48                theme.surface(),
49                1.0 - PRESSED_STATE_LAYER_OPACITY,
50            ),
51            theme.primary(),
52            None,
53        ),
54        Button::Secondary => (
55            theme.secondary(),
56            mix_colors(
57                theme.secondary(),
58                theme.surface(),
59                1.0 - FOCUS_STATE_LAYER_OPACITY,
60            ),
61            mix_colors(
62                theme.secondary(),
63                theme.surface(),
64                1.0 - PRESSED_STATE_LAYER_OPACITY,
65            ),
66            theme.on_secondary(),
67            None,
68        ),
69        Button::InverseSecondary => (
70            theme.on_secondary(),
71            mix_colors(
72                theme.on_secondary(),
73                theme.surface(),
74                1.0 - FOCUS_STATE_LAYER_OPACITY,
75            ),
76            mix_colors(
77                theme.on_secondary(),
78                theme.surface(),
79                1.0 - PRESSED_STATE_LAYER_OPACITY,
80            ),
81            theme.secondary(),
82            None,
83        ),
84        Button::Tertiary => (
85            theme.tertiary(),
86            mix_colors(
87                theme.tertiary(),
88                theme.surface(),
89                1.0 - FOCUS_STATE_LAYER_OPACITY,
90            ),
91            mix_colors(
92                theme.tertiary(),
93                theme.surface(),
94                1.0 - PRESSED_STATE_LAYER_OPACITY,
95            ),
96            theme.on_tertiary(),
97            None,
98        ),
99        Button::InverseTertiary => (
100            theme.on_tertiary(),
101            mix_colors(
102                theme.on_tertiary(),
103                theme.surface(),
104                1.0 - FOCUS_STATE_LAYER_OPACITY,
105            ),
106            mix_colors(
107                theme.on_tertiary(),
108                theme.surface(),
109                1.0 - PRESSED_STATE_LAYER_OPACITY,
110            ),
111            theme.tertiary(),
112            None,
113        ),
114        Button::Outlined => (
115            Color::TRANSPARENT,
116            theme
117                .on_surface_variant()
118                .scale_alpha(FOCUS_STATE_LAYER_OPACITY),
119            theme
120                .on_surface_variant()
121                .scale_alpha(PRESSED_STATE_LAYER_OPACITY),
122            theme.on_surface_variant(),
123            Some(theme.on_surface_variant()),
124        ),
125        Button::Error => (
126            theme.error(),
127            mix_colors(
128                theme.error(),
129                theme.on_error(),
130                1.0 - FOCUS_STATE_LAYER_OPACITY,
131            ),
132            mix_colors(
133                theme.error(),
134                theme.on_error(),
135                1.0 - PRESSED_STATE_LAYER_OPACITY,
136            ),
137            theme.on_error(),
138            None,
139        ),
140    };
141    iced_widget::button::Style {
142        background: Some(iced::Background::Color(match status {
143            iced_widget::button::Status::Active => color_regular,
144            iced_widget::button::Status::Hovered => color_hovered,
145            iced_widget::button::Status::Pressed => color_pressed,
146            iced_widget::button::Status::Disabled => color_regular.scale_alpha(DIM_ALPHA),
147        })),
148        border: iced::Border {
149            radius: Radius::from(f32::MAX),
150            color: border_color
151                .map(|c| {
152                    if status == iced_widget::button::Status::Disabled {
153                        c.scale_alpha(DIM_ALPHA)
154                    } else {
155                        c
156                    }
157                })
158                .unwrap_or_default(),
159            width: if border_color.is_some() { 1.0 } else { 0.0 },
160        },
161        text_color: content_color,
162        ..Default::default()
163    }
164}