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)]
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
43 self
44 }
45
46 pub fn color(mut self, color: impl Into<Option<Color>>) -> Self {
47 if let Some(color) = color.into() {
48 self.color = color;
49 }
50
51 self
52 }
53
54 pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
55 self.selected_icon = icon.into();
56 self
57 }
58
59 pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
60 self.selected_icon_color = color.into();
61 self
62 }
63
64 pub fn indicator(mut self, indicator: Indicator) -> Self {
65 self.indicator = Some(indicator);
66 self
67 }
68
69 pub fn indicator_border_color(mut self, color: Option<Hsla>) -> Self {
70 self.indicator_border_color = color;
71 self
72 }
73}
74
75impl Disableable for ButtonIcon {
76 fn disabled(mut self, disabled: bool) -> Self {
77 self.disabled = disabled;
78 self
79 }
80}
81
82impl Toggleable for ButtonIcon {
83 fn toggle_state(mut self, selected: bool) -> Self {
84 self.selected = selected;
85 self
86 }
87}
88
89impl SelectableButton for ButtonIcon {
90 fn selected_style(mut self, style: ButtonStyle) -> Self {
91 self.selected_style = Some(style);
92 self
93 }
94}
95
96impl RenderOnce for ButtonIcon {
97 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
98 let icon = self
99 .selected_icon
100 .filter(|_| self.selected)
101 .unwrap_or(self.icon);
102
103 let icon_color = if self.disabled {
104 Color::Disabled
105 } else if self.selected_style.is_some() && self.selected {
106 self.selected_style.unwrap().into()
107 } else if self.selected {
108 self.selected_icon_color.unwrap_or(Color::Selected)
109 } else {
110 self.color
111 };
112
113 let icon = Icon::new(icon).size(self.size).color(icon_color);
114
115 match self.indicator {
116 Some(indicator) => IconWithIndicator::new(icon, Some(indicator))
117 .indicator_border_color(self.indicator_border_color)
118 .into_any_element(),
119 None => icon.into_any_element(),
120 }
121 }
122}