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 selected_icon_color: Option<Color>,
26 indicator: Option<Indicator>,
27 indicator_border_color: Option<Hsla>,
28 alpha: Option<f32>,
29}
30
31impl IconButton {
32 pub fn new(id: impl Into<ElementId>, icon: IconName) -> Self {
33 let mut this = Self {
34 base: ButtonLike::new(id),
35 shape: IconButtonShape::Wide,
36 icon,
37 icon_size: IconSize::default(),
38 icon_color: Color::Default,
39 selected_icon: None,
40 selected_icon_color: None,
41 indicator: None,
42 indicator_border_color: None,
43 alpha: None,
44 };
45 this.base.base = this.base.base.debug_selector(|| format!("ICON-{:?}", icon));
46 this
47 }
48
49 pub fn shape(mut self, shape: IconButtonShape) -> Self {
50 self.shape = shape;
51 self
52 }
53
54 pub fn icon_size(mut self, icon_size: IconSize) -> Self {
55 self.icon_size = icon_size;
56 self
57 }
58
59 pub fn icon_color(mut self, icon_color: Color) -> Self {
60 self.icon_color = icon_color;
61 self
62 }
63
64 pub fn alpha(mut self, alpha: f32) -> Self {
65 self.alpha = Some(alpha);
66 self
67 }
68
69 pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
70 self.selected_icon = icon.into();
71 self
72 }
73
74 /// Sets the icon color used when the button is in a selected state.
75 pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
76 self.selected_icon_color = color.into();
77 self
78 }
79
80 pub fn indicator(mut self, indicator: Indicator) -> Self {
81 self.indicator = Some(indicator);
82 self
83 }
84
85 pub fn indicator_border_color(mut self, color: Option<Hsla>) -> Self {
86 self.indicator_border_color = color;
87 self
88 }
89}
90
91impl Disableable for IconButton {
92 fn disabled(mut self, disabled: bool) -> Self {
93 self.base = self.base.disabled(disabled);
94 self
95 }
96}
97
98impl Toggleable for IconButton {
99 fn toggle_state(mut self, selected: bool) -> Self {
100 self.base = self.base.toggle_state(selected);
101 self
102 }
103}
104
105impl SelectableButton for IconButton {
106 fn selected_style(mut self, style: ButtonStyle) -> Self {
107 self.base = self.base.selected_style(style);
108 self
109 }
110}
111
112impl Clickable for IconButton {
113 fn on_click(
114 mut self,
115 handler: impl Fn(&gpui::ClickEvent, &mut Window, &mut App) + 'static,
116 ) -> Self {
117 self.base = self.base.on_click(handler);
118 self
119 }
120
121 fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
122 self.base = self.base.cursor_style(cursor_style);
123 self
124 }
125}
126
127impl FixedWidth for IconButton {
128 fn width(mut self, width: DefiniteLength) -> Self {
129 self.base = self.base.width(width);
130 self
131 }
132
133 fn full_width(mut self) -> Self {
134 self.base = self.base.full_width();
135 self
136 }
137}
138
139impl ButtonCommon for IconButton {
140 fn id(&self) -> &ElementId {
141 self.base.id()
142 }
143
144 fn style(mut self, style: ButtonStyle) -> Self {
145 self.base = self.base.style(style);
146 self
147 }
148
149 fn size(mut self, size: ButtonSize) -> Self {
150 self.base = self.base.size(size);
151 self
152 }
153
154 fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
155 self.base = self.base.tooltip(tooltip);
156 self
157 }
158
159 fn layer(mut self, elevation: ElevationIndex) -> Self {
160 self.base = self.base.layer(elevation);
161 self
162 }
163}
164
165impl VisibleOnHover for IconButton {
166 fn visible_on_hover(mut self, group_name: impl Into<SharedString>) -> Self {
167 self.base = self.base.visible_on_hover(group_name);
168 self
169 }
170}
171
172impl RenderOnce for IconButton {
173 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
174 let is_disabled = self.base.disabled;
175 let is_selected = self.base.selected;
176 let selected_style = self.base.selected_style;
177
178 let color = self.icon_color.color(cx).opacity(self.alpha.unwrap_or(1.0));
179 self.base
180 .map(|this| match self.shape {
181 IconButtonShape::Square => {
182 let size = self.icon_size.square(window, cx);
183 this.width(size.into()).height(size.into())
184 }
185 IconButtonShape::Wide => this,
186 })
187 .child(
188 ButtonIcon::new(self.icon)
189 .disabled(is_disabled)
190 .toggle_state(is_selected)
191 .selected_icon(self.selected_icon)
192 .selected_icon_color(self.selected_icon_color)
193 .when_some(selected_style, |this, style| this.selected_style(style))
194 .when_some(self.indicator, |this, indicator| {
195 this.indicator(indicator)
196 .indicator_border_color(self.indicator_border_color)
197 })
198 .size(self.icon_size)
199 .color(Color::Custom(color)),
200 )
201 }
202}