icon_button.rs

  1use std::marker::PhantomData;
  2use std::sync::Arc;
  3
  4use gpui3::{Interactive, MouseButton};
  5
  6use crate::prelude::*;
  7use crate::{theme, 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    icon: Icon,
 23    color: IconColor,
 24    variant: ButtonVariant,
 25    state: InteractionState,
 26    handlers: IconButtonHandlers<S>,
 27}
 28
 29impl<S: 'static + Send + Sync> IconButton<S> {
 30    pub fn new(icon: Icon) -> Self {
 31        Self {
 32            state_type: PhantomData,
 33            icon,
 34            color: IconColor::default(),
 35            variant: ButtonVariant::default(),
 36            state: InteractionState::default(),
 37            handlers: IconButtonHandlers::default(),
 38        }
 39    }
 40
 41    pub fn icon(mut self, icon: Icon) -> Self {
 42        self.icon = icon;
 43        self
 44    }
 45
 46    pub fn color(mut self, color: IconColor) -> Self {
 47        self.color = color;
 48        self
 49    }
 50
 51    pub fn variant(mut self, variant: ButtonVariant) -> Self {
 52        self.variant = variant;
 53        self
 54    }
 55
 56    pub fn state(mut self, state: InteractionState) -> Self {
 57        self.state = state;
 58        self
 59    }
 60
 61    pub fn on_click(
 62        mut self,
 63        handler: impl Fn(&mut S, &mut ViewContext<S>) + 'static + Send + Sync,
 64    ) -> Self {
 65        self.handlers.click = Some(Arc::new(handler));
 66        self
 67    }
 68
 69    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
 70        let theme = theme(cx);
 71
 72        let icon_color = match (self.state, self.color) {
 73            (InteractionState::Disabled, _) => IconColor::Disabled,
 74            _ => self.color,
 75        };
 76
 77        let mut div = div();
 78        if self.variant == ButtonVariant::Filled {
 79            div = div.fill(theme.highest.on.default.background);
 80        }
 81
 82        if let Some(click_handler) = self.handlers.click.clone() {
 83            div = div.on_click(MouseButton::Left, move |state, event, cx| {
 84                click_handler(state, cx);
 85            });
 86        }
 87
 88        div.w_7()
 89            .h_6()
 90            .flex()
 91            .items_center()
 92            .justify_center()
 93            .rounded_md()
 94            .hover()
 95            .fill(theme.highest.base.hovered.background)
 96            // .active()
 97            // .fill(theme.highest.base.pressed.background)
 98            .child(IconElement::new(self.icon).color(icon_color))
 99    }
100}