From a14b39555e5c480422c24df7d708dd1addd0a67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Dec 2019 07:45:49 +0100 Subject: [PATCH] Allow clipboard access in `Widget::on_event` --- .github/workflows/build.yml | 2 ++ .github/workflows/test.yml | 3 +++ native/src/clipboard.rs | 8 ++++++++ native/src/element.rs | 7 ++++++- native/src/lib.rs | 2 ++ native/src/user_interface.rs | 10 +++++++--- native/src/widget.rs | 5 +++-- native/src/widget/button.rs | 5 +++-- native/src/widget/checkbox.rs | 3 ++- native/src/widget/column.rs | 5 ++++- native/src/widget/container.rs | 5 ++++- native/src/widget/radio.rs | 3 ++- native/src/widget/row.rs | 5 ++++- native/src/widget/scrollable.rs | 6 ++++-- native/src/widget/slider.rs | 5 +++-- native/src/widget/text_input.rs | 5 +++-- winit/Cargo.toml | 1 + winit/src/application.rs | 14 ++++++++++---- winit/src/clipboard.rs | 13 +++++++++++++ winit/src/lib.rs | 8 +++++--- 20 files changed, 89 insertions(+), 26 deletions(-) create mode 100644 native/src/clipboard.rs create mode 100644 winit/src/clipboard.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 804273ff..65a4f0a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: hecrj/setup-rust-action@v1 + - name: Install xcb libraries + run: sudo apt-get install -y libxcb-shape0-dev libxcb-xfixes0-dev - name: Install cargo-deb run: cargo install cargo-deb - uses: actions/checkout@master diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4f911303..09e52f92 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,9 @@ jobs: with: rust-version: ${{ matrix.rust }} - uses: actions/checkout@master + - name: Install xcb libraries + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get install -y libxcb-shape0-dev libxcb-xfixes0-dev - name: Run tests run: | cargo test --verbose --all 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; +} 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, 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, 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, ) -> Vec { 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, _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, _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, _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, 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, 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, _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, 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, 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, _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..3890e9c6 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, renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, ) { match event { Event::Mouse(mouse::Event::Input { diff --git a/winit/Cargo.toml b/winit/Cargo.toml index b5b07449..ab19f0e2 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -13,6 +13,7 @@ debug = [] [dependencies] iced_native = { version = "0.1.0-alpha", path = "../native" } winit = { version = "0.20.0-alpha3", git = "https://github.com/rust-windowing/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"} +window_clipboard = "=0.1.0-alpha.1" futures = { version = "0.3", features = ["thread-pool"] } log = "0.4" diff --git a/winit/src/application.rs b/winit/src/application.rs index 3b8ac16b..a8612b1a 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -2,8 +2,8 @@ use crate::{ conversion, input::{keyboard, mouse}, renderer::{Target, Windowed}, - subscription, Cache, Command, Container, Debug, Element, Event, Length, - MouseCursor, Settings, Subscription, UserInterface, + subscription, Cache, Clipboard, Command, Container, Debug, Element, Event, + Length, MouseCursor, Settings, Subscription, UserInterface, }; /// An interactive, native cross-platform application. @@ -139,6 +139,7 @@ pub trait Application: Sized { let mut size = window.inner_size(); let mut resized = false; + let clipboard = Clipboard::new(&window); let mut renderer = Self::Renderer::new(); let mut target = { @@ -193,8 +194,13 @@ pub trait Application: Sized { subscription_pool.broadcast_event(*event) }); - let mut messages = - user_interface.update(&renderer, events.drain(..)); + let mut messages = user_interface.update( + &renderer, + clipboard + .as_ref() + .map(|c| c as &dyn iced_native::Clipboard), + events.drain(..), + ); messages.extend(external_messages.drain(..)); debug.event_processing_finished(); diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs new file mode 100644 index 00000000..4739c603 --- /dev/null +++ b/winit/src/clipboard.rs @@ -0,0 +1,13 @@ +pub struct Clipboard(window_clipboard::Clipboard); + +impl Clipboard { + pub fn new(window: &winit::window::Window) -> Option { + window_clipboard::Clipboard::new(window).map(Clipboard).ok() + } +} + +impl iced_native::Clipboard for Clipboard { + fn content(&self) -> Option { + self.0.read().ok() + } +} diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 8a1dc870..ffc662fb 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -29,11 +29,9 @@ pub mod conversion; pub mod settings; mod application; +mod clipboard; mod subscription; -pub use application::Application; -pub use settings::Settings; - // We disable debug capabilities on release builds unless the `debug` feature // is explicitly enabled. #[cfg(feature = "debug")] @@ -43,4 +41,8 @@ mod debug; #[path = "debug/null.rs"] mod debug; +pub use application::Application; +pub use settings::Settings; + +use clipboard::Clipboard; use debug::Debug;