1use gpui::{AnyView, DefiniteLength};
2
3use crate::{prelude::*, IconPosition};
4use crate::{
5 ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconSize, Label, LineHeightStyle,
6};
7
8use super::button_icon::ButtonIcon;
9
10#[derive(IntoElement)]
11pub struct Button {
12 base: ButtonLike,
13 label: SharedString,
14 label_color: Option<Color>,
15 selected_label: Option<SharedString>,
16 icon: Option<Icon>,
17 icon_position: Option<IconPosition>,
18 icon_size: Option<IconSize>,
19 icon_color: Option<Color>,
20 selected_icon: Option<Icon>,
21}
22
23impl Button {
24 pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>) -> Self {
25 Self {
26 base: ButtonLike::new(id),
27 label: label.into(),
28 label_color: None,
29 selected_label: None,
30 icon: None,
31 icon_position: None,
32 icon_size: None,
33 icon_color: None,
34 selected_icon: None,
35 }
36 }
37
38 pub fn color(mut self, label_color: impl Into<Option<Color>>) -> Self {
39 self.label_color = label_color.into();
40 self
41 }
42
43 pub fn selected_label<L: Into<SharedString>>(mut self, label: impl Into<Option<L>>) -> Self {
44 self.selected_label = label.into().map(Into::into);
45 self
46 }
47
48 pub fn icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
49 self.icon = icon.into();
50 self
51 }
52
53 pub fn icon_position(mut self, icon_position: impl Into<Option<IconPosition>>) -> Self {
54 self.icon_position = icon_position.into();
55 self
56 }
57
58 pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
59 self.icon_size = icon_size.into();
60 self
61 }
62
63 pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
64 self.icon_color = icon_color.into();
65 self
66 }
67
68 pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
69 self.selected_icon = icon.into();
70 self
71 }
72}
73
74impl Selectable for Button {
75 fn selected(mut self, selected: bool) -> Self {
76 self.base = self.base.selected(selected);
77 self
78 }
79}
80
81impl Disableable for Button {
82 fn disabled(mut self, disabled: bool) -> Self {
83 self.base = self.base.disabled(disabled);
84 self
85 }
86}
87
88impl Clickable for Button {
89 fn on_click(
90 mut self,
91 handler: impl Fn(&gpui::ClickEvent, &mut WindowContext) + 'static,
92 ) -> Self {
93 self.base = self.base.on_click(handler);
94 self
95 }
96}
97
98impl FixedWidth for Button {
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 Button {
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
131impl RenderOnce for Button {
132 type Rendered = ButtonLike;
133
134 fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
135 let is_disabled = self.base.disabled;
136 let is_selected = self.base.selected;
137
138 let label = self
139 .selected_label
140 .filter(|_| is_selected)
141 .unwrap_or(self.label);
142
143 let label_color = if is_disabled {
144 Color::Disabled
145 } else if is_selected {
146 Color::Selected
147 } else {
148 self.label_color.unwrap_or_default()
149 };
150
151 self.base.child(
152 h_stack()
153 .gap_1()
154 .when(self.icon_position.is_some(), |this| {
155 this.children(self.icon.map(|icon| {
156 ButtonIcon::new(icon)
157 .disabled(is_disabled)
158 .selected(is_selected)
159 .selected_icon(self.selected_icon)
160 .size(self.icon_size)
161 .color(self.icon_color)
162 }))
163 })
164 .child(
165 Label::new(label)
166 .color(label_color)
167 .line_height_style(LineHeightStyle::UILabel),
168 )
169 .when(!self.icon_position.is_some(), |this| {
170 this.children(self.icon.map(|icon| {
171 ButtonIcon::new(icon)
172 .disabled(is_disabled)
173 .selected(is_selected)
174 .selected_icon(self.selected_icon)
175 .size(self.icon_size)
176 .color(self.icon_color)
177 }))
178 }),
179 )
180 }
181}