diff options
| author | 2019-12-05 03:09:39 +0100 | |
|---|---|---|
| committer | 2019-12-05 03:09:39 +0100 | |
| commit | 14fb7e13fb272a43b9924d5d2823b0c105d781b0 (patch) | |
| tree | cbc9a7acc00e96179c9dfb99da10db8e72490d10 /native/src/widget | |
| parent | e92ea48e8814b42fc566017db085ca9bdaf3c272 (diff) | |
| download | iced-14fb7e13fb272a43b9924d5d2823b0c105d781b0.tar.gz iced-14fb7e13fb272a43b9924d5d2823b0c105d781b0.tar.bz2 iced-14fb7e13fb272a43b9924d5d2823b0c105d781b0.zip  | |
Place `TextInput` cursor position on click
Diffstat (limited to '')
| -rw-r--r-- | native/src/widget/text_input.rs | 78 | 
1 files changed, 75 insertions, 3 deletions
diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index f97ed424..764f87cf 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -160,7 +160,7 @@ where          layout: Layout<'_>,          cursor_position: Point,          messages: &mut Vec<Message>, -        _renderer: &Renderer, +        renderer: &Renderer,      ) {          match event {              Event::Mouse(mouse::Event::Input { @@ -170,8 +170,22 @@ where                  self.state.is_focused =                      layout.bounds().contains(cursor_position); -                if self.state.cursor_position(&self.value) == 0 { -                    self.state.move_cursor_to_end(&self.value); +                if self.state.is_focused { +                    let text_layout = layout.children().next().unwrap(); +                    let target = cursor_position.x - text_layout.bounds().x; + +                    if target < 0.0 { +                        self.state.cursor_position = 0; +                    } else { +                        self.state.cursor_position = find_cursor_position( +                            renderer, +                            target, +                            &self.value, +                            self.size.unwrap_or(renderer.default_size()), +                            0, +                            self.value.len(), +                        ); +                    }                  }              }              Event::Keyboard(keyboard::Event::CharacterReceived(c)) @@ -275,6 +289,11 @@ pub trait Renderer: crate::Renderer + Sized {      /// [`TextInput`]: struct.TextInput.html      fn default_size(&self) -> u16; +    /// Returns the width of the value of the [`TextInput`]. +    /// +    /// [`TextInput`]: struct.TextInput.html +    fn measure_value(&self, value: &str, size: u16) -> f32; +      /// Draws a [`TextInput`].      ///      /// It receives: @@ -437,3 +456,56 @@ impl Value {          let _ = self.0.remove(index);      }  } + +// TODO: Reduce allocations +fn find_cursor_position<Renderer: self::Renderer>( +    renderer: &Renderer, +    target: f32, +    value: &Value, +    size: u16, +    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); +        let next_width = renderer.measure_value(&next.to_string(), size); + +        if (target - next_width).abs() > (target - prev_width).abs() { +            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); + +    if width > target { +        find_cursor_position( +            renderer, +            target, +            value, +            size, +            start, +            start + index, +        ) +    } else { +        find_cursor_position( +            renderer, +            target, +            value, +            size, +            start + index + 1, +            end, +        ) +    } +}  | 
