Skip to main content

egui_charts/ui_kit/buttons/
mod.rs

1//! Icon buttons, split buttons and button styling helpers.
2//!
3//! Use [`IconButton`] for an individual action and [`SplitButton`] for an action
4//! with a separate dropdown trigger.
5
6use crate::localization as l10n;
7mod button;
8mod icon_button;
9mod split_button;
10mod variant;
11
12pub use button::{Button, ButtonExt};
13pub use icon_button::IconButton;
14pub use split_button::SplitButton;
15pub use variant::ButtonVariant;
16
17use crate::tokens::DESIGN_TOKENS;
18use egui::{Response, Role, Ui, WidgetInfo};
19
20/// Button sizes
21#[derive(Debug, Clone, Copy, PartialEq, Default)]
22pub enum ButtonSize {
23    /// Small buttons.
24    SM,
25    /// Medium toolbar buttons.
26    #[default]
27    MD,
28    /// Large buttons.
29    LG,
30    /// Extra-large buttons.
31    XL,
32}
33
34impl ButtonSize {
35    /// Side length in egui logical points.
36    #[inline]
37    pub fn pixels(&self) -> f32 {
38        match self {
39            ButtonSize::SM => DESIGN_TOKENS.sizing.button_sm,
40            ButtonSize::MD => DESIGN_TOKENS.sizing.button_md,
41            ButtonSize::LG => DESIGN_TOKENS.sizing.button_lg,
42            ButtonSize::XL => DESIGN_TOKENS.sizing.button_xl,
43        }
44    }
45
46    /// Icon size for this button size, or `scale` times the button size when one is set.
47    fn icon_pixels(&self, scale: Option<f32>) -> f32 {
48        scale.map_or(
49            match self {
50                ButtonSize::SM => DESIGN_TOKENS.sizing.icon_sm,
51                ButtonSize::MD => DESIGN_TOKENS.sizing.icon_md,
52                ButtonSize::LG | ButtonSize::XL => DESIGN_TOKENS.sizing.icon_lg,
53            },
54            |scale| self.pixels() * scale,
55        )
56    }
57}
58
59/// Report a button to accessibility tools and attach its tooltip, which also shows while disabled.
60fn finish(
61    response: Response,
62    selected: Option<bool>,
63    label: &str,
64    tooltip: Option<&str>,
65) -> Response {
66    let translated_label = l10n::text(&response.ctx, label);
67    response.widget_info(|| {
68        if let Some(selected) = selected {
69            WidgetInfo::selected(
70                Role::Button,
71                response.enabled(),
72                selected,
73                &translated_label,
74            )
75        } else {
76            WidgetInfo::labeled(Role::Button, response.enabled(), &translated_label)
77        }
78    });
79    match tooltip {
80        Some(tip) => {
81            let tip = l10n::text(&response.ctx, tip);
82            response.on_hover_text(&tip).on_disabled_hover_text(&tip)
83        }
84        None => response,
85    }
86}
87
88/// Render a dialog close button: an [`IconButton`] with the close icon.
89///
90/// Returns the click [`Response`].
91///
92/// # Example
93///
94/// ```
95/// use egui_charts::tokens::DESIGN_TOKENS;
96/// use egui_charts::ui_kit::buttons::dialog_close_button;
97///
98/// # egui::__run_test_ui(|ui| {
99/// ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
100///     ui.add_space(DESIGN_TOKENS.spacing.sm);
101///     if dialog_close_button(ui).clicked() {
102///         // close the dialog
103///     }
104/// });
105/// # });
106/// ```
107pub fn dialog_close_button(ui: &mut Ui) -> Response {
108    IconButton::new(&crate::icons::icons::CLOSE)
109        .tooltip("Close")
110        .show(ui)
111}
112
113/// The kit disclosure icon for egui combo boxes.
114pub(crate) fn combo_chevron(
115    ui: &Ui,
116    rect: egui::Rect,
117    visuals: &egui::style::WidgetVisuals,
118    _open: bool,
119) {
120    use egui::emath::GuiRounding;
121    let rect = egui::Rect::from_center_size(
122        rect.center(),
123        egui::Vec2::splat(DESIGN_TOKENS.sizing.icon_sm),
124    )
125    .round_to_pixels(ui.pixels_per_point());
126    crate::icons::icons::CHEVRON_DOWN
127        .as_image_tinted(rect.size(), visuals.fg_stroke.color)
128        .paint_at(ui, rect);
129}