From b22b0dd7ff56d433c459e0d14e14eb5472a6224d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 10 Mar 2021 01:16:26 +0100 Subject: [PATCH 1/4] Update `window_clipboard` to `0.2` --- glutin/src/application.rs | 2 +- native/src/clipboard.rs | 4 ++-- native/src/widget/text_input.rs | 2 +- winit/Cargo.toml | 2 +- winit/src/application.rs | 2 +- winit/src/clipboard.rs | 8 +++++--- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/glutin/src/application.rs b/glutin/src/application.rs index 42513feb1b..e6bb28e46c 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -136,7 +136,7 @@ async fn run_instance( use glutin::event; use iced_winit::futures::stream::StreamExt; - let clipboard = Clipboard::new(context.window()); + let clipboard = Clipboard::connect(context.window()); let mut state = application::State::new(&application, context.window()); let mut viewport_version = state.viewport_version(); diff --git a/native/src/clipboard.rs b/native/src/clipboard.rs index ecdccabfe5..3eeb184dac 100644 --- a/native/src/clipboard.rs +++ b/native/src/clipboard.rs @@ -1,6 +1,6 @@ /// A buffer for short-term storage and transfer within and between /// applications. pub trait Clipboard { - /// Returns the current content of the [`Clipboard`] as text. - fn content(&self) -> Option; + /// Reads the current content of the [`Clipboard`] as text. + fn read(&self) -> Option; } diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 2fd9cec189..4c38b1a345 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -509,7 +509,7 @@ where Some(content) => content, None => { let content: String = clipboard - .content() + .read() .unwrap_or(String::new()) .chars() .filter(|c| !c.is_control()) diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 39a6a5faa6..ecee0e2efb 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -15,7 +15,7 @@ debug = ["iced_native/debug"] [dependencies] winit = "0.24" -window_clipboard = "0.1" +window_clipboard = "0.2" log = "0.4" thiserror = "1.0" diff --git a/winit/src/application.rs b/winit/src/application.rs index d1a94864f4..6f8cfc2284 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -194,7 +194,7 @@ async fn run_instance( use winit::event; let surface = compositor.create_surface(&window); - let clipboard = Clipboard::new(&window); + let clipboard = Clipboard::connect(&window); let mut state = State::new(&application, &window); let mut viewport_version = state.viewport_version(); diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs index 93d53b11ad..cce2b37119 100644 --- a/winit/src/clipboard.rs +++ b/winit/src/clipboard.rs @@ -5,13 +5,15 @@ pub struct Clipboard(window_clipboard::Clipboard); impl Clipboard { /// Creates a new [`Clipboard`] for the given window. - pub fn new(window: &winit::window::Window) -> Option { - window_clipboard::Clipboard::new(window).map(Clipboard).ok() + pub fn connect(window: &winit::window::Window) -> Option { + window_clipboard::Clipboard::connect(window) + .map(Clipboard) + .ok() } } impl iced_native::Clipboard for Clipboard { - fn content(&self) -> Option { + fn read(&self) -> Option { self.0.read().ok() } } From 35425001edcb54d861a42ec6d23f9e57b37745fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 10 Mar 2021 01:18:22 +0100 Subject: [PATCH 2/4] Introduce `write` method to `Clipboard` trait --- native/src/clipboard.rs | 3 +++ winit/src/clipboard.rs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/native/src/clipboard.rs b/native/src/clipboard.rs index 3eeb184dac..fdb769da8e 100644 --- a/native/src/clipboard.rs +++ b/native/src/clipboard.rs @@ -3,4 +3,7 @@ pub trait Clipboard { /// Reads the current content of the [`Clipboard`] as text. fn read(&self) -> Option; + + /// Writes the given text contents to the [`Clipboard`]. + fn write(&mut self, contents: String); } diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs index cce2b37119..06e7c1a86b 100644 --- a/winit/src/clipboard.rs +++ b/winit/src/clipboard.rs @@ -16,4 +16,11 @@ impl iced_native::Clipboard for Clipboard { fn read(&self) -> Option { self.0.read().ok() } + + fn write(&mut self, contents: String) { + match self.0.write(contents) { + Ok(()) => {} + Err(error) => log::warn!("error writing to clipboard: {}", error), + } + } } From 21971e0037c2ddcb96fd48ea96332445de4137bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 10 Mar 2021 01:59:02 +0100 Subject: [PATCH 3/4] Make `Clipboard` argument in `Widget` trait mutable --- examples/integration/src/main.rs | 5 +- glutin/src/application.rs | 4 +- graphics/src/widget/canvas.rs | 4 +- native/src/clipboard.rs | 14 ++++++ native/src/element.rs | 18 +++---- native/src/lib.rs | 2 +- native/src/overlay.rs | 4 +- native/src/overlay/element.rs | 12 ++--- native/src/overlay/menu.rs | 10 ++-- native/src/program/state.rs | 4 +- native/src/user_interface.rs | 16 +++--- native/src/widget.rs | 4 +- native/src/widget/button.rs | 6 +-- native/src/widget/checkbox.rs | 4 +- native/src/widget/column.rs | 6 +-- native/src/widget/container.rs | 6 +-- native/src/widget/image/viewer.rs | 4 +- native/src/widget/pane_grid.rs | 6 +-- native/src/widget/pane_grid/content.rs | 8 +-- native/src/widget/pane_grid/title_bar.rs | 6 +-- native/src/widget/pick_list.rs | 4 +- native/src/widget/radio.rs | 4 +- native/src/widget/row.rs | 6 +-- native/src/widget/scrollable.rs | 6 +-- native/src/widget/slider.rs | 4 +- native/src/widget/text_input.rs | 63 ++++++++++++------------ native/src/widget/text_input/cursor.rs | 21 ++++---- native/src/widget/text_input/value.rs | 9 ++++ native/src/widget/tooltip.rs | 6 +-- winit/src/application.rs | 4 +- winit/src/clipboard.rs | 34 ++++++++++--- 31 files changed, 175 insertions(+), 129 deletions(-) diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs index ec01c4e6a5..b57c73d844 100644 --- a/examples/integration/src/main.rs +++ b/examples/integration/src/main.rs @@ -5,7 +5,7 @@ use controls::Controls; use scene::Scene; use iced_wgpu::{wgpu, Backend, Renderer, Settings, Viewport}; -use iced_winit::{conversion, futures, program, winit, Debug, Size}; +use iced_winit::{conversion, futures, program, winit, Clipboard, Debug, Size}; use futures::task::SpawnExt; use winit::{ @@ -28,6 +28,7 @@ pub fn main() { ); let mut cursor_position = PhysicalPosition::new(-1.0, -1.0); let mut modifiers = ModifiersState::default(); + let mut clipboard = Clipboard::connect(&window); // Initialize wgpu let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); @@ -141,8 +142,8 @@ pub fn main() { cursor_position, viewport.scale_factor(), ), - None, &mut renderer, + &mut clipboard, &mut debug, ); diff --git a/glutin/src/application.rs b/glutin/src/application.rs index e6bb28e46c..19eee2194e 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -136,7 +136,7 @@ async fn run_instance( use glutin::event; use iced_winit::futures::stream::StreamExt; - let clipboard = Clipboard::connect(context.window()); + let mut clipboard = Clipboard::connect(context.window()); let mut state = application::State::new(&application, context.window()); let mut viewport_version = state.viewport_version(); @@ -170,8 +170,8 @@ async fn run_instance( let statuses = user_interface.update( &events, state.cursor_position(), - clipboard.as_ref().map(|c| c as _), &mut renderer, + &mut clipboard, &mut messages, ); diff --git a/graphics/src/widget/canvas.rs b/graphics/src/widget/canvas.rs index 95ede50f7e..7897c8ec7e 100644 --- a/graphics/src/widget/canvas.rs +++ b/graphics/src/widget/canvas.rs @@ -154,9 +154,9 @@ where event: iced_native::Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { let bounds = layout.bounds(); diff --git a/native/src/clipboard.rs b/native/src/clipboard.rs index fdb769da8e..081b40046c 100644 --- a/native/src/clipboard.rs +++ b/native/src/clipboard.rs @@ -1,3 +1,5 @@ +//! Access the clipboard. + /// A buffer for short-term storage and transfer within and between /// applications. pub trait Clipboard { @@ -7,3 +9,15 @@ pub trait Clipboard { /// Writes the given text contents to the [`Clipboard`]. fn write(&mut self, contents: String); } + +/// A null implementation of the [`Clipboard`] trait. +#[derive(Debug, Clone, Copy)] +pub struct Null; + +impl Clipboard for Null { + fn read(&self) -> Option { + None + } + + fn write(&mut self, _contents: String) {} +} diff --git a/native/src/element.rs b/native/src/element.rs index d6e9639a7e..5c84a3887f 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -223,17 +223,17 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.widget.on_event( event, layout, cursor_position, - messages, renderer, clipboard, + messages, ) } @@ -311,9 +311,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { let mut original_messages = Vec::new(); @@ -321,9 +321,9 @@ where event, layout, cursor_position, - &mut original_messages, renderer, clipboard, + &mut original_messages, ); original_messages @@ -401,17 +401,17 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.element.widget.on_event( event, layout, cursor_position, - messages, renderer, clipboard, + messages, ) } diff --git a/native/src/lib.rs b/native/src/lib.rs index 0890785be5..20bbb1d025 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -33,6 +33,7 @@ #![deny(unused_results)] #![forbid(unsafe_code)] #![forbid(rust_2018_idioms)] +pub mod clipboard; pub mod event; pub mod keyboard; pub mod layout; @@ -45,7 +46,6 @@ pub mod touch; pub mod widget; pub mod window; -mod clipboard; mod element; mod hasher; mod runtime; diff --git a/native/src/overlay.rs b/native/src/overlay.rs index ea8bb3845c..84145e7fad 100644 --- a/native/src/overlay.rs +++ b/native/src/overlay.rs @@ -67,9 +67,9 @@ where _event: Event, _layout: Layout<'_>, _cursor_position: Point, - _messages: &mut Vec, _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + _messages: &mut Vec, ) -> event::Status { event::Status::Ignored } diff --git a/native/src/overlay/element.rs b/native/src/overlay/element.rs index 0f44a7810c..e48190376b 100644 --- a/native/src/overlay/element.rs +++ b/native/src/overlay/element.rs @@ -53,17 +53,17 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.overlay.on_event( event, layout, cursor_position, - messages, renderer, clipboard, + messages, ) } @@ -117,9 +117,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { let mut original_messages = Vec::new(); @@ -127,9 +127,9 @@ where event, layout, cursor_position, - &mut original_messages, renderer, clipboard, + &mut original_messages, ); original_messages diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs index 5ad1391f95..afb17bd3b9 100644 --- a/native/src/overlay/menu.rs +++ b/native/src/overlay/menu.rs @@ -219,17 +219,17 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.container.on_event( event.clone(), layout, cursor_position, - messages, renderer, clipboard, + messages, ) } @@ -320,9 +320,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - _messages: &mut Vec, renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + _messages: &mut Vec, ) -> event::Status { match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => { diff --git a/native/src/program/state.rs b/native/src/program/state.rs index e630890a4d..3f5f606978 100644 --- a/native/src/program/state.rs +++ b/native/src/program/state.rs @@ -91,8 +91,8 @@ where &mut self, bounds: Size, cursor_position: Point, - clipboard: Option<&dyn Clipboard>, renderer: &mut P::Renderer, + clipboard: &mut dyn Clipboard, debug: &mut Debug, ) -> Option> { let mut user_interface = build_user_interface( @@ -109,8 +109,8 @@ where let _ = user_interface.update( &self.queued_events, cursor_position, - clipboard, renderer, + clipboard, &mut messages, ); diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 7a64ac5925..475faf8d15 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -134,7 +134,7 @@ where /// completing [the previous example](#example): /// /// ```no_run - /// use iced_native::{UserInterface, Cache, Size, Point}; + /// use iced_native::{clipboard, UserInterface, Cache, Size, Point}; /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { @@ -157,6 +157,7 @@ where /// let mut renderer = Renderer::new(); /// let mut window_size = Size::new(1024.0, 768.0); /// let mut cursor_position = Point::default(); + /// let mut clipboard = clipboard::Null; /// /// // Initialize our event storage /// let mut events = Vec::new(); @@ -176,8 +177,8 @@ where /// let event_statuses = user_interface.update( /// &events, /// cursor_position, - /// None, /// &renderer, + /// &mut clipboard, /// &mut messages /// ); /// @@ -193,8 +194,8 @@ where &mut self, events: &[Event], cursor_position: Point, - clipboard: Option<&dyn Clipboard>, renderer: &Renderer, + clipboard: &mut dyn Clipboard, messages: &mut Vec, ) -> Vec { let (base_cursor, overlay_statuses) = if let Some(mut overlay) = @@ -215,9 +216,9 @@ where event, Layout::new(&layer.layout), cursor_position, - messages, renderer, clipboard, + messages, ) }) .collect(); @@ -246,9 +247,9 @@ where event, Layout::new(&self.base.layout), base_cursor, - messages, renderer, clipboard, + messages, ); event_status.merge(overlay_status) @@ -269,7 +270,7 @@ where /// [completing the last example](#example-1): /// /// ```no_run - /// use iced_native::{UserInterface, Cache, Size, Point}; + /// use iced_native::{clipboard, UserInterface, Cache, Size, Point}; /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { @@ -292,6 +293,7 @@ where /// let mut renderer = Renderer::new(); /// let mut window_size = Size::new(1024.0, 768.0); /// let mut cursor_position = Point::default(); + /// let mut clipboard = clipboard::Null; /// let mut events = Vec::new(); /// let mut messages = Vec::new(); /// @@ -309,8 +311,8 @@ where /// let event_statuses = user_interface.update( /// &events, /// cursor_position, - /// None, /// &renderer, + /// &mut clipboard, /// &mut messages /// ); /// diff --git a/native/src/widget.rs b/native/src/widget.rs index d5c353dfd5..791c53a3e4 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -164,9 +164,9 @@ where _event: Event, _layout: Layout<'_>, _cursor_position: Point, - _messages: &mut Vec, _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + _messages: &mut Vec, ) -> event::Status { event::Status::Ignored } diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index b8c146342a..59d6e21958 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -160,17 +160,17 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { if let event::Status::Captured = self.content.on_event( event.clone(), layout.children().next().unwrap(), cursor_position, - messages, renderer, clipboard, + messages, ) { return event::Status::Captured; } diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 77a82fad2e..6ce2e973fc 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -150,9 +150,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index e0e88d31f3..d7f0365a50 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -141,9 +141,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.children .iter_mut() @@ -153,9 +153,9 @@ where event.clone(), layout, cursor_position, - messages, renderer, clipboard, + messages, ) }) .fold(event::Status::Ignored, event::Status::merge) diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 6576414883..69fe699bde 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -151,17 +151,17 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.content.widget.on_event( event, layout.children().next().unwrap(), cursor_position, - messages, renderer, clipboard, + messages, ) } diff --git a/native/src/widget/image/viewer.rs b/native/src/widget/image/viewer.rs index 5f0dda4e0d..a006c0af7b 100644 --- a/native/src/widget/image/viewer.rs +++ b/native/src/widget/image/viewer.rs @@ -155,9 +155,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - _messages: &mut Vec, renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + _messages: &mut Vec, ) -> event::Status { let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index c6fe4b60bb..9a3580e0a1 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -362,9 +362,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { let mut event_status = event::Status::Ignored; @@ -461,9 +461,9 @@ where event.clone(), layout, cursor_position, - messages, renderer, clipboard, + messages, ) }) .fold(event_status, event::Status::merge) diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index 913cfe96e0..a5493fe282 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -143,9 +143,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { let mut event_status = event::Status::Ignored; @@ -156,9 +156,9 @@ where event.clone(), children.next().unwrap(), cursor_position, - messages, renderer, clipboard, + messages, ); children.next().unwrap() @@ -170,9 +170,9 @@ where event, body_layout, cursor_position, - messages, renderer, clipboard, + messages, ); event_status.merge(body_status) diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index 2f9659e867..ff689ddbb0 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -199,9 +199,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { if let Some(controls) = &mut self.controls { let mut children = layout.children(); @@ -215,9 +215,9 @@ where event, controls_layout, cursor_position, - messages, renderer, clipboard, + messages, ) } else { event::Status::Ignored diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index 74f4508e2d..046d57791a 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -210,9 +210,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index 6995234586..9482a9b14e 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -156,9 +156,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs index b71663bd05..5634ab1234 100644 --- a/native/src/widget/row.rs +++ b/native/src/widget/row.rs @@ -140,9 +140,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.children .iter_mut() @@ -152,9 +152,9 @@ where event.clone(), layout, cursor_position, - messages, renderer, clipboard, + messages, ) }) .fold(event::Status::Ignored, event::Status::merge) diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 18cdf16974..70ebebe2db 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -162,9 +162,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); @@ -205,9 +205,9 @@ where event.clone(), content, cursor_position, - messages, renderer, clipboard, + messages, ) }; diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index 010c6e539f..2a74d5a313 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -180,9 +180,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, + _clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { let mut change = || { let bounds = layout.bounds(); diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 4c38b1a345..400cae2a90 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -243,9 +243,9 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) @@ -503,43 +503,42 @@ where } keyboard::KeyCode::V => { if self.state.keyboard_modifiers.is_command_pressed() { - if let Some(clipboard) = clipboard { - let content = match self.state.is_pasting.take() - { - Some(content) => content, - None => { - let content: String = clipboard - .read() - .unwrap_or(String::new()) - .chars() - .filter(|c| !c.is_control()) - .collect(); - - Value::new(&content) - } - }; - - let mut editor = Editor::new( - &mut self.value, - &mut self.state.cursor, - ); + let content = match self.state.is_pasting.take() { + Some(content) => content, + None => { + let content: String = clipboard + .read() + .unwrap_or(String::new()) + .chars() + .filter(|c| !c.is_control()) + .collect(); + + Value::new(&content) + } + }; + + let mut editor = Editor::new( + &mut self.value, + &mut self.state.cursor, + ); - editor.paste(content.clone()); + editor.paste(content.clone()); - let message = - (self.on_change)(editor.contents()); - messages.push(message); + let message = (self.on_change)(editor.contents()); + messages.push(message); - self.state.is_pasting = Some(content); - } + self.state.is_pasting = Some(content); } else { self.state.is_pasting = None; } } - keyboard::KeyCode::A => { - if self.state.keyboard_modifiers.is_command_pressed() { - self.state.cursor.select_all(&self.value); - } + keyboard::KeyCode::A + if self + .state + .keyboard_modifiers + .is_command_pressed() => + { + self.state.cursor.select_all(&self.value); } keyboard::KeyCode::Escape => { self.state.is_focused = false; diff --git a/native/src/widget/text_input/cursor.rs b/native/src/widget/text_input/cursor.rs index e630e29388..1e7aee8326 100644 --- a/native/src/widget/text_input/cursor.rs +++ b/native/src/widget/text_input/cursor.rs @@ -48,6 +48,18 @@ impl Cursor { } } + /// Returns the current selection of the [`Cursor`] for the given [`Value`]. + /// + /// `start` is guaranteed to be <= than `end`. + pub fn selection(&self, value: &Value) -> Option<(usize, usize)> { + match self.state(value) { + State::Selection { start, end } => { + Some((start.min(end), start.max(end))) + } + _ => None, + } + } + pub(crate) fn move_to(&mut self, position: usize) { self.state = State::Index(position); } @@ -161,15 +173,6 @@ impl Cursor { end.min(value.len()) } - pub(crate) fn selection(&self, value: &Value) -> Option<(usize, usize)> { - match self.state(value) { - State::Selection { start, end } => { - Some((start.min(end), start.max(end))) - } - _ => None, - } - } - fn left(&self, value: &Value) -> usize { match self.state(value) { State::Index(index) => index, diff --git a/native/src/widget/text_input/value.rs b/native/src/widget/text_input/value.rs index 86be279010..2034cca418 100644 --- a/native/src/widget/text_input/value.rs +++ b/native/src/widget/text_input/value.rs @@ -73,6 +73,15 @@ impl Value { .unwrap_or(self.len()) } + /// Returns a new [`Value`] containing the graphemes from `start` until the + /// given `end`. + pub fn select(&self, start: usize, end: usize) -> Self { + let graphemes = + self.graphemes[start.min(self.len())..end.min(self.len())].to_vec(); + + Self { graphemes } + } + /// Returns a new [`Value`] containing the graphemes until the given /// `index`. pub fn until(&self, index: usize) -> Self { diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs index ab07868c0b..276afd4102 100644 --- a/native/src/widget/tooltip.rs +++ b/native/src/widget/tooltip.rs @@ -120,17 +120,17 @@ where event: Event, layout: Layout<'_>, cursor_position: Point, - messages: &mut Vec, renderer: &Renderer, - clipboard: Option<&dyn Clipboard>, + clipboard: &mut dyn Clipboard, + messages: &mut Vec, ) -> event::Status { self.content.widget.on_event( event, layout, cursor_position, - messages, renderer, clipboard, + messages, ) } diff --git a/winit/src/application.rs b/winit/src/application.rs index 6f8cfc2284..2cb2c01610 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -194,7 +194,7 @@ async fn run_instance( use winit::event; let surface = compositor.create_surface(&window); - let clipboard = Clipboard::connect(&window); + let mut clipboard = Clipboard::connect(&window); let mut state = State::new(&application, &window); let mut viewport_version = state.viewport_version(); @@ -237,8 +237,8 @@ async fn run_instance( let statuses = user_interface.update( &events, state.cursor_position(), - clipboard.as_ref().map(|c| c as _), &mut renderer, + &mut clipboard, &mut messages, ); diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs index 06e7c1a86b..15dc989f21 100644 --- a/winit/src/clipboard.rs +++ b/winit/src/clipboard.rs @@ -1,26 +1,44 @@ /// A buffer for short-term storage and transfer within and between /// applications. #[allow(missing_debug_implementations)] -pub struct Clipboard(window_clipboard::Clipboard); +pub struct Clipboard { + state: State, +} + +enum State { + Connected(window_clipboard::Clipboard), + Unavailable, +} impl Clipboard { /// Creates a new [`Clipboard`] for the given window. - pub fn connect(window: &winit::window::Window) -> Option { - window_clipboard::Clipboard::connect(window) - .map(Clipboard) + pub fn connect(window: &winit::window::Window) -> Clipboard { + let state = window_clipboard::Clipboard::connect(window) .ok() + .map(State::Connected) + .unwrap_or(State::Unavailable); + + Clipboard { state } } } impl iced_native::Clipboard for Clipboard { fn read(&self) -> Option { - self.0.read().ok() + match &self.state { + State::Connected(clipboard) => clipboard.read().ok(), + State::Unavailable => None, + } } fn write(&mut self, contents: String) { - match self.0.write(contents) { - Ok(()) => {} - Err(error) => log::warn!("error writing to clipboard: {}", error), + match &mut self.state { + State::Connected(clipboard) => match clipboard.write(contents) { + Ok(()) => {} + Err(error) => { + log::warn!("error writing to clipboard: {}", error) + } + }, + State::Unavailable => {} } } } From 17dcfa8faf68afe3cbad1151f41eb35230ef83e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 10 Mar 2021 01:59:20 +0100 Subject: [PATCH 4/4] Implement copy and cut behavior for `TextInput` --- native/src/widget/text_input.rs | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 400cae2a90..de6032b77a 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -501,6 +501,46 @@ where self.state.cursor.move_to(self.value.len()); } } + keyboard::KeyCode::C + if self + .state + .keyboard_modifiers + .is_command_pressed() => + { + match self.state.cursor.selection(&self.value) { + Some((start, end)) => { + clipboard.write( + self.value.select(start, end).to_string(), + ); + } + None => {} + } + } + keyboard::KeyCode::X + if self + .state + .keyboard_modifiers + .is_command_pressed() => + { + match self.state.cursor.selection(&self.value) { + Some((start, end)) => { + clipboard.write( + self.value.select(start, end).to_string(), + ); + } + None => {} + } + + let mut editor = Editor::new( + &mut self.value, + &mut self.state.cursor, + ); + + editor.delete(); + + let message = (self.on_change)(editor.contents()); + messages.push(message); + } keyboard::KeyCode::V => { if self.state.keyboard_modifiers.is_command_pressed() { let content = match self.state.is_pasting.take() {