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 /// Sets the label to render as a single line.
54 fn single_line(self) -> Self;
55}
56
57#[derive(IntoElement)]
58pub struct LabelLike {
59 pub(super) base: Div,
60 size: LabelSize,
61 weight: Option<FontWeight>,
62 line_height_style: LineHeightStyle,
63 pub(crate) color: Color,
64 strikethrough: bool,
65 italic: bool,
66 children: SmallVec<[AnyElement; 2]>,
67 alpha: Option<f32>,
68 underline: bool,
69 single_line: bool,
70}
71
72impl Default for LabelLike {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl LabelLike {
79 pub fn new() -> Self {
80 Self {
81 base: div(),
82 size: LabelSize::Default,
83 weight: None,
84 line_height_style: LineHeightStyle::default(),
85 color: Color::Default,
86 strikethrough: false,
87 italic: false,
88 children: SmallVec::new(),
89 alpha: None,
90 underline: false,
91 single_line: false,
92 }
93 }
94}
95
96// Style methods.
97impl LabelLike {
98 fn style(&mut self) -> &mut StyleRefinement {
99 self.base.style()
100 }
101
102 gpui::margin_style_methods!({
103 visibility: pub
104 });
105}
106
107impl LabelCommon for LabelLike {
108 fn size(mut self, size: LabelSize) -> Self {
109 self.size = size;
110 self
111 }
112
113 fn weight(mut self, weight: FontWeight) -> Self {
114 self.weight = Some(weight);
115 self
116 }
117
118 fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
119 self.line_height_style = line_height_style;
120 self
121 }
122
123 fn color(mut self, color: Color) -> Self {
124 self.color = color;
125 self
126 }
127
128 fn strikethrough(mut self, strikethrough: bool) -> Self {
129 self.strikethrough = strikethrough;
130 self
131 }
132
133 fn italic(mut self, italic: bool) -> Self {
134 self.italic = italic;
135 self
136 }
137
138 fn underline(mut self, underline: bool) -> Self {
139 self.underline = underline;
140 self
141 }
142
143 fn alpha(mut self, alpha: f32) -> Self {
144 self.alpha = Some(alpha);
145 self
146 }
147
148 fn single_line(mut self) -> Self {
149 self.single_line = true;
150 self
151 }
152}
153
154impl ParentElement for LabelLike {
155 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
156 self.children.extend(elements)
157 }
158}
159
160impl RenderOnce for LabelLike {
161 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
162 let settings = ThemeSettings::get_global(cx);
163
164 let mut color = self.color.color(cx);
165 if let Some(alpha) = self.alpha {
166 color.fade_out(1.0 - alpha);
167 }
168
169 self.base
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 .when(self.strikethrough, |this| this.line_through())
191 .when(self.single_line, |this| this.whitespace_nowrap())
192 .text_color(color)
193 .font_weight(self.weight.unwrap_or(settings.ui_font.weight))
194 .children(self.children)
195 }
196}