button_icon.rs

  1use crate::{Icon, IconName, IconSize, IconWithIndicator, Indicator, prelude::*};
  2use gpui::Hsla;
  3
  4/// An icon that appears within a button.
  5///
  6/// Can be used as either an icon alongside a label, like in [`Button`](crate::Button),
  7/// or as a standalone icon, like in [`IconButton`](crate::IconButton).
  8#[derive(IntoElement, RegisterComponent)]
  9pub(super) struct ButtonIcon {
 10    icon: IconName,
 11    size: IconSize,
 12    color: Color,
 13    disabled: bool,
 14    selected: bool,
 15    selected_icon: Option<IconName>,
 16    selected_icon_color: Option<Color>,
 17    selected_style: Option<ButtonStyle>,
 18    indicator: Option<Indicator>,
 19    indicator_border_color: Option<Hsla>,
 20}
 21
 22impl ButtonIcon {
 23    pub fn new(icon: IconName) -> Self {
 24        Self {
 25            icon,
 26            size: IconSize::default(),
 27            color: Color::default(),
 28            disabled: false,
 29            selected: false,
 30            selected_icon: None,
 31            selected_icon_color: None,
 32            selected_style: None,
 33            indicator: None,
 34            indicator_border_color: None,
 35        }
 36    }
 37
 38    pub fn size(mut self, size: impl Into<Option<IconSize>>) -> Self {
 39        if let Some(size) = size.into() {
 40            self.size = size;
 41        }
 42        self
 43    }
 44
 45    pub fn color(mut self, color: impl Into<Option<Color>>) -> Self {
 46        if let Some(color) = color.into() {
 47            self.color = color;
 48        }
 49        self
 50    }
 51
 52    pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
 53        self.selected_icon = icon.into();
 54        self
 55    }
 56
 57    pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
 58        self.selected_icon_color = color.into();
 59        self
 60    }
 61
 62    pub fn indicator(mut self, indicator: Indicator) -> Self {
 63        self.indicator = Some(indicator);
 64        self
 65    }
 66
 67    pub fn indicator_border_color(mut self, color: Option<Hsla>) -> Self {
 68        self.indicator_border_color = color;
 69        self
 70    }
 71}
 72
 73impl Disableable for ButtonIcon {
 74    fn disabled(mut self, disabled: bool) -> Self {
 75        self.disabled = disabled;
 76        self
 77    }
 78}
 79
 80impl Toggleable for ButtonIcon {
 81    fn toggle_state(mut self, selected: bool) -> Self {
 82        self.selected = selected;
 83        self
 84    }
 85}
 86
 87impl SelectableButton for ButtonIcon {
 88    fn selected_style(mut self, style: ButtonStyle) -> Self {
 89        self.selected_style = Some(style);
 90        self
 91    }
 92}
 93
 94impl RenderOnce for ButtonIcon {
 95    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
 96        let icon = self
 97            .selected_icon
 98            .filter(|_| self.selected)
 99            .unwrap_or(self.icon);
100
101        let icon_color = if self.disabled {
102            Color::Disabled
103        } else if self.selected_style.is_some() && self.selected {
104            self.selected_style.unwrap().into()
105        } else if self.selected {
106            self.selected_icon_color.unwrap_or(Color::Selected)
107        } else {
108            self.color
109        };
110
111        let icon = Icon::new(icon).size(self.size).color(icon_color);
112
113        match self.indicator {
114            Some(indicator) => IconWithIndicator::new(icon, Some(indicator))
115                .indicator_border_color(self.indicator_border_color)
116                .into_any_element(),
117            None => icon.into_any_element(),
118        }
119    }
120}
121
122impl Component for ButtonIcon {
123    fn scope() -> ComponentScope {
124        ComponentScope::Input
125    }
126
127    fn name() -> &'static str {
128        "ButtonIcon"
129    }
130
131    fn description() -> Option<&'static str> {
132        Some("An icon component specifically designed for use within buttons.")
133    }
134
135    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
136        Some(
137            v_flex()
138                .gap_6()
139                .children(vec![
140                    example_group_with_title(
141                        "Basic Usage",
142                        vec![
143                            single_example(
144                                "Default",
145                                ButtonIcon::new(IconName::Star).into_any_element(),
146                            ),
147                            single_example(
148                                "Custom Size",
149                                ButtonIcon::new(IconName::Star)
150                                    .size(IconSize::Medium)
151                                    .into_any_element(),
152                            ),
153                            single_example(
154                                "Custom Color",
155                                ButtonIcon::new(IconName::Star)
156                                    .color(Color::Accent)
157                                    .into_any_element(),
158                            ),
159                        ],
160                    ),
161                    example_group_with_title(
162                        "States",
163                        vec![
164                            single_example(
165                                "Selected",
166                                ButtonIcon::new(IconName::Star)
167                                    .toggle_state(true)
168                                    .into_any_element(),
169                            ),
170                            single_example(
171                                "Disabled",
172                                ButtonIcon::new(IconName::Star)
173                                    .disabled(true)
174                                    .into_any_element(),
175                            ),
176                        ],
177                    ),
178                    example_group_with_title(
179                        "With Indicator",
180                        vec![
181                            single_example(
182                                "Default Indicator",
183                                ButtonIcon::new(IconName::Star)
184                                    .indicator(Indicator::dot())
185                                    .into_any_element(),
186                            ),
187                            single_example(
188                                "Custom Indicator",
189                                ButtonIcon::new(IconName::Star)
190                                    .indicator(Indicator::dot().color(Color::Error))
191                                    .into_any_element(),
192                            ),
193                        ],
194                    ),
195                ])
196                .into_any_element(),
197        )
198    }
199}