From 1a7a9f4e980be1edc5fcd27afb85d0bfbf524eed Mon Sep 17 00:00:00 2001 From: thewizzy <858086+thewizzy@users.noreply.github.com> Date: Tue, 28 Nov 2023 22:16:33 +1100 Subject: [PATCH] Support mouse selection and delete key on textbox (#206) * Support mouse selection and delete key on textbox * Fixed clippy and removed held state. --- src/views/text_input.rs | 90 ++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/src/views/text_input.rs b/src/views/text_input.rs index ec85c92a..26f9dbe5 100644 --- a/src/views/text_input.rs +++ b/src/views/text_input.rs @@ -334,6 +334,31 @@ impl TextInput { ) } + fn get_box_position(&self, pos_x: f64, pos_y: f64, cx: &mut EventCx) -> usize { + // Already focused - move cursor to click pos + let layout = cx.get_layout(self.id()).unwrap(); + let style = cx.app_state.get_builtin_style(self.id()); + + let padding_left = match style.padding_left() { + PxPct::Px(padding) => padding as f32, + PxPct::Pct(pct) => pct as f32 * layout.size.width, + }; + let padding_top = match style.padding_top() { + PxPct::Px(padding) => padding as f32, + PxPct::Pct(pct) => pct as f32 * layout.size.width, + }; + self.text_buf + .as_ref() + .unwrap() + .hit_point(Point::new( + pos_x + self.clip_start_x - padding_left as f64, + // TODO: prevent cursor incorrectly going to end of buffer when clicking + // slightly below the text + pos_y - padding_top as f64, + )) + .index + } + fn get_selection_rect(&self, node_layout: &Layout, left_padding: f64) -> Rect { let selection = if let Some(curr_selection) = &self.selection { curr_selection @@ -374,6 +399,20 @@ impl TextInput { tmp.size() } + fn update_selection(&mut self, selection_start: usize, selection_stop: usize) { + if selection_stop < selection_start { + self.selection = Some(Range { + start: selection_stop, + end: selection_start, + }); + } else { + self.selection = Some(Range { + start: selection_start, + end: selection_stop, + }); + } + } + fn update_text_layout(&mut self) { let mut text_layout = TextLayout::new(); let attrs_list = self.get_text_attrs(); @@ -605,6 +644,15 @@ impl TextInput { } } Key::Named(NamedKey::Delete) => { + let selection = self.selection.clone(); + if let Some(selection) = selection { + self.cursor_glyph_idx = selection.start; + self.buffer + .update(|buf| replace_range(buf, selection, None)); + self.selection = None; + return true; + } + let prev_cursor_idx = self.cursor_glyph_idx; if event.modifiers.contains(ModifiersState::CONTROL) { @@ -808,32 +856,28 @@ impl View for TextInput { // Just gained focus - move cursor to buff end self.cursor_glyph_idx = self.buffer.with_untracked(|buff| buff.len()); } else { - // Already focused - move cursor to click pos - let layout = cx.get_layout(self.id()).unwrap(); - let style = cx.app_state.get_builtin_style(self.id()); - - let padding_left = match style.padding_left() { - PxPct::Px(padding) => padding as f32, - PxPct::Pct(pct) => pct as f32 * layout.size.width, - }; - let padding_top = match style.padding_top() { - PxPct::Px(padding) => padding as f32, - PxPct::Pct(pct) => pct as f32 * layout.size.width, - }; - self.cursor_glyph_idx = self - .text_buf - .as_ref() - .unwrap() - .hit_point(Point::new( - event.pos.x + self.clip_start_x - padding_left as f64, - // TODO: prevent cursor incorrectly going to end of buffer when clicking - // slightly below the text - event.pos.y - padding_top as f64, - )) - .index; + cx.update_active(self.id()); + cx.app_state_mut().request_layout(self.id()); + self.selection = None; + self.cursor_glyph_idx = self.get_box_position(event.pos.x, event.pos.y, cx); + } + true + } + Event::PointerUp(event) => { + cx.app_state_mut().request_layout(self.id()); + if self.selection.is_some() { + self.cursor_glyph_idx = self.get_box_position(event.pos.x, event.pos.y, cx); } true } + Event::PointerMove(event) => { + cx.app_state_mut().request_layout(self.id()); + if cx.is_active(self.id()) { + let selection_stop = self.get_box_position(event.pos.x, event.pos.y, cx); + self.update_selection(self.cursor_glyph_idx, selection_stop); + } + false + } Event::KeyDown(event) => self.handle_key_down(cx, event), _ => false, };