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    /// Truncates overflowing text with an ellipsis (`…`) if needed.
 54    fn text_ellipsis(self) -> Self;
 55
 56    /// Sets the label to render as a single line.
 57    fn single_line(self) -> Self;
 58}
 59
 60#[derive(IntoElement)]
 61pub struct LabelLike {
 62    pub(super) base: Div,
 63    size: LabelSize,
 64    weight: Option<FontWeight>,
 65    line_height_style: LineHeightStyle,
 66    pub(crate) color: Color,
 67    strikethrough: bool,
 68    italic: bool,
 69    children: SmallVec<[AnyElement; 2]>,
 70    alpha: Option<f32>,
 71    underline: bool,
 72    single_line: bool,
 73    text_ellipsis: bool,
 74}
 75
 76impl Default for LabelLike {
 77    fn default() -> Self {
 78        Self::new()
 79    }
 80}
 81
 82impl LabelLike {
 83    pub fn new() -> Self {
 84        Self {
 85            base: div(),
 86            size: LabelSize::Default,
 87            weight: None,
 88            line_height_style: LineHeightStyle::default(),
 89            color: Color::Default,
 90            strikethrough: false,
 91            italic: false,
 92            children: SmallVec::new(),
 93            alpha: None,
 94            underline: false,
 95            single_line: false,
 96            text_ellipsis: false,
 97        }
 98    }
 99}
100
101// Style methods.
102impl LabelLike {
103    fn style(&mut self) -> &mut StyleRefinement {
104        self.base.style()
105    }
106
107    gpui::margin_style_methods!({
108        visibility: pub
109    });
110}
111
112impl LabelCommon for LabelLike {
113    fn size(mut self, size: LabelSize) -> Self {
114        self.size = size;
115        self
116    }
117
118    fn weight(mut self, weight: FontWeight) -> Self {
119        self.weight = Some(weight);
120        self
121    }
122
123    fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
124        self.line_height_style = line_height_style;
125        self
126    }
127
128    fn color(mut self, color: Color) -> Self {
129        self.color = color;
130        self
131    }
132
133    fn strikethrough(mut self, strikethrough: bool) -> Self {
134        self.strikethrough = strikethrough;
135        self
136    }
137
138    fn italic(mut self, italic: bool) -> Self {
139        self.italic = italic;
140        self
141    }
142
143    fn underline(mut self, underline: bool) -> Self {
144        self.underline = underline;
145        self
146    }
147
148    fn alpha(mut self, alpha: f32) -> Self {
149        self.alpha = Some(alpha);
150        self
151    }
152
153    fn text_ellipsis(mut self) -> Self {
154        self.text_ellipsis = true;
155        self
156    }
157
158    fn single_line(mut self) -> Self {
159        self.single_line = true;
160        self
161    }
162}
163
164impl ParentElement for LabelLike {
165    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
166        self.children.extend(elements)
167    }
168}
169
170impl RenderOnce for LabelLike {
171    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
172        let settings = ThemeSettings::get_global(cx);
173
174        let mut color = self.color.color(cx);
175        if let Some(alpha) = self.alpha {
176            color.fade_out(1.0 - alpha);
177        }
178
179        self.base
180            .map(|this| match self.size {
181                LabelSize::Large => this.text_ui_lg(cx),
182                LabelSize::Default => this.text_ui(cx),
183                LabelSize::Small => this.text_ui_sm(cx),
184                LabelSize::XSmall => this.text_ui_xs(cx),
185            })
186            .when(self.line_height_style == LineHeightStyle::UiLabel, |this| {
187                this.line_height(relative(1.))
188            })
189            .when(self.italic, |this| this.italic())
190            .when(self.underline, |mut this| {
191                this.text_style()
192                    .get_or_insert_with(Default::default)
193                    .underline = Some(UnderlineStyle {
194                    thickness: px(1.),
195                    color: None,
196                    wavy: false,
197                });
198                this
199            })
200            .when(self.strikethrough, |this| this.line_through())
201            .when(self.single_line, |this| this.whitespace_nowrap())
202            .when(self.text_ellipsis, |this| {
203                this.overflow_x_hidden().text_ellipsis()
204            })
205            .text_color(color)
206            .font_weight(self.weight.unwrap_or(settings.ui_font.weight))
207            .children(self.children)
208    }
209}