diff options
Diffstat (limited to 'native/src/widget')
-rw-r--r-- | native/src/widget/button.rs | 5 | ||||
-rw-r--r-- | native/src/widget/checkbox.rs | 3 | ||||
-rw-r--r-- | native/src/widget/column.rs | 5 | ||||
-rw-r--r-- | native/src/widget/container.rs | 5 | ||||
-rw-r--r-- | native/src/widget/radio.rs | 3 | ||||
-rw-r--r-- | native/src/widget/row.rs | 5 | ||||
-rw-r--r-- | native/src/widget/scrollable.rs | 6 | ||||
-rw-r--r-- | native/src/widget/slider.rs | 5 | ||||
-rw-r--r-- | native/src/widget/text_input.rs | 110 |
9 files changed, 116 insertions, 31 deletions
diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index 67b49dc6..2881105f 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -6,8 +6,8 @@ //! [`State`]: struct.State.html use crate::{ input::{mouse, ButtonState}, - layout, Background, Element, Event, Hasher, Layout, Length, Point, - Rectangle, Widget, + layout, Background, Clipboard, Element, Event, Hasher, Layout, Length, + Point, Rectangle, Widget, }; use std::hash::Hash; @@ -192,6 +192,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, ) { match event { Event::Mouse(mouse::Event::Input { diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index ca4410b9..0dcac712 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -3,7 +3,7 @@ use std::hash::Hash; use crate::{ input::{mouse, ButtonState}, - layout, row, text, Align, Color, Element, Event, Font, Hasher, + layout, row, text, Align, Clipboard, Color, Element, Event, Font, Hasher, HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text, VerticalAlignment, Widget, }; @@ -114,6 +114,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, ) { match event { Event::Mouse(mouse::Event::Input { diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index cdcf25af..4b5d631c 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -2,7 +2,8 @@ use std::hash::Hash; use crate::{ - layout, Align, Element, Event, Hasher, Layout, Length, Point, Widget, + layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, + Widget, }; use std::u32; @@ -153,6 +154,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, renderer: &Renderer, + clipboard: Option<&dyn Clipboard>, ) { self.children.iter_mut().zip(layout.children()).for_each( |(child, layout)| { @@ -162,6 +164,7 @@ where cursor_position, messages, renderer, + clipboard, ) }, ); diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 7852eecf..74f0e0ef 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -2,7 +2,8 @@ use std::hash::Hash; use crate::{ - layout, Align, Element, Event, Hasher, Layout, Length, Point, Widget, + layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, + Widget, }; use std::u32; @@ -131,6 +132,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, renderer: &Renderer, + clipboard: Option<&dyn Clipboard>, ) { self.content.widget.on_event( event, @@ -138,6 +140,7 @@ where cursor_position, messages, renderer, + clipboard, ) } diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index a9d145db..a9995b86 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -1,7 +1,7 @@ //! Create choices using radio buttons. use crate::{ input::{mouse, ButtonState}, - layout, row, text, Align, Color, Element, Event, Font, Hasher, + layout, row, text, Align, Clipboard, Color, Element, Event, Font, Hasher, HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text, VerticalAlignment, Widget, }; @@ -113,6 +113,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, ) { match event { Event::Mouse(mouse::Event::Input { diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs index c854aff7..3de65deb 100644 --- a/native/src/widget/row.rs +++ b/native/src/widget/row.rs @@ -2,7 +2,8 @@ use std::hash::Hash; use crate::{ - layout, Align, Element, Event, Hasher, Layout, Length, Point, Widget, + layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, + Widget, }; use std::u32; @@ -154,6 +155,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, renderer: &Renderer, + clipboard: Option<&dyn Clipboard>, ) { self.children.iter_mut().zip(layout.children()).for_each( |(child, layout)| { @@ -163,6 +165,7 @@ where cursor_position, messages, renderer, + clipboard, ) }, ); diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 3c2625b7..872c59cb 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -2,8 +2,8 @@ use crate::{ column, input::{mouse, ButtonState}, - layout, Align, Column, Element, Event, Hasher, Layout, Length, Point, - Rectangle, Size, Widget, + layout, Align, Clipboard, Column, Element, Event, Hasher, Layout, Length, + Point, Rectangle, Size, Widget, }; use std::{f32, hash::Hash, u32}; @@ -143,6 +143,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, renderer: &Renderer, + clipboard: Option<&dyn Clipboard>, ) { let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); @@ -247,6 +248,7 @@ where cursor_position, messages, renderer, + clipboard, ) } diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index f07ea7cd..f446f7e8 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -6,8 +6,8 @@ //! [`State`]: struct.State.html use crate::{ input::{mouse, ButtonState}, - layout, Element, Event, Hasher, Layout, Length, Point, Rectangle, Size, - Widget, + layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, + Rectangle, Size, Widget, }; use std::{hash::Hash, ops::RangeInclusive}; @@ -133,6 +133,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, ) { let mut change = || { let bounds = layout.bounds(); diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index f0bb9f87..71e3d75a 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -6,8 +6,8 @@ //! [`State`]: struct.State.html use crate::{ input::{keyboard, mouse, ButtonState}, - layout, Element, Event, Hasher, Layout, Length, Point, Rectangle, Size, - Widget, + layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, + Rectangle, Size, Widget, }; use unicode_segmentation::UnicodeSegmentation; @@ -172,6 +172,7 @@ where cursor_position: Point, messages: &mut Vec<Message>, renderer: &Renderer, + clipboard: Option<&dyn Clipboard>, ) { match event { Event::Mouse(mouse::Event::Input { @@ -209,7 +210,9 @@ where } } Event::Keyboard(keyboard::Event::CharacterReceived(c)) - if self.state.is_focused && !c.is_control() => + if self.state.is_focused + && self.state.is_pasting.is_none() + && !c.is_control() => { let cursor_position = self.state.cursor_position(&self.value); @@ -254,26 +257,18 @@ where } } keyboard::KeyCode::Left => { - let jump_modifier_pressed = if cfg!(target_os = "macos") { - modifiers.alt - } else { - modifiers.control - }; - - if jump_modifier_pressed && !self.is_secure { + if platform::is_jump_modifier_pressed(modifiers) + && !self.is_secure + { self.state.move_cursor_left_by_words(&self.value); } else { self.state.move_cursor_left(&self.value); } } keyboard::KeyCode::Right => { - let jump_modifier_pressed = if cfg!(target_os = "macos") { - modifiers.alt - } else { - modifiers.control - }; - - if jump_modifier_pressed && !self.is_secure { + if platform::is_jump_modifier_pressed(modifiers) + && !self.is_secure + { self.state.move_cursor_right_by_words(&self.value); } else { self.state.move_cursor_right(&self.value); @@ -285,6 +280,50 @@ where keyboard::KeyCode::End => { self.state.move_cursor_to_end(&self.value); } + keyboard::KeyCode::V => { + if platform::is_copy_paste_modifier_pressed(modifiers) { + if let Some(clipboard) = clipboard { + let content = match self.state.is_pasting.take() { + Some(content) => content, + None => { + let content: String = clipboard + .content() + .unwrap_or(String::new()) + .chars() + .filter(|c| !c.is_control()) + .collect(); + + Value::new(&content) + } + }; + + let cursor_position = + self.state.cursor_position(&self.value); + + self.value + .insert_many(cursor_position, content.clone()); + + self.state.cursor_position += content.len(); + self.state.is_pasting = Some(content); + + let message = + (self.on_change)(self.value.to_string()); + messages.push(message); + } + } else { + self.state.is_pasting = None; + } + } + _ => {} + }, + Event::Keyboard(keyboard::Event::Input { + key_code, + state: ButtonState::Released, + .. + }) => match key_code { + keyboard::KeyCode::V => { + self.state.is_pasting = None; + } _ => {} }, _ => {} @@ -397,6 +436,7 @@ where #[derive(Debug, Default, Clone)] pub struct State { is_focused: bool, + is_pasting: Option<Value>, cursor_position: usize, } @@ -416,6 +456,7 @@ impl State { Self { is_focused: true, + is_pasting: None, cursor_position: usize::MAX, } } @@ -486,7 +527,7 @@ impl State { /// /// [`TextInput`]: struct.TextInput.html // TODO: Reduce allocations, cache results (?) -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Value { graphemes: Vec<String>, } @@ -573,8 +614,6 @@ impl Value { } /// Inserts a new `char` at the given grapheme `index`. - /// - /// [`Value`]: struct.Value.html pub fn insert(&mut self, index: usize, c: char) { self.graphemes.insert(index, c.to_string()); @@ -584,6 +623,13 @@ impl Value { .collect(); } + /// Inserts a bunch of graphemes at the given grapheme `index`. + pub fn insert_many(&mut self, index: usize, mut value: Value) { + let _ = self + .graphemes + .splice(index..index, value.graphemes.drain(..)); + } + /// Removes the grapheme at the given `index`. /// /// [`Value`]: struct.Value.html @@ -656,3 +702,27 @@ fn find_cursor_position<Renderer: self::Renderer>( ) } } + +mod platform { + use crate::input::keyboard; + + pub fn is_jump_modifier_pressed( + modifiers: keyboard::ModifiersState, + ) -> bool { + if cfg!(target_os = "macos") { + modifiers.alt + } else { + modifiers.control + } + } + + pub fn is_copy_paste_modifier_pressed( + modifiers: keyboard::ModifiersState, + ) -> bool { + if cfg!(target_os = "macos") { + modifiers.logo + } else { + modifiers.control + } + } +} |