icon_button.rs

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