icon_button.rs

  1use gpui::{AnyView, DefiniteLength};
  2
  3use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle};
  4use crate::{prelude::*, ElevationIndex, SelectableButton};
  5use crate::{IconName, IconSize};
  6
  7use super::button_icon::ButtonIcon;
  8
  9/// The shape of an [`IconButton`].
 10#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
 11pub enum IconButtonShape {
 12    Square,
 13    Wide,
 14}
 15
 16#[derive(IntoElement)]
 17pub struct IconButton {
 18    base: ButtonLike,
 19    shape: IconButtonShape,
 20    icon: IconName,
 21    icon_size: IconSize,
 22    icon_color: Color,
 23    selected_icon: Option<IconName>,
 24}
 25
 26impl IconButton {
 27    pub fn new(id: impl Into<ElementId>, icon: IconName) -> Self {
 28        let mut this = Self {
 29            base: ButtonLike::new(id),
 30            shape: IconButtonShape::Wide,
 31            icon,
 32            icon_size: IconSize::default(),
 33            icon_color: Color::Default,
 34            selected_icon: None,
 35        };
 36        this.base.base = this.base.base.debug_selector(|| format!("ICON-{:?}", icon));
 37        this
 38    }
 39
 40    pub fn shape(mut self, shape: IconButtonShape) -> Self {
 41        self.shape = shape;
 42        self
 43    }
 44
 45    pub fn icon_size(mut self, icon_size: IconSize) -> Self {
 46        self.icon_size = icon_size;
 47        self
 48    }
 49
 50    pub fn icon_color(mut self, icon_color: Color) -> Self {
 51        self.icon_color = icon_color;
 52        self
 53    }
 54
 55    pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
 56        self.selected_icon = icon.into();
 57        self
 58    }
 59}
 60
 61impl Disableable for IconButton {
 62    fn disabled(mut self, disabled: bool) -> Self {
 63        self.base = self.base.disabled(disabled);
 64        self
 65    }
 66}
 67
 68impl Selectable for IconButton {
 69    fn selected(mut self, selected: bool) -> Self {
 70        self.base = self.base.selected(selected);
 71        self
 72    }
 73}
 74
 75impl SelectableButton for IconButton {
 76    fn selected_style(mut self, style: ButtonStyle) -> Self {
 77        self.base = self.base.selected_style(style);
 78        self
 79    }
 80}
 81
 82impl Clickable for IconButton {
 83    fn on_click(
 84        mut self,
 85        handler: impl Fn(&gpui::ClickEvent, &mut WindowContext) + 'static,
 86    ) -> Self {
 87        self.base = self.base.on_click(handler);
 88        self
 89    }
 90
 91    fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
 92        self.base = self.base.cursor_style(cursor_style);
 93        self
 94    }
 95}
 96
 97impl FixedWidth for IconButton {
 98    fn width(mut self, width: DefiniteLength) -> Self {
 99        self.base = self.base.width(width);
100        self
101    }
102
103    fn full_width(mut self) -> Self {
104        self.base = self.base.full_width();
105        self
106    }
107}
108
109impl ButtonCommon for IconButton {
110    fn id(&self) -> &ElementId {
111        self.base.id()
112    }
113
114    fn style(mut self, style: ButtonStyle) -> Self {
115        self.base = self.base.style(style);
116        self
117    }
118
119    fn size(mut self, size: ButtonSize) -> Self {
120        self.base = self.base.size(size);
121        self
122    }
123
124    fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
125        self.base = self.base.tooltip(tooltip);
126        self
127    }
128
129    fn layer(mut self, elevation: ElevationIndex) -> Self {
130        self.base = self.base.layer(elevation);
131        self
132    }
133}
134
135impl VisibleOnHover for IconButton {
136    fn visible_on_hover(mut self, group_name: impl Into<SharedString>) -> Self {
137        self.base = self.base.visible_on_hover(group_name);
138        self
139    }
140}
141
142impl RenderOnce for IconButton {
143    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
144        let is_disabled = self.base.disabled;
145        let is_selected = self.base.selected;
146        let selected_style = self.base.selected_style;
147
148        self.base
149            .map(|this| match self.shape {
150                IconButtonShape::Square => {
151                    let size = self.icon_size.square(cx);
152                    this.width(size.into()).height(size.into())
153                }
154                IconButtonShape::Wide => this,
155            })
156            .child(
157                ButtonIcon::new(self.icon)
158                    .disabled(is_disabled)
159                    .selected(is_selected)
160                    .selected_icon(self.selected_icon)
161                    .when_some(selected_style, |this, style| this.selected_style(style))
162                    .size(self.icon_size)
163                    .color(self.icon_color),
164            )
165    }
166}