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