1use gpui::{relative, AnyElement, FontWeight, StyleRefinement, Styled};
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 alpha property of the label, overwriting the alpha value of the color.
46 fn alpha(self, alpha: f32) -> Self;
47}
48
49#[derive(IntoElement)]
50pub struct LabelLike {
51 pub(super) base: Div,
52 size: LabelSize,
53 weight: Option<FontWeight>,
54 line_height_style: LineHeightStyle,
55 pub(crate) color: Color,
56 strikethrough: bool,
57 italic: bool,
58 children: SmallVec<[AnyElement; 2]>,
59 alpha: Option<f32>,
60}
61
62impl LabelLike {
63 pub fn new() -> Self {
64 Self {
65 base: div(),
66 size: LabelSize::Default,
67 weight: None,
68 line_height_style: LineHeightStyle::default(),
69 color: Color::Default,
70 strikethrough: false,
71 italic: false,
72 children: SmallVec::new(),
73 alpha: None,
74 }
75 }
76}
77
78// Style methods.
79impl LabelLike {
80 fn style(&mut self) -> &mut StyleRefinement {
81 self.base.style()
82 }
83
84 gpui::margin_style_methods!({
85 visibility: pub
86 });
87}
88
89impl LabelCommon for LabelLike {
90 fn size(mut self, size: LabelSize) -> Self {
91 self.size = size;
92 self
93 }
94
95 fn weight(mut self, weight: FontWeight) -> Self {
96 self.weight = Some(weight);
97 self
98 }
99
100 fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
101 self.line_height_style = line_height_style;
102 self
103 }
104
105 fn color(mut self, color: Color) -> Self {
106 self.color = color;
107 self
108 }
109
110 fn strikethrough(mut self, strikethrough: bool) -> Self {
111 self.strikethrough = strikethrough;
112 self
113 }
114
115 fn italic(mut self, italic: bool) -> Self {
116 self.italic = italic;
117 self
118 }
119
120 fn alpha(mut self, alpha: f32) -> Self {
121 self.alpha = Some(alpha);
122 self
123 }
124}
125
126impl ParentElement for LabelLike {
127 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
128 self.children.extend(elements)
129 }
130}
131
132impl RenderOnce for LabelLike {
133 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
134 let settings = ThemeSettings::get_global(cx);
135
136 let mut color = self.color.color(cx);
137 if let Some(alpha) = self.alpha {
138 color.fade_out(1.0 - alpha);
139 }
140
141 self.base
142 .when(self.strikethrough, |this| {
143 this.relative().child(
144 div()
145 .absolute()
146 .top_1_2()
147 .w_full()
148 .h_px()
149 .bg(Color::Hidden.color(cx)),
150 )
151 })
152 .map(|this| match self.size {
153 LabelSize::Large => this.text_ui_lg(cx),
154 LabelSize::Default => this.text_ui(cx),
155 LabelSize::Small => this.text_ui_sm(cx),
156 LabelSize::XSmall => this.text_ui_xs(cx),
157 })
158 .when(self.line_height_style == LineHeightStyle::UiLabel, |this| {
159 this.line_height(relative(1.))
160 })
161 .when(self.italic, |this| this.italic())
162 .text_color(color)
163 .font_weight(self.weight.unwrap_or(settings.ui_font.weight))
164 .children(self.children)
165 }
166}