1use gpui::{AnyView, DefiniteLength};
2
3use crate::prelude::*;
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_size: Option<IconSize>,
18 icon_color: Option<Color>,
19 selected_icon: Option<Icon>,
20}
21
22impl Button {
23 pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>) -> Self {
24 Self {
25 base: ButtonLike::new(id),
26 label: label.into(),
27 label_color: None,
28 selected_label: None,
29 icon: None,
30 icon_size: None,
31 icon_color: None,
32 selected_icon: None,
33 }
34 }
35
36 pub fn color(mut self, label_color: impl Into<Option<Color>>) -> Self {
37 self.label_color = label_color.into();
38 self
39 }
40
41 pub fn selected_label<L: Into<SharedString>>(mut self, label: impl Into<Option<L>>) -> Self {
42 self.selected_label = label.into().map(Into::into);
43 self
44 }
45
46 pub fn icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
47 self.icon = icon.into();
48 self
49 }
50
51 pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
52 self.icon_size = icon_size.into();
53 self
54 }
55
56 pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
57 self.icon_color = icon_color.into();
58 self
59 }
60
61 pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
62 self.selected_icon = icon.into();
63 self
64 }
65}
66
67impl Selectable for Button {
68 fn selected(mut self, selected: bool) -> Self {
69 self.base = self.base.selected(selected);
70 self
71 }
72}
73
74impl Disableable for Button {
75 fn disabled(mut self, disabled: bool) -> Self {
76 self.base = self.base.disabled(disabled);
77 self
78 }
79}
80
81impl Clickable for Button {
82 fn on_click(
83 mut self,
84 handler: impl Fn(&gpui::ClickEvent, &mut WindowContext) + 'static,
85 ) -> Self {
86 self.base = self.base.on_click(handler);
87 self
88 }
89}
90
91impl FixedWidth for Button {
92 fn width(mut self, width: DefiniteLength) -> Self {
93 self.base = self.base.width(width);
94 self
95 }
96
97 fn full_width(mut self) -> Self {
98 self.base = self.base.full_width();
99 self
100 }
101}
102
103impl ButtonCommon for Button {
104 fn id(&self) -> &ElementId {
105 self.base.id()
106 }
107
108 fn style(mut self, style: ButtonStyle) -> Self {
109 self.base = self.base.style(style);
110 self
111 }
112
113 fn size(mut self, size: ButtonSize) -> Self {
114 self.base = self.base.size(size);
115 self
116 }
117
118 fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
119 self.base = self.base.tooltip(tooltip);
120 self
121 }
122}
123
124impl RenderOnce for Button {
125 type Rendered = ButtonLike;
126
127 fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
128 let is_disabled = self.base.disabled;
129 let is_selected = self.base.selected;
130
131 let label = self
132 .selected_label
133 .filter(|_| is_selected)
134 .unwrap_or(self.label);
135
136 let label_color = if is_disabled {
137 Color::Disabled
138 } else if is_selected {
139 Color::Selected
140 } else {
141 self.label_color.unwrap_or_default()
142 };
143
144 self.base
145 .children(self.icon.map(|icon| {
146 ButtonIcon::new(icon)
147 .disabled(is_disabled)
148 .selected(is_selected)
149 .selected_icon(self.selected_icon)
150 .size(self.icon_size)
151 .color(self.icon_color)
152 }))
153 .child(
154 Label::new(label)
155 .color(label_color)
156 .line_height_style(LineHeightStyle::UILabel),
157 )
158 }
159}