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