1use crate::{
2 color::ColorU,
3 fonts::{FamilyId, Properties},
4 geometry::vector::{vec2f, Vector2F},
5 AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, MutableAppContext,
6 PaintContext, SizeConstraint,
7};
8use std::{ops::Range, sync::Arc};
9
10pub struct Label {
11 text: String,
12 family_id: FamilyId,
13 font_properties: Properties,
14 font_size: f32,
15 highlights: Option<Highlights>,
16 layout_line: Option<Arc<Line>>,
17 colors: Option<Vec<(Range<usize>, ColorU)>>,
18 size: Option<Vector2F>,
19}
20
21pub struct Highlights {
22 color: ColorU,
23 indices: Vec<usize>,
24 font_properties: Properties,
25}
26
27impl Label {
28 pub fn new(text: String, family_id: FamilyId, font_size: f32) -> Self {
29 Self {
30 text,
31 family_id,
32 font_properties: Properties::new(),
33 font_size,
34 highlights: None,
35 layout_line: None,
36 colors: None,
37 size: None,
38 }
39 }
40
41 pub fn with_highlights(
42 mut self,
43 color: ColorU,
44 font_properties: Properties,
45 indices: Vec<usize>,
46 ) -> Self {
47 self.highlights = Some(Highlights {
48 color,
49 font_properties,
50 indices,
51 });
52 self
53 }
54}
55
56impl Element for Label {
57 fn layout(
58 &mut self,
59 constraint: SizeConstraint,
60 ctx: &mut LayoutContext,
61 _: &AppContext,
62 ) -> Vector2F {
63 let font_id = ctx
64 .font_cache
65 .select_font(self.family_id, &self.font_properties)
66 .unwrap();
67 let text_len = self.text.chars().count();
68 let mut styles;
69 let mut colors;
70 if let Some(highlights) = self.highlights.as_ref() {
71 styles = Vec::new();
72 colors = Vec::new();
73 let highlight_font_id = ctx
74 .font_cache
75 .select_font(self.family_id, &highlights.font_properties)
76 .unwrap_or(font_id);
77 let mut pending_highlight: Option<Range<usize>> = None;
78 for ix in &highlights.indices {
79 if let Some(pending_highlight) = pending_highlight.as_mut() {
80 if *ix == pending_highlight.end {
81 pending_highlight.end += 1;
82 } else {
83 styles.push((pending_highlight.clone(), highlight_font_id));
84 colors.push((pending_highlight.clone(), highlights.color));
85 styles.push((pending_highlight.end..*ix, font_id));
86 colors.push((pending_highlight.end..*ix, ColorU::black()));
87 *pending_highlight = *ix..*ix + 1;
88 }
89 } else {
90 styles.push((0..*ix, font_id));
91 colors.push((0..*ix, ColorU::black()));
92 pending_highlight = Some(*ix..*ix + 1);
93 }
94 }
95 if let Some(pending_highlight) = pending_highlight.as_mut() {
96 styles.push((pending_highlight.clone(), highlight_font_id));
97 colors.push((pending_highlight.clone(), highlights.color));
98 if text_len > pending_highlight.end {
99 styles.push((pending_highlight.end..text_len, font_id));
100 colors.push((pending_highlight.end..text_len, ColorU::black()));
101 }
102 } else {
103 styles.push((0..text_len, font_id));
104 colors.push((0..text_len, ColorU::black()));
105 }
106 } else {
107 styles = vec![(0..text_len, font_id)];
108 colors = vec![(0..text_len, ColorU::black())];
109 }
110
111 self.colors = Some(colors);
112
113 let layout_line = ctx.text_layout_cache.layout_str(
114 self.text.as_str(),
115 self.font_size,
116 styles.as_slice(),
117 ctx.font_cache,
118 );
119
120 let size = vec2f(
121 layout_line
122 .width
123 .max(constraint.min.x())
124 .min(constraint.max.x()),
125 ctx.font_cache.line_height(font_id, self.font_size).ceil(),
126 );
127
128 self.layout_line = Some(layout_line);
129 self.size = Some(size);
130
131 size
132 }
133
134 fn after_layout(&mut self, _: &mut AfterLayoutContext, _: &mut MutableAppContext) {}
135
136 fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, _: &AppContext) {
137 // ctx.canvas.set_fill_style(FillStyle::Color(ColorU::black()));
138 // self.layout_line.as_ref().unwrap().paint(
139 // origin,
140 // RectF::new(origin, self.size.unwrap()),
141 // self.colors.as_ref().unwrap(),
142 // ctx.canvas,
143 // ctx.font_cache,
144 // );
145 }
146
147 fn size(&self) -> Option<Vector2F> {
148 self.size
149 }
150
151 fn dispatch_event(&self, _: &Event, _: &mut EventContext, _: &AppContext) -> bool {
152 false
153 }
154}