label.rs

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