diff options
Diffstat (limited to 'native')
| -rw-r--r-- | native/src/clipboard.rs | 8 | ||||
| -rw-r--r-- | native/src/element.rs | 7 | ||||
| -rw-r--r-- | native/src/lib.rs | 2 | ||||
| -rw-r--r-- | native/src/user_interface.rs | 10 | ||||
| -rw-r--r-- | native/src/widget.rs | 5 | ||||
| -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 | 
14 files changed, 142 insertions, 37 deletions
| diff --git a/native/src/clipboard.rs b/native/src/clipboard.rs new file mode 100644 index 00000000..4c574590 --- /dev/null +++ b/native/src/clipboard.rs @@ -0,0 +1,8 @@ +/// A buffer for short-term storage and transfer within and between +/// applications. +pub trait Clipboard { +    /// Returns the current content of the [`Clipboard`] as text. +    /// +    /// [`Clipboard`]: trait.Clipboard.html +    fn content(&self) -> Option<String>; +} diff --git a/native/src/element.rs b/native/src/element.rs index d4237fd0..63d2de0c 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -1,5 +1,6 @@  use crate::{ -    layout, renderer, Color, Event, Hasher, Layout, Length, Point, Widget, +    layout, renderer, Clipboard, Color, Event, Hasher, Layout, Length, Point, +    Widget,  };  /// A generic [`Widget`]. @@ -293,6 +294,7 @@ where          cursor_position: Point,          messages: &mut Vec<B>,          renderer: &Renderer, +        clipboard: Option<&dyn Clipboard>,      ) {          let mut original_messages = Vec::new(); @@ -302,6 +304,7 @@ where              cursor_position,              &mut original_messages,              renderer, +            clipboard,          );          original_messages @@ -366,6 +369,7 @@ where          cursor_position: Point,          messages: &mut Vec<Message>,          renderer: &Renderer, +        clipboard: Option<&dyn Clipboard>,      ) {          self.element.widget.on_event(              event, @@ -373,6 +377,7 @@ where              cursor_position,              messages,              renderer, +            clipboard,          )      } diff --git a/native/src/lib.rs b/native/src/lib.rs index c4d72df8..8dcacb2b 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -45,6 +45,7 @@ pub mod renderer;  pub mod subscription;  pub mod widget; +mod clipboard;  mod element;  mod event;  mod hasher; @@ -57,6 +58,7 @@ pub use iced_core::{      Point, Rectangle, Vector, VerticalAlignment,  }; +pub use clipboard::Clipboard;  pub use element::Element;  pub use event::Event;  pub use hasher::Hasher; diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 9833c815..07b936a9 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -1,4 +1,6 @@ -use crate::{input::mouse, layout, Element, Event, Layout, Point, Size}; +use crate::{ +    input::mouse, layout, Clipboard, Element, Event, Layout, Point, Size, +};  use std::hash::Hasher; @@ -185,7 +187,7 @@ where      ///     );      ///      ///     // Update the user interface -    ///     let messages = user_interface.update(&renderer, events.drain(..)); +    ///     let messages = user_interface.update(&renderer, None, events.drain(..));      ///      ///     cache = user_interface.into_cache();      /// @@ -198,6 +200,7 @@ where      pub fn update(          &mut self,          renderer: &Renderer, +        clipboard: Option<&dyn Clipboard>,          events: impl Iterator<Item = Event>,      ) -> Vec<Message> {          let mut messages = Vec::new(); @@ -213,6 +216,7 @@ where                  self.cursor_position,                  &mut messages,                  renderer, +                clipboard,              );          } @@ -282,7 +286,7 @@ where      ///         &mut renderer,      ///     );      /// -    ///     let messages = user_interface.update(&renderer, events.drain(..)); +    ///     let messages = user_interface.update(&renderer, None, events.drain(..));      ///      ///     // Draw the user interface      ///     let mouse_cursor = user_interface.draw(&mut renderer); diff --git a/native/src/widget.rs b/native/src/widget.rs index ee7232cb..26889280 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -24,12 +24,12 @@ pub mod button;  pub mod checkbox;  pub mod column;  pub mod container; -pub mod svg;  pub mod image;  pub mod radio;  pub mod row;  pub mod scrollable;  pub mod slider; +pub mod svg;  pub mod text;  pub mod text_input; @@ -58,7 +58,7 @@ pub use text::Text;  #[doc(no_inline)]  pub use text_input::TextInput; -use crate::{layout, Event, Hasher, Layout, Length, Point}; +use crate::{layout, Clipboard, Event, Hasher, Layout, Length, Point};  /// A component that displays information and allows interaction.  /// @@ -142,6 +142,7 @@ where          _cursor_position: Point,          _messages: &mut Vec<Message>,          _renderer: &Renderer, +        _clipboard: Option<&dyn Clipboard>,      ) {      }  } 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 +        } +    } +} | 
