1use gpui::{relative, AnyElement, FontWeight, StyleRefinement, Styled, UnderlineStyle};
2use settings::Settings;
3use smallvec::SmallVec;
4use theme::ThemeSettings;
5
6use crate::prelude::*;
7
8#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
9pub enum LabelSize {
10 #[default]
11 Default,
12 Large,
13 Small,
14 XSmall,
15}
16
17#[derive(Default, PartialEq, Copy, Clone)]
18pub enum LineHeightStyle {
19 #[default]
20 TextLabel,
21 /// Sets the line height to 1.
22 UiLabel,
23}
24
25/// A common set of traits all labels must implement.
26pub trait LabelCommon {
27 /// Sets the size of the label using a [`LabelSize`].
28 fn size(self, size: LabelSize) -> Self;
29
30 /// Sets the font weight of the label.
31 fn weight(self, weight: FontWeight) -> Self;
32
33 /// Sets the line height style of the label using a [`LineHeightStyle`].
34 fn line_height_style(self, line_height_style: LineHeightStyle) -> Self;
35
36 /// Sets the color of the label using a [`Color`].
37 fn color(self, color: Color) -> Self;
38
39 /// Sets the strikethrough property of the label.
40 fn strikethrough(self, strikethrough: bool) -> Self;
41
42 /// Sets the italic property of the label.
43 fn italic(self, italic: bool) -> Self;
44
45 /// Sets the underline property of the label
46 fn underline(self, underline: bool) -> Self;
47
48 /// Sets the alpha property of the label, overwriting the alpha value of the color.
49 fn alpha(self, alpha: f32) -> Self;
50}
51
52#[derive(IntoElement)]
53pub struct LabelLike {
54 pub(super) base: Div,
55 size: LabelSize,
56 weight: Option<FontWeight>,
57 line_height_style: LineHeightStyle,
58 pub(crate) color: Color,
59 strikethrough: bool,
60 italic: bool,
61 children: SmallVec<[AnyElement; 2]>,
62 alpha: Option<f32>,
63 underline: bool,
64}
65
66impl Default for LabelLike {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72impl LabelLike {
73 pub fn new() -> Self {
74 Self {
75 base: div(),
76 size: LabelSize::Default,
77 weight: None,
78 line_height_style: LineHeightStyle::default(),
79 color: Color::Default,
80 strikethrough: false,
81 italic: false,
82 children: SmallVec::new(),
83 alpha: None,
84 underline: false,
85 }
86 }
87}
88
89// Style methods.
90impl LabelLike {
91 fn style(&mut self) -> &mut StyleRefinement {
92 self.base.style()
93 }
94
95 gpui::margin_style_methods!({
96 visibility: pub
97 });
98}
99
100impl LabelCommon for LabelLike {
101 fn size(mut self, size: LabelSize) -> Self {
102 self.size = size;
103 self
104 }
105
106 fn weight(mut self, weight: FontWeight) -> Self {
107 self.weight = Some(weight);
108 self
109 }
110
111 fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
112 self.line_height_style = line_height_style;
113 self
114 }
115
116 fn color(mut self, color: Color) -> Self {
117 self.color = color;
118 self
119 }
120
121 fn strikethrough(mut self, strikethrough: bool) -> Self {
122 self.strikethrough = strikethrough;
123 self
124 }
125
126 fn italic(mut self, italic: bool) -> Self {
127 self.italic = italic;
128 self
129 }
130
131 fn underline(mut self, underline: bool) -> Self {
132 self.underline = underline;
133 self
134 }
135
136 fn alpha(mut self, alpha: f32) -> Self {
137 self.alpha = Some(alpha);
138 self
139 }
140}
141
142impl ParentElement for LabelLike {
143 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
144 self.children.extend(elements)
145 }
146}
147
148impl RenderOnce for LabelLike {
149 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
150 let settings = ThemeSettings::get_global(cx);
151
152 let mut color = self.color.color(cx);
153 if let Some(alpha) = self.alpha {
154 color.fade_out(1.0 - alpha);
155 }
156
157 self.base
158 .when(self.strikethrough, |this| {
159 this.relative().child(
160 div()
161 .absolute()
162 .top_1_2()
163 .w_full()
164 .h_px()
165 .bg(Color::Hidden.color(cx)),
166 )
167 })
168 .map(|this| match self.size {
169 LabelSize::Large => this.text_ui_lg(cx),
170 LabelSize::Default => this.text_ui(cx),
171 LabelSize::Small => this.text_ui_sm(cx),
172 LabelSize::XSmall => this.text_ui_xs(cx),
173 })
174 .when(self.line_height_style == LineHeightStyle::UiLabel, |this| {
175 this.line_height(relative(1.))
176 })
177 .when(self.italic, |this| this.italic())
178 .when(self.underline, |mut this| {
179 this.text_style()
180 .get_or_insert_with(Default::default)
181 .underline = Some(UnderlineStyle {
182 thickness: px(1.),
183 color: None,
184 wavy: false,
185 });
186 this
187 })
188 .text_color(color)
189 .font_weight(self.weight.unwrap_or(settings.ui_font.weight))
190 .children(self.children)
191 }
192}