egui_cha_ds/atoms/core/
button.rs1use egui::{Color32, Response, RichText, Stroke, Ui, Widget};
4use egui_cha::ViewCtx;
5
6use crate::Theme;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum ButtonVariant {
11 #[default]
12 Primary,
13 Secondary,
14 Outline,
15 Ghost,
16 Danger,
17 Warning,
18 Success,
19 Info,
20}
21
22#[derive(Clone)]
24pub struct Button<'a> {
25 label: &'a str,
26 variant: ButtonVariant,
27 disabled: bool,
28 icon: Option<&'a str>,
29}
30
31impl<'a> Button<'a> {
32 pub fn new(label: &'a str) -> Self {
34 Self {
35 label,
36 variant: ButtonVariant::Primary,
37 disabled: false,
38 icon: None,
39 }
40 }
41
42 pub fn primary(label: &'a str) -> Self {
44 Self::new(label).variant(ButtonVariant::Primary)
45 }
46
47 pub fn secondary(label: &'a str) -> Self {
49 Self::new(label).variant(ButtonVariant::Secondary)
50 }
51
52 pub fn outline(label: &'a str) -> Self {
54 Self::new(label).variant(ButtonVariant::Outline)
55 }
56
57 pub fn ghost(label: &'a str) -> Self {
59 Self::new(label).variant(ButtonVariant::Ghost)
60 }
61
62 pub fn danger(label: &'a str) -> Self {
64 Self::new(label).variant(ButtonVariant::Danger)
65 }
66
67 pub fn warning(label: &'a str) -> Self {
69 Self::new(label).variant(ButtonVariant::Warning)
70 }
71
72 pub fn success(label: &'a str) -> Self {
74 Self::new(label).variant(ButtonVariant::Success)
75 }
76
77 pub fn info(label: &'a str) -> Self {
79 Self::new(label).variant(ButtonVariant::Info)
80 }
81
82 pub fn variant(mut self, variant: ButtonVariant) -> Self {
84 self.variant = variant;
85 self
86 }
87
88 pub fn disabled(mut self, disabled: bool) -> Self {
90 self.disabled = disabled;
91 self
92 }
93
94 pub fn icon(mut self, icon: &'a str) -> Self {
96 self.icon = Some(icon);
97 self
98 }
99
100 pub fn on_click<Msg>(self, ctx: &mut ViewCtx<'_, Msg>, msg: Msg) -> bool {
102 let clicked = self.show(ctx.ui);
103 if clicked {
104 ctx.emit(msg);
105 }
106 clicked
107 }
108
109 pub fn show(self, ui: &mut Ui) -> bool {
111 let text = match self.icon {
112 Some(icon) => format!("{} {}", icon, self.label),
113 None => self.label.to_string(),
114 };
115
116 let theme = Theme::current(ui.ctx());
117 let (fill, text_color, stroke) = self.variant_style(&theme);
118
119 let rich_text = RichText::new(text).color(text_color);
120 let mut button = egui::Button::new(rich_text).fill(fill);
121
122 if let Some(s) = stroke {
123 button = button.stroke(s);
124 }
125
126 let response = ui.add_enabled(!self.disabled, button);
127 response.clicked()
128 }
129
130 fn variant_style(&self, theme: &Theme) -> (Color32, Color32, Option<Stroke>) {
132 match self.variant {
133 ButtonVariant::Primary => (theme.primary, theme.primary_text, None),
134 ButtonVariant::Secondary => (theme.secondary, theme.secondary_text, None),
135 ButtonVariant::Outline => (
136 Color32::TRANSPARENT,
137 theme.text_primary,
138 Some(Stroke::new(1.0, theme.border)),
139 ),
140 ButtonVariant::Ghost => (Color32::TRANSPARENT, theme.text_secondary, None),
141 ButtonVariant::Danger => (theme.state_danger, theme.state_danger_text, None),
142 ButtonVariant::Warning => (theme.state_warning, theme.state_warning_text, None),
143 ButtonVariant::Success => (theme.state_success, theme.state_success_text, None),
144 ButtonVariant::Info => (theme.state_info, theme.state_info_text, None),
145 }
146 }
147}
148
149impl<'a> Widget for Button<'a> {
150 fn ui(self, ui: &mut Ui) -> Response {
151 let text = match self.icon {
152 Some(icon) => format!("{} {}", icon, self.label),
153 None => self.label.to_string(),
154 };
155
156 let theme = Theme::current(ui.ctx());
157 let (fill, text_color, stroke) = self.variant_style(&theme);
158
159 let rich_text = RichText::new(text).color(text_color);
160 let mut button = egui::Button::new(rich_text).fill(fill);
161
162 if let Some(s) = stroke {
163 button = button.stroke(s);
164 }
165
166 ui.add_enabled(!self.disabled, button)
167 }
168}