egui_macview/controls/
button_cell.rs1use crate::theme::MacTheme;
7use egui::{Color32, CornerRadius, Response, Stroke, StrokeKind, Ui, Vec2, Widget};
8
9pub struct MacButtonCell<'a> {
30 text: &'a str,
31 selected: bool,
32 enabled: bool,
33 theme: Option<&'a MacTheme>,
34 width: Option<f32>,
35 height: Option<f32>,
36 corner_radius: Option<f32>,
37}
38
39pub type MacButton<'a> = MacButtonCell<'a>;
41
42impl<'a> MacButtonCell<'a> {
43 pub fn new(text: &'a str) -> Self {
45 Self {
46 text,
47 selected: false,
48 enabled: true,
49 theme: None,
50 width: None,
51 height: None,
52 corner_radius: None,
53 }
54 }
55
56 pub fn enabled(mut self, enabled: bool) -> Self {
58 self.enabled = enabled;
59 self
60 }
61
62 pub fn theme(mut self, theme: &'a MacTheme) -> Self {
64 self.theme = Some(theme);
65 self
66 }
67
68 pub fn selected(mut self, selected: bool) -> Self {
70 self.selected = selected;
71 self
72 }
73
74 pub fn width(mut self, width: f32) -> Self {
76 self.width = Some(width);
77 self
78 }
79
80 pub fn height(mut self, height: f32) -> Self {
82 self.height = Some(height);
83 self
84 }
85
86 pub fn corner_radius(mut self, r: f32) -> Self {
88 self.corner_radius = Some(r);
89 self
90 }
91}
92
93impl<'a> Widget for MacButtonCell<'a> {
94 fn ui(self, ui: &mut Ui) -> Response {
95 let theme_cow = MacTheme::resolve(self.theme, ui.ctx());
96 let theme: &MacTheme = &theme_cow;
97
98 let metrics = &theme.button().regular;
99 let height = self.height.unwrap_or_else(|| metrics.height.points());
100 let corner_radius = self
101 .corner_radius
102 .unwrap_or_else(|| metrics.corner_radius.points());
103 let padding_h = metrics
104 .padding_horizontal
105 .as_ref()
106 .map(|d| d.points())
107 .unwrap_or_else(|| metrics.font_size.points());
108
109 let font_id = egui::FontId::proportional(metrics.font_size.points());
110 let text_layout = theme.layout_tracked_galley(
111 ui,
112 self.text,
113 font_id,
114 Color32::PLACEHOLDER,
115 f32::INFINITY,
116 );
117 let desired_width = self
118 .width
119 .unwrap_or_else(|| text_layout.size().x + padding_h * 2.0);
120
121 let enabled = self.enabled && ui.is_enabled();
122 let sense = if enabled {
123 egui::Sense::click()
124 } else {
125 egui::Sense::hover()
126 };
127 let (rect, response) = ui.allocate_exact_size(Vec2::new(desired_width, height), sense);
128 let painter = ui.painter_at(rect);
129
130 let alpha_factor = if enabled {
131 1.0
132 } else {
133 theme.disabled_opacity()
134 };
135
136 let base_bg = if !enabled {
138 if self.selected {
139 theme.selected_control_inactive()
140 } else {
141 theme.control_background()
142 }
143 } else if response.is_pointer_button_down_on() {
144 theme.selected_control_inactive()
145 } else if self.selected {
146 theme.selected_control()
147 } else if response.hovered() {
148 theme.control()
149 } else {
150 theme.control_background()
151 };
152 let bg_color = base_bg.gamma_multiply(alpha_factor);
153
154 let border_stroke = Stroke::new(
155 metrics.border_width.points(),
156 theme.separator().gamma_multiply(alpha_factor),
157 );
158
159 painter.rect(
160 rect,
161 CornerRadius::same(corner_radius as u8),
162 bg_color,
163 border_stroke,
164 StrokeKind::Inside,
165 );
166
167 let bg_style = theme.background_style(base_bg);
168 let text_color = bg_style
169 .primary_text_color(theme)
170 .gamma_multiply(alpha_factor);
171
172 let text_pos = egui::Align2::CENTER_CENTER
173 .anchor_size(rect.center(), text_layout.size())
174 .min;
175 painter.galley(text_pos, text_layout, text_color);
176
177 response
178 }
179}