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