use egui::{Color32, Response, RichText, Stroke, Ui, Widget};
use egui_cha::ViewCtx;
use crate::Theme;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ButtonVariant {
#[default]
Primary,
Secondary,
Outline,
Ghost,
Danger,
Warning,
Success,
Info,
}
#[derive(Clone)]
pub struct Button<'a> {
label: &'a str,
variant: ButtonVariant,
disabled: bool,
icon: Option<&'a str>,
}
impl<'a> Button<'a> {
pub fn new(label: &'a str) -> Self {
Self {
label,
variant: ButtonVariant::Primary,
disabled: false,
icon: None,
}
}
pub fn primary(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Primary)
}
pub fn secondary(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Secondary)
}
pub fn outline(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Outline)
}
pub fn ghost(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Ghost)
}
pub fn danger(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Danger)
}
pub fn warning(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Warning)
}
pub fn success(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Success)
}
pub fn info(label: &'a str) -> Self {
Self::new(label).variant(ButtonVariant::Info)
}
pub fn variant(mut self, variant: ButtonVariant) -> Self {
self.variant = variant;
self
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub fn icon(mut self, icon: &'a str) -> Self {
self.icon = Some(icon);
self
}
pub fn on_click<Msg>(self, ctx: &mut ViewCtx<'_, Msg>, msg: Msg) -> bool {
let clicked = self.show(ctx.ui);
if clicked {
ctx.emit(msg);
}
clicked
}
pub fn show(self, ui: &mut Ui) -> bool {
let text = match self.icon {
Some(icon) => format!("{} {}", icon, self.label),
None => self.label.to_string(),
};
let theme = Theme::current(ui.ctx());
let (fill, text_color, stroke) = self.variant_style(&theme);
let rich_text = RichText::new(text).color(text_color);
let mut button = egui::Button::new(rich_text).fill(fill);
if let Some(s) = stroke {
button = button.stroke(s);
}
let response = ui.add_enabled(!self.disabled, button);
response.clicked()
}
fn variant_style(&self, theme: &Theme) -> (Color32, Color32, Option<Stroke>) {
match self.variant {
ButtonVariant::Primary => (theme.primary, theme.primary_text, None),
ButtonVariant::Secondary => (theme.secondary, theme.secondary_text, None),
ButtonVariant::Outline => (
Color32::TRANSPARENT,
theme.text_primary,
Some(Stroke::new(1.0, theme.border)),
),
ButtonVariant::Ghost => (Color32::TRANSPARENT, theme.text_secondary, None),
ButtonVariant::Danger => (theme.state_danger, theme.state_danger_text, None),
ButtonVariant::Warning => (theme.state_warning, theme.state_warning_text, None),
ButtonVariant::Success => (theme.state_success, theme.state_success_text, None),
ButtonVariant::Info => (theme.state_info, theme.state_info_text, None),
}
}
}
impl<'a> Widget for Button<'a> {
fn ui(self, ui: &mut Ui) -> Response {
let text = match self.icon {
Some(icon) => format!("{} {}", icon, self.label),
None => self.label.to_string(),
};
let theme = Theme::current(ui.ctx());
let (fill, text_color, stroke) = self.variant_style(&theme);
let rich_text = RichText::new(text).color(text_color);
let mut button = egui::Button::new(rich_text).fill(fill);
if let Some(s) = stroke {
button = button.stroke(s);
}
ui.add_enabled(!self.disabled, button)
}
}