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, _window: &mut Window, cx: &mut App) -> impl IntoElement {
172        let mut color = self.color.color(cx);
173        if let Some(alpha) = self.alpha {
174            color.fade_out(1.0 - alpha);
175        }
176
177        self.base
178            .map(|this| match self.size {
179                LabelSize::Large => this.text_ui_lg(cx),
180                LabelSize::Default => this.text_ui(cx),
181                LabelSize::Small => this.text_ui_sm(cx),
182                LabelSize::XSmall => this.text_ui_xs(cx),
183            })
184            .when(self.line_height_style == LineHeightStyle::UiLabel, |this| {
185                this.line_height(relative(1.))
186            })
187            .when(self.italic, |this| this.italic())
188            .when(self.underline, |mut this| {
189                this.text_style()
190                    .get_or_insert_with(Default::default)
191                    .underline = Some(UnderlineStyle {
192                    thickness: px(1.),
193                    color: None,
194                    wavy: false,
195                });
196                this
197            })
198            .when(self.strikethrough, |this| this.line_through())
199            .when(self.single_line, |this| this.whitespace_nowrap())
200            .when(self.text_ellipsis, |this| {
201                this.overflow_x_hidden().text_ellipsis()
202            })
203            .text_color(color)
204            .font_weight(
205                self.weight
206                    .unwrap_or(ThemeSettings::get_global(cx).ui_font.weight),
207            )
208            .children(self.children)
209    }
210}