diff options
Diffstat (limited to '')
| -rw-r--r-- | glow/src/backend.rs | 20 | ||||
| -rw-r--r-- | glow/src/text.rs | 94 | 
2 files changed, 113 insertions, 1 deletions
| diff --git a/glow/src/backend.rs b/glow/src/backend.rs index 1680fc00..37c0ac9d 100644 --- a/glow/src/backend.rs +++ b/glow/src/backend.rs @@ -2,6 +2,7 @@ use crate::quad;  use crate::text;  use crate::triangle;  use crate::{Settings, Transformation, Viewport}; +  use iced_graphics::backend;  use iced_graphics::font;  use iced_graphics::Layer; @@ -211,6 +212,25 @@ impl backend::Text for Backend {      ) -> (f32, f32) {          self.text_pipeline.measure(contents, size, font, bounds)      } + +    fn hit_test( +        &self, +        contents: &str, +        size: f32, +        font: Font, +        bounds: Size, +        point: iced_native::Point, +        nearest_only: bool, +    ) -> text::Hit { +        self.text_pipeline.hit_test( +            contents, +            size, +            font, +            bounds, +            point, +            nearest_only, +        ) +    }  }  #[cfg(feature = "image")] diff --git a/glow/src/text.rs b/glow/src/text.rs index a4c39dfe..d6915d92 100644 --- a/glow/src/text.rs +++ b/glow/src/text.rs @@ -1,8 +1,12 @@  use crate::Transformation; -use glow_glyph::ab_glyph; +  use iced_graphics::font; + +use glow_glyph::ab_glyph;  use std::{cell::RefCell, collections::HashMap}; +pub use iced_native::text::Hit; +  #[derive(Debug)]  pub struct Pipeline {      draw_brush: RefCell<glow_glyph::GlyphBrush>, @@ -109,6 +113,94 @@ impl Pipeline {          }      } +    pub fn hit_test( +        &self, +        content: &str, +        size: f32, +        font: iced_native::Font, +        bounds: iced_native::Size, +        point: iced_native::Point, +        nearest_only: bool, +    ) -> Hit { +        use glow_glyph::GlyphCruncher; + +        let glow_glyph::FontId(font_id) = self.find_font(font); + +        let section = glow_glyph::Section { +            bounds: (bounds.width, bounds.height), +            text: vec![glow_glyph::Text { +                text: content, +                scale: size.into(), +                font_id: glow_glyph::FontId(font_id), +                extra: glow_glyph::Extra::default(), +            }], +            ..Default::default() +        }; + +        let mut mb = self.measure_brush.borrow_mut(); + +        // The underlying type is FontArc, so clones are cheap. +        use ab_glyph::{Font, ScaleFont}; +        let font = mb.fonts()[font_id].clone().into_scaled(size); + +        // Implements an iterator over the glyph bounding boxes. +        let bounds = mb.glyphs(section).map( +            |glow_glyph::SectionGlyph { +                 byte_index, glyph, .. +             }| { +                ( +                    *byte_index, +                    iced_native::Rectangle::new( +                        iced_native::Point::new( +                            glyph.position.x - font.h_side_bearing(glyph.id), +                            glyph.position.y - font.ascent(), +                        ), +                        iced_native::Size::new( +                            font.h_advance(glyph.id), +                            font.ascent() - font.descent(), +                        ), +                    ), +                ) +            }, +        ); + +        // Implements computation of the character index based on the byte index +        // within the input string. +        let char_index = |byte_index| { +            let mut b_count = 0; +            for (i, utf8_len) in +                content.chars().map(|c| c.len_utf8()).enumerate() +            { +                if byte_index < (b_count + utf8_len) { +                    return i; +                } +                b_count += utf8_len; +            } +            return byte_index; +        }; + +        if !nearest_only { +            for (idx, bounds) in bounds.clone() { +                if bounds.contains(point) { +                    return Hit::CharOffset(char_index(idx)); +                } +            } +        } + +        let (idx, nearest) = bounds.fold( +            (0usize, iced_native::Point::ORIGIN), +            |acc: (usize, iced_native::Point), (idx, bounds)| { +                if bounds.center().distance(point) < acc.1.distance(point) { +                    (idx, bounds.center()) +                } else { +                    acc +                } +            }, +        ); + +        Hit::NearestCharOffset(char_index(idx), (point - nearest).into()) +    } +      pub fn trim_measurement_cache(&mut self) {          // TODO: We should probably use a `GlyphCalculator` for this. However,          // it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop. | 
