icon_button.rs

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