material_egui/widgets/
button.rs1use egui::{Align2, Color32, FontId, Id, LayerId, Order, Response, Stroke, Ui};
2use crate::MaterialColors;
3#[derive(Clone, Default, Debug)]
4pub struct Button {
5 style: MaterialColors
6}
7impl Button {
8 pub fn new(style: &MaterialColors) -> Self {
9 Self {
10 style: style.clone(),
11 }
12 }
13 pub fn elevated(&self, ui: &mut Ui, text: impl Into<String>) -> Response {
15 Self::m3_button(
16 ui,
17 text,
18 self.style.surface_container_low,
19 self.style.primary,
20 Self::stroke_null(),
21 )
22 }
23 pub fn filled(&self, ui: &mut Ui, text: impl Into<String>) -> Response {
24 Self::m3_button(
25 ui,
26 text,
27 self.style.primary,
28 self.style.on_primary,
29 Self::stroke_null(),
30 )
31 }
32 pub fn filled_tonal(&self, ui: &mut Ui, text: impl Into<String>) -> Response {
33 Self::m3_button(
34 ui,
35 text,
36 self.style.primary_container,
37 self.style.on_primary_container,
38 Self::stroke_null(),
39 )
40 }
41 pub fn outlined(&self, ui: &mut Ui, text: impl Into<String>) -> Response {
42 Self::m3_button(
43 ui,
44 text,
45 self.style.surface,
46 self.style.primary,
47 Stroke {
48 width: 1.5,
49 color: self.style.outline,
50 },
51 )
52 }
53
54 fn m3_button(
55 ui: &mut egui::Ui,
56 text: impl Into<String>,
57 container_style: Color32,
58 text_style: Color32,
59 stroke: Stroke,
60 ) -> egui::Response {
61 let text = text.into().replace('\n', "");
62
63 let scale = 1.5;
65
66 let desired_size = ui.spacing().interact_size.y * egui::vec2(scale * 2., scale);
67 let (mut rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
68
69 let mut container_style = container_style;
71 if response.hovered() {
72 container_style = Self::delta(container_style, 10);
73 };
74
75 let mut width = 0.;
76 let mut height = 0.;
77 let mut position = rect.left_center();
78 position.x += 10.;
79
80 ui.with_layer_id(
81 LayerId {
82 order: Order::Foreground,
83 id: Id::new("foreground"),
84 },
85 |ui| {
86 let ui = ui.painter().text(
87 position,
88 Align2::LEFT_CENTER,
89 text,
90 FontId::proportional(rect.width() / 4.5),
91 text_style,
92 );
93 width = ui.width();
94 height = ui.height();
95 },
96 );
97
98 let radius = 0.5 * rect.height();
100 rect.set_width(width + 20.);
101
102 ui.with_layer_id(LayerId::background(), |ui| {
103 ui.painter().rect(rect, radius, container_style, stroke);
104 });
105
106 response
107 }
108
109
110 fn stroke_null() -> Stroke {
111 Stroke {
112 width: 0.0,
113 color: Default::default(),
114 }
115 }
116
117 fn delta(i: Color32, change: u8) -> Color32 {
119 let f = change;
120 let (mut r, mut g, mut b, a) = (i.r(), i.g(), i.b(), i.a());
121 if (r as u32 + g as u32 + b as u32) > 384 {
122 r -= f;
123 g -= f;
124 b -= f;
125 } else {
126 r += f;
127 g += f;
128 b += f;
129 }
130 Color32::from_rgba_premultiplied(r, g, b, a)
131 }
132}