icon_button.rs

  1use crate::{h_stack, prelude::*, ClickHandler, Icon, IconElement};
  2use gpui::{prelude::*, AnyView, MouseButton};
  3use std::sync::Arc;
  4
  5struct IconButtonHandlers<V: 'static> {
  6    click: Option<ClickHandler<V>>,
  7}
  8
  9impl<V: 'static> Default for IconButtonHandlers<V> {
 10    fn default() -> Self {
 11        Self { click: None }
 12    }
 13}
 14
 15#[derive(Component)]
 16pub struct IconButton<V: 'static> {
 17    id: ElementId,
 18    icon: Icon,
 19    color: TextColor,
 20    variant: ButtonVariant,
 21    state: InteractionState,
 22    tooltip: Option<Box<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>>,
 23    handlers: IconButtonHandlers<V>,
 24}
 25
 26impl<V: 'static> IconButton<V> {
 27    pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self {
 28        Self {
 29            id: id.into(),
 30            icon,
 31            color: TextColor::default(),
 32            variant: ButtonVariant::default(),
 33            state: InteractionState::default(),
 34            tooltip: None,
 35            handlers: IconButtonHandlers::default(),
 36        }
 37    }
 38
 39    pub fn icon(mut self, icon: Icon) -> Self {
 40        self.icon = icon;
 41        self
 42    }
 43
 44    pub fn color(mut self, color: TextColor) -> Self {
 45        self.color = color;
 46        self
 47    }
 48
 49    pub fn variant(mut self, variant: ButtonVariant) -> Self {
 50        self.variant = variant;
 51        self
 52    }
 53
 54    pub fn state(mut self, state: InteractionState) -> Self {
 55        self.state = state;
 56        self
 57    }
 58
 59    pub fn tooltip(
 60        mut self,
 61        tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static,
 62    ) -> Self {
 63        self.tooltip = Some(Box::new(tooltip));
 64        self
 65    }
 66
 67    pub fn on_click(mut self, handler: impl 'static + Fn(&mut V, &mut ViewContext<V>)) -> Self {
 68        self.handlers.click = Some(Arc::new(handler));
 69        self
 70    }
 71
 72    fn render(mut self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 73        let icon_color = match (self.state, self.color) {
 74            (InteractionState::Disabled, _) => TextColor::Disabled,
 75            (InteractionState::Active, _) => TextColor::Error,
 76            _ => self.color,
 77        };
 78
 79        let (bg_color, bg_hover_color, bg_active_color) = match self.variant {
 80            ButtonVariant::Filled => (
 81                cx.theme().colors().element_background,
 82                cx.theme().colors().element_hover,
 83                cx.theme().colors().element_active,
 84            ),
 85            ButtonVariant::Ghost => (
 86                cx.theme().colors().ghost_element_background,
 87                cx.theme().colors().ghost_element_hover,
 88                cx.theme().colors().ghost_element_active,
 89            ),
 90        };
 91
 92        let mut button = h_stack()
 93            .id(self.id.clone())
 94            .justify_center()
 95            .rounded_md()
 96            .p_1()
 97            .bg(bg_color)
 98            .hover(|style| style.bg(bg_hover_color))
 99            .active(|style| style.bg(bg_active_color))
100            .child(IconElement::new(self.icon).color(icon_color));
101
102        if let Some(click_handler) = self.handlers.click.clone() {
103            button = button
104                .on_mouse_down(MouseButton::Left, move |state, event, cx| {
105                    cx.stop_propagation();
106                    click_handler(state, cx);
107                })
108                .cursor_pointer();
109        }
110
111        if let Some(tooltip) = self.tooltip.take() {
112            button = button.tooltip(move |view: &mut V, cx| (tooltip)(view, cx))
113        }
114
115        button
116    }
117}