Merge pull request #670 from twitchyliquid64/text_backend
Refactor textual hit testing into a `renderer::Backend` method
This commit is contained in:
commit
6821114cae
13 changed files with 335 additions and 69 deletions
|
|
@ -2,6 +2,7 @@ use crate::quad;
|
|||
use crate::text;
|
||||
use crate::triangle;
|
||||
use crate::{Settings, Transformation};
|
||||
|
||||
use iced_graphics::backend;
|
||||
use iced_graphics::font;
|
||||
use iced_graphics::layer::Layer;
|
||||
|
|
@ -274,6 +275,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_rs")]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
use crate::Transformation;
|
||||
|
||||
use iced_graphics::font;
|
||||
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
use wgpu_glyph::ab_glyph;
|
||||
|
||||
pub use iced_native::text::Hit;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pipeline {
|
||||
draw_brush: RefCell<wgpu_glyph::GlyphBrush<()>>,
|
||||
|
|
@ -117,6 +121,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 wgpu_glyph::GlyphCruncher;
|
||||
|
||||
let wgpu_glyph::FontId(font_id) = self.find_font(font);
|
||||
|
||||
let section = wgpu_glyph::Section {
|
||||
bounds: (bounds.width, bounds.height),
|
||||
text: vec![wgpu_glyph::Text {
|
||||
text: content,
|
||||
scale: size.into(),
|
||||
font_id: wgpu_glyph::FontId(font_id),
|
||||
extra: wgpu_glyph::Extra::default(),
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut mb = self.measure_brush.borrow_mut();
|
||||
|
||||
// The underlying type is FontArc, so clones are cheap.
|
||||
use wgpu_glyph::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(
|
||||
|wgpu_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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue