icon_button.rs

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