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