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(
 61        mut self,
 62        handler: impl 'static + Fn(&mut V, &mut ViewContext<V>) + Send + Sync,
 63    ) -> Self {
 64        self.handlers.click = Some(Arc::new(handler));
 65        self
 66    }
 67
 68    fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 69        let icon_color = match (self.state, self.color) {
 70            (InteractionState::Disabled, _) => IconColor::Disabled,
 71            _ => self.color,
 72        };
 73
 74        let (bg_color, bg_hover_color, bg_active_color) = match self.variant {
 75            ButtonVariant::Filled => (
 76                cx.theme().colors().element,
 77                cx.theme().colors().element_hover,
 78                cx.theme().colors().element_active,
 79            ),
 80            ButtonVariant::Ghost => (
 81                cx.theme().colors().ghost_element,
 82                cx.theme().colors().ghost_element_hover,
 83                cx.theme().colors().ghost_element_active,
 84            ),
 85        };
 86
 87        let mut button = h_stack()
 88            .id(self.id.clone())
 89            .justify_center()
 90            .rounded_md()
 91            .py(ui_size(cx, 0.25))
 92            .px(ui_size(cx, 6. / 14.))
 93            .bg(bg_color)
 94            .hover(|style| style.bg(bg_hover_color))
 95            .active(|style| style.bg(bg_active_color))
 96            .child(IconElement::new(self.icon).color(icon_color));
 97
 98        if let Some(click_handler) = self.handlers.click.clone() {
 99            button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
100                click_handler(state, cx);
101            });
102        }
103
104        button
105    }
106}