diff options
author | 2021-08-21 10:31:26 -0700 | |
---|---|---|
committer | 2021-08-21 10:31:26 -0700 | |
commit | aa63841e2c80ca8130adf41d25e5d731409b92f4 (patch) | |
tree | 4dab3f0405dc002a06f0e36ec40f2f74ff07212b /native | |
parent | 8333b8f88ceaa53c361eb6726b2b7dac6cd2c402 (diff) | |
download | iced-aa63841e2c80ca8130adf41d25e5d731409b92f4.tar.gz iced-aa63841e2c80ca8130adf41d25e5d731409b92f4.tar.bz2 iced-aa63841e2c80ca8130adf41d25e5d731409b92f4.zip |
Implement textual hit testing
Diffstat (limited to 'native')
-rw-r--r-- | native/src/lib.rs | 4 | ||||
-rw-r--r-- | native/src/renderer/null.rs | 16 | ||||
-rw-r--r-- | native/src/widget/text.rs | 21 | ||||
-rw-r--r-- | native/src/widget/text_input.rs | 70 |
4 files changed, 42 insertions, 69 deletions
diff --git a/native/src/lib.rs b/native/src/lib.rs index cbb02506..06bfd3c5 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -61,8 +61,8 @@ mod debug; mod debug; pub use iced_core::{ - menu, Align, Background, Color, Font, HorizontalAlignment, Length, Menu, - Padding, Point, Rectangle, Size, Vector, VerticalAlignment, + menu, Align, Background, Color, Font, HitTestResult, HorizontalAlignment, + Length, Menu, Padding, Point, Rectangle, Size, Vector, VerticalAlignment, }; pub use iced_futures::{executor, futures, Command}; diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index bb57c163..3ae05f10 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -1,8 +1,8 @@ use crate::{ button, checkbox, column, container, pane_grid, progress_bar, radio, row, scrollable, slider, text, text_input, toggler, Color, Element, Font, - HorizontalAlignment, Layout, Padding, Point, Rectangle, Renderer, Size, - VerticalAlignment, + HitTestResult, HorizontalAlignment, Layout, Padding, Point, Rectangle, + Renderer, Size, Vector, VerticalAlignment, }; /// A renderer that does nothing. @@ -67,6 +67,18 @@ impl text::Renderer for Null { (0.0, 20.0) } + fn hit_test( + &self, + _contents: &str, + _size: f32, + _font: Self::Font, + _bounds: Size, + _point: Point, + _nearest_only: bool, + ) -> HitTestResult { + HitTestResult::NearestCharOffset(0, Vector::new(0., 0.)) + } + fn draw( &mut self, _defaults: &Self::Defaults, diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs index 6cc18e6c..f37f90a9 100644 --- a/native/src/widget/text.rs +++ b/native/src/widget/text.rs @@ -1,7 +1,7 @@ //! Write some text for your users to read. use crate::{ - layout, Color, Element, Hasher, HorizontalAlignment, Layout, Length, Point, - Rectangle, Size, VerticalAlignment, Widget, + layout, Color, Element, Hasher, HitTestResult, HorizontalAlignment, Layout, + Length, Point, Rectangle, Size, VerticalAlignment, Widget, }; use std::hash::Hash; @@ -179,6 +179,23 @@ pub trait Renderer: crate::Renderer { bounds: Size, ) -> (f32, f32); + /// Tests whether the provided point is within the boundaries of [`Text`] + /// laid out with the given parameters, returning information about + /// the nearest character. + /// + /// If nearest_only is true, the hit test does not consider whether the + /// the point is interior to any glyph bounds, returning only the character + /// with the nearest centeroid. + fn hit_test( + &self, + contents: &str, + size: f32, + font: Self::Font, + bounds: Size, + point: Point, + nearest_only: bool, + ) -> HitTestResult; + /// Draws a [`Text`] fragment. /// /// It receives: diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index bb64d5b7..f1a7a1a0 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -707,15 +707,15 @@ pub trait Renderer: text::Renderer + Sized { let offset = self.offset(text_bounds, font, size, &value, &state); - find_cursor_position( - self, - &value, + self.hit_test( + &value.to_string(), + size.into(), font, - size, - x + offset, - 0, - value.len(), + Size::INFINITY, + Point::new(x + offset, text_bounds.height / 2.0), + true, ) + .cursor() } } @@ -803,62 +803,6 @@ impl State { } } -// TODO: Reduce allocations -fn find_cursor_position<Renderer: self::Renderer>( - renderer: &Renderer, - value: &Value, - font: Renderer::Font, - size: u16, - target: f32, - start: usize, - end: usize, -) -> usize { - if start >= end { - if start == 0 { - return 0; - } - - let prev = value.until(start - 1); - let next = value.until(start); - - let prev_width = renderer.measure_value(&prev.to_string(), size, font); - let next_width = renderer.measure_value(&next.to_string(), size, font); - - if next_width - target > target - prev_width { - return start - 1; - } else { - return start; - } - } - - let index = (end - start) / 2; - let subvalue = value.until(start + index); - - let width = renderer.measure_value(&subvalue.to_string(), size, font); - - if width > target { - find_cursor_position( - renderer, - value, - font, - size, - target, - start, - start + index, - ) - } else { - find_cursor_position( - renderer, - value, - font, - size, - target, - start + index + 1, - end, - ) - } -} - mod platform { use crate::keyboard; |