label_like.rs

  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}