rgpui_component/plot/
label.rs1use std::fmt::Debug;
2
3use rgpui::{
4 App, Bounds, FontWeight, Hsla, Pixels, Point, ShapedLine, SharedString, TextAlign, TextRun,
5 Window, point, px,
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
14fn shape_label(
15 text: &SharedString,
16 font_size: Pixels,
17 color: Hsla,
18 window: &mut Window,
19) -> ShapedLine {
20 let text_run = TextRun {
21 len: text.len(),
22 font: window.text_style().font(),
23 color,
24 background_color: None,
25 underline: None,
26 strikethrough: None,
27 };
28 window
29 .text_system()
30 .shape_line(text.clone(), font_size, &[text_run], None)
31}
32
33pub fn measure_text_width(text: &SharedString, font_size: Pixels, window: &mut Window) -> f32 {
37 if text.is_empty() {
38 return 0.;
39 }
40 shape_label(
41 text,
42 font_size,
43 Hsla {
44 h: 0.,
45 s: 0.,
46 l: 0.,
47 a: 1.,
48 },
49 window,
50 )
51 .width()
52 .as_f32()
53}
54
55pub struct Text {
56 pub text: SharedString,
57 pub origin: Point<Pixels>,
58 pub color: Hsla,
59 pub font_size: Pixels,
60 pub font_weight: FontWeight,
61 pub align: TextAlign,
62}
63
64impl Text {
65 pub fn new<T>(text: impl Into<SharedString>, origin: Point<T>, color: Hsla) -> Self
66 where
67 T: Default + Clone + Copy + Debug + PartialEq + Into<Pixels>,
68 {
69 let origin = point(origin.x.into(), origin.y.into());
70
71 Self {
72 text: text.into(),
73 origin,
74 color,
75 font_size: TEXT_SIZE.into(),
76 font_weight: FontWeight::NORMAL,
77 align: TextAlign::Left,
78 }
79 }
80
81 pub fn font_size(mut self, font_size: impl Into<Pixels>) -> Self {
83 self.font_size = font_size.into();
84 self
85 }
86
87 pub fn font_weight(mut self, font_weight: FontWeight) -> Self {
89 self.font_weight = font_weight;
90 self
91 }
92
93 pub fn align(mut self, align: TextAlign) -> Self {
95 self.align = align;
96 self
97 }
98}
99
100impl<I> From<I> for PlotLabel
101where
102 I: Iterator<Item = Text>,
103{
104 fn from(items: I) -> Self {
105 Self::new(items.collect())
106 }
107}
108
109#[derive(Default)]
110pub struct PlotLabel(Vec<Text>);
111
112impl PlotLabel {
113 pub fn new(items: Vec<Text>) -> Self {
114 Self(items)
115 }
116
117 pub fn paint(&self, bounds: &Bounds<Pixels>, window: &mut Window, cx: &mut App) {
119 for Text {
120 text,
121 origin,
122 color,
123 font_size,
124 font_weight: _,
125 align,
126 } in self.0.iter()
127 {
128 let origin = origin_point(origin.x, origin.y, bounds.origin);
129
130 let line = shape_label(text, *font_size, *color, window);
131 let origin = match align {
132 TextAlign::Left => origin,
133 TextAlign::Right => origin - point(line.width(), px(0.)),
134 _ => origin - point(line.width() / 2., px(0.)),
135 };
136 let _ = line.paint(origin, *font_size, *align, None, window, cx);
137 }
138 }
139}