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
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 theme_cow = MacTheme::resolve(self.theme, ui.ctx());
93 let theme: &MacTheme = &theme_cow;
94
95 let metrics = &theme.button().regular;
96 let height = self.height.unwrap_or_else(|| metrics.height.points());
97 let corner_radius = self
98 .corner_radius
99 .unwrap_or_else(|| metrics.corner_radius.points());
100 let padding_h = metrics
101 .padding_horizontal
102 .as_ref()
103 .map(|d| d.points())
104 .unwrap_or_else(|| metrics.font_size.points());
105
106 let font_id = egui::FontId::proportional(metrics.font_size.points());
107 let text_layout =
108 ui.painter()
109 .layout_no_wrap(self.text.to_owned(), font_id, Color32::PLACEHOLDER);
110 let desired_width = self
111 .width
112 .unwrap_or_else(|| text_layout.size().x + padding_h * 2.0);
113
114 let sense = if self.enabled {
115 egui::Sense::click()
116 } else {
117 egui::Sense::hover()
118 };
119 let (rect, response) = ui.allocate_exact_size(Vec2::new(desired_width, height), sense);
120 let painter = ui.painter_at(rect);
121
122 let alpha_factor = if self.enabled {
123 1.0
124 } else {
125 theme.disabled_opacity()
126 };
127
128 let base_bg = if !self.enabled {
130 if self.selected {
131 theme.selected_control_inactive()
132 } else {
133 theme.control_background()
134 }
135 } else if response.is_pointer_button_down_on() {
136 theme.selected_control_inactive()
137 } else if self.selected {
138 theme.selected_control()
139 } else if response.hovered() {
140 theme.control()
141 } else {
142 theme.control_background()
143 };
144 let bg_color = base_bg.gamma_multiply(alpha_factor);
145
146 let border_stroke = Stroke::new(
147 metrics.border_width.points(),
148 theme.separator().gamma_multiply(alpha_factor),
149 );
150
151 painter.rect(
152 rect,
153 CornerRadius::same(corner_radius as u8),
154 bg_color,
155 border_stroke,
156 StrokeKind::Inside,
157 );
158
159 let bg_style = theme.background_style(base_bg);
160 let text_color = bg_style
161 .primary_text_color(theme)
162 .gamma_multiply(alpha_factor);
163
164 let text_pos = egui::Align2::CENTER_CENTER
165 .anchor_size(rect.center(), text_layout.size())
166 .min;
167 painter.galley(text_pos, text_layout, text_color);
168
169 response
170 }
171}