diff --git a/src/bin/test/main.rs b/src/bin/test/main.rs index 9e2f00e..36888b0 100644 --- a/src/bin/test/main.rs +++ b/src/bin/test/main.rs @@ -5,7 +5,10 @@ use input::Input; use iris::prelude::*; use len_fns::*; use render::Renderer; -use std::sync::Arc; +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; use winit::{ dpi::{LogicalPosition, LogicalSize}, event::{Ime, WindowEvent}, @@ -30,6 +33,7 @@ pub struct Client { focus: Option>, clipboard: Clipboard, ime: usize, + last_click: Instant, } #[derive(Eq, PartialEq, Hash, Clone)] @@ -50,10 +54,15 @@ impl WidgetAttr for Selectable { &id.clone(), CursorSense::click_or_drag(), move |client: &mut Client, data| { - client - .ui - .text(&id) - .select(data.cursor, data.size, data.sense.is_dragging()); + let now = Instant::now(); + let recent = (now - client.last_click) < Duration::from_millis(300); + client.last_click = now; + client.ui.text(&id).select( + data.cursor, + data.size, + data.sense.is_dragging(), + recent, + ); if let Some(region) = client.ui.window_region(&id) { client.window.set_ime_allowed(true); client.window.set_ime_cursor_area( @@ -249,16 +258,15 @@ impl Client { focus: None, clipboard: Clipboard::new().unwrap(), ime: 0, + last_click: Instant::now(), } } pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) { let input_changed = self.input.event(&event); let cursor_state = self.cursor_state().clone(); - if let Some(focus) = &self.focus - && cursor_state.buttons.left.is_start() - { - self.ui.text(focus).deselect(); + let old = self.focus.clone(); + if cursor_state.buttons.left.is_start() { self.focus = None; } if input_changed { @@ -266,6 +274,11 @@ impl Client { self.run_sensors(&cursor_state, window_size); self.ui.run_sensors(&cursor_state, window_size); } + if old != self.focus + && let Some(old) = old + { + self.ui.text(&old).deselect(); + } match event { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { diff --git a/src/core/text/edit.rs b/src/core/text/edit.rs index 600c7df..9546e62 100644 --- a/src/core/text/edit.rs +++ b/src/core/text/edit.rs @@ -163,10 +163,7 @@ impl<'a> TextEditCtx<'a> { pub fn motion(&mut self, motion: Motion) { if let TextSelection::Pos(cursor) = self.text.selection - && let Some((cursor, _)) = - self.text - .buf - .cursor_motion(self.font_system, cursor, None, motion) + && let Some(cursor) = self.buf_motion(cursor, motion) { self.text.selection = TextSelection::Pos(cursor); } else if let TextSelection::Span { start, end } = self.text.selection { @@ -275,11 +272,7 @@ impl<'a> TextEditCtx<'a> { { if word { let start = *cursor; - if let Some((end, _)) = - self.text - .buf - .cursor_motion(self.font_system, start, None, Motion::RightWord) - { + if let Some(end) = self.buf_motion(start, Motion::RightWord) { self.delete_between(start, end); } } else { @@ -303,7 +296,23 @@ impl<'a> TextEditCtx<'a> { } } - pub fn select(&mut self, pos: Vec2, size: Vec2, drag: bool) { + fn buf_motion(&mut self, cursor: Cursor, motion: Motion) -> Option { + self.text + .buf + .cursor_motion(self.font_system, cursor, None, motion) + .map(|r| r.0) + } + + pub fn select_word_at(&mut self, cursor: Cursor) { + if let (Some(start), Some(end)) = ( + self.buf_motion(cursor, Motion::LeftWord), + self.buf_motion(cursor, Motion::RightWord), + ) { + self.text.selection = TextSelection::Span { start, end }; + } + } + + pub fn select(&mut self, pos: Vec2, size: Vec2, drag: bool, recent: bool) { let pos = pos - self.text.region().top_left().to_abs(size); let hit = self.text.buf.hit(pos.x, pos.y); let sel = &mut self.text.selection; @@ -316,7 +325,13 @@ impl<'a> TextEditCtx<'a> { TextSelection::Pos(pos) => match (hit, drag) { (None, false) => *sel = TextSelection::None, (None, true) => (), - (Some(hit), false) => *pos = hit, + (Some(hit), false) => { + if recent && hit == *pos { + return self.select_word_at(hit); + } else { + *pos = hit + } + } (Some(end), true) => *sel = TextSelection::Span { start: *pos, end }, }, TextSelection::Span { start, end } => match (hit, drag) { diff --git a/src/layout/id.rs b/src/layout/id.rs index 64099ab..1746bba 100644 --- a/src/layout/id.rs +++ b/src/layout/id.rs @@ -33,6 +33,12 @@ pub struct WidgetId { _pd: PhantomData, } +impl PartialEq for WidgetId { + fn eq(&self, other: &Self) -> bool { + self.ty == other.ty && self.id == other.id + } +} + /// A WidgetId for a static widget that cannot be removed from a Ui. /// Useful because ergonomic clones don't exist yet so you can easily use these in closures. /// Do not use this if you want the widget to be freeable.