gpui_component/plot/
label.rs

1use std::fmt::Debug;
2
3use gpui::{
4    point, px, App, Bounds, FontWeight, Hsla, Pixels, Point, SharedString, TextAlign, TextRun,
5    Window,
6};
7
8use super::origin_point;
9
10pub const TEXT_SIZE: f32 = 10.;
11pub const TEXT_GAP: f32 = 2.;
12pub const TEXT_HEIGHT: f32 = TEXT_SIZE + TEXT_GAP;
13
14pub struct Text {
15    pub text: SharedString,
16    pub origin: Point<Pixels>,
17    pub color: Hsla,
18    pub font_size: Pixels,
19    pub font_weight: FontWeight,
20    pub align: TextAlign,
21}
22
23impl Text {
24    pub fn new<T>(text: impl Into<SharedString>, origin: Point<T>, color: Hsla) -> Self
25    where
26        T: Default + Clone + Copy + Debug + PartialEq + Into<Pixels>,
27    {
28        let origin = point(origin.x.into(), origin.y.into());
29
30        Self {
31            text: text.into(),
32            origin,
33            color,
34            font_size: TEXT_SIZE.into(),
35            font_weight: FontWeight::NORMAL,
36            align: TextAlign::Left,
37        }
38    }
39
40    /// Set the font size of the Text.
41    pub fn font_size(mut self, font_size: impl Into<Pixels>) -> Self {
42        self.font_size = font_size.into();
43        self
44    }
45
46    /// Set the font weight of the Text.
47    pub fn font_weight(mut self, font_weight: FontWeight) -> Self {
48        self.font_weight = font_weight;
49        self
50    }
51
52    /// Set the alignment of the Text.
53    pub fn align(mut self, align: TextAlign) -> Self {
54        self.align = align;
55        self
56    }
57}
58
59impl<I> From<I> for Label
60where
61    I: Iterator<Item = Text>,
62{
63    fn from(items: I) -> Self {
64        Self::new(items.collect())
65    }
66}
67
68#[derive(Default)]
69pub struct Label(Vec<Text>);
70
71impl Label {
72    pub fn new(items: Vec<Text>) -> Self {
73        Self(items)
74    }
75
76    /// Paint the Label.
77    pub fn paint(&self, bounds: &Bounds<Pixels>, window: &mut Window, cx: &mut App) {
78        for Text {
79            text,
80            origin,
81            color,
82            font_size,
83            font_weight,
84            align,
85        } in self.0.iter()
86        {
87            let origin = origin_point(origin.x, origin.y, bounds.origin);
88
89            let text_run = TextRun {
90                len: text.len(),
91                font: window.text_style().highlight(*font_weight).font(),
92                color: *color,
93                background_color: None,
94                underline: None,
95                strikethrough: None,
96            };
97
98            if let Ok(text) =
99                window
100                    .text_system()
101                    .shape_text(text.clone(), *font_size, &[text_run], None, None)
102            {
103                for line in text {
104                    let origin = match align {
105                        TextAlign::Left => origin,
106                        TextAlign::Right => origin - point(line.size(*font_size).width, px(0.)),
107                        _ => origin - point(line.size(*font_size).width / 2., px(0.)),
108                    };
109
110                    let _ = line.paint(origin, *font_size, *align, None, window, cx);
111                }
112            }
113        }
114    }
115}