label_like.rs

  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}