label.rs

  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}