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