icon_button.rs

  1use crate::{h_stack, prelude::*};
  2use crate::{ClickHandler, Icon, IconColor, IconElement};
  3use gpui::{prelude::*, rems, MouseButton};
  4use std::sync::Arc;
  5
  6struct IconButtonHandlers<V: 'static> {
  7    click: Option<ClickHandler<V>>,
  8}
  9
 10impl<V: 'static> Default for IconButtonHandlers<V> {
 11    fn default() -> Self {
 12        Self { click: None }
 13    }
 14}
 15
 16#[derive(Component)]
 17pub struct IconButton<V: 'static> {
 18    id: ElementId,
 19    icon: Icon,
 20    color: IconColor,
 21    variant: ButtonVariant,
 22    state: InteractionState,
 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: IconColor::default(),
 32            variant: ButtonVariant::default(),
 33            state: InteractionState::default(),
 34            handlers: IconButtonHandlers::default(),
 35        }
 36    }
 37
 38    pub fn icon(mut self, icon: Icon) -> Self {
 39        self.icon = icon;
 40        self
 41    }
 42
 43    pub fn color(mut self, color: IconColor) -> Self {
 44        self.color = color;
 45        self
 46    }
 47
 48    pub fn variant(mut self, variant: ButtonVariant) -> Self {
 49        self.variant = variant;
 50        self
 51    }
 52
 53    pub fn state(mut self, state: InteractionState) -> Self {
 54        self.state = state;
 55        self
 56    }
 57
 58    pub fn on_click(
 59        mut self,
 60        handler: impl 'static + Fn(&mut V, &mut ViewContext<V>) + Send + Sync,
 61    ) -> Self {
 62        self.handlers.click = Some(Arc::new(handler));
 63        self
 64    }
 65
 66    fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 67        let icon_color = match (self.state, self.color) {
 68            (InteractionState::Disabled, _) => IconColor::Disabled,
 69            _ => self.color,
 70        };
 71
 72        let (bg_color, bg_hover_color, bg_active_color) = match self.variant {
 73            ButtonVariant::Filled => (
 74                cx.theme().colors().element_background,
 75                cx.theme().colors().element_hover,
 76                cx.theme().colors().element_active,
 77            ),
 78            ButtonVariant::Ghost => (
 79                cx.theme().colors().ghost_element_background,
 80                cx.theme().colors().ghost_element_hover,
 81                cx.theme().colors().ghost_element_active,
 82            ),
 83        };
 84
 85        let mut button = h_stack()
 86            .id(self.id.clone())
 87            .justify_center()
 88            .rounded_md()
 89            // todo!("Where do these numbers come from?")
 90            .py(rems(0.21875))
 91            .px(rems(0.375))
 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                cx.stop_propagation();
100                click_handler(state, cx);
101            });
102        }
103
104        button
105    }
106}