Skip to main content

egui_charts/ui_kit/toolbar/
mod.rs

1//! Horizontal and vertical toolbar layouts with grouped buttons.
2//!
3//! Use [`ResponsiveToolbar`] for a toolbar container, [`ButtonGroup`] for related
4//! actions and [`ToolbarLayout`] to split left and right controls. Toolbars lay out
5//! contents directly without adding scrolling.
6
7mod button_group;
8
9pub use button_group::{ButtonGroup, ToolbarLayout};
10
11use std::hash::Hash;
12
13use egui::{Id, Ui};
14
15use crate::styles::responsive::LayoutContext;
16
17/// Toolbar orientation
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19pub enum Orientation {
20    /// Horizontal toolbar (most common)
21    #[default]
22    Horizontal,
23    /// Vertical toolbar (e.g., drawing toolbar)
24    Vertical,
25}
26
27/// Horizontal or vertical toolbar container with an egui state scope.
28///
29/// Contents use the available layout directly, without a scroll area.
30///
31/// # Example
32/// ```
33/// # use egui_charts::ui_kit::ResponsiveToolbar;
34/// # egui::__run_test_ui(|ui| {
35/// ResponsiveToolbar::horizontal("my_toolbar")
36///     .height(48.0)
37///     .show(ui, |ui, ctx| {
38///         // Render toolbar contents
39///     });
40/// # });
41/// ```
42pub struct ResponsiveToolbar {
43    /// Unique toolbar ID, scoping the contents' egui state so multiple toolbars
44    /// in one frame do not collide.
45    id: Id,
46    orientation: Orientation,
47    height: Option<f32>,
48}
49
50impl ResponsiveToolbar {
51    /// Create a new horizontal toolbar with the given ID
52    pub fn horizontal(id: impl Hash + std::fmt::Debug) -> Self {
53        Self {
54            id: Id::unique(id),
55            orientation: Orientation::Horizontal,
56            height: None,
57        }
58    }
59
60    /// Create a new vertical toolbar with the given ID
61    pub fn vertical(id: impl Hash + std::fmt::Debug) -> Self {
62        Self {
63            id: Id::unique(id),
64            orientation: Orientation::Vertical,
65            height: None,
66        }
67    }
68
69    /// Set the fixed height for the toolbar
70    #[must_use]
71    pub fn height(mut self, h: f32) -> Self {
72        self.height = Some(h);
73        self
74    }
75
76    /// Show the toolbar contents without a scroll area.
77    ///
78    /// The callback receives:
79    /// - `ui`: The UI context to render into
80    /// - `ctx`: The layout context
81    ///
82    /// Returns the value returned by the callback.
83    pub fn show<R>(self, ui: &mut Ui, content: impl FnOnce(&mut Ui, &LayoutContext) -> R) -> R {
84        let layout_ctx = LayoutContext::from_egui(ui.ctx());
85        let id = self.id;
86
87        ui.push_id(id, |ui| match self.orientation {
88            Orientation::Horizontal => self.show_horizontal(ui, &layout_ctx, content),
89            Orientation::Vertical => self.show_vertical(ui, &layout_ctx, content),
90        })
91        .inner
92    }
93
94    fn show_horizontal<R>(
95        self,
96        ui: &mut Ui,
97        layout_ctx: &LayoutContext,
98        content: impl FnOnce(&mut Ui, &LayoutContext) -> R,
99    ) -> R {
100        // Get the FULL panel rect
101        let full_rect = ui.max_rect();
102        let bg_color = ui.style().visuals.panel_fill;
103
104        // Paint background over the full area
105        ui.painter().rect_filled(full_rect, 0.0, bg_color);
106
107        // Allocate the entire space to prevent gaps
108        let _ = ui.allocate_rect(full_rect, egui::Sense::hover());
109
110        // Create a child UI with centered layout
111        let mut child_ui = ui.new_child(
112            egui::UiBuilder::new()
113                .max_rect(full_rect)
114                .layout(egui::Layout::left_to_right(egui::Align::Center)),
115        );
116
117        // Desktop: render content directly (no scroll)
118        content(&mut child_ui, layout_ctx)
119    }
120
121    fn show_vertical<R>(
122        self,
123        ui: &mut Ui,
124        layout_ctx: &LayoutContext,
125        content: impl FnOnce(&mut Ui, &LayoutContext) -> R,
126    ) -> R {
127        // Desktop: normal vertical layout (no scroll)
128        ui.vertical(|ui| content(ui, layout_ctx)).inner
129    }
130}