summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2019-12-19 17:43:25 +0100
committerLibravatar GitHub <noreply@github.com>2019-12-19 17:43:25 +0100
commit773a23630be538372d5dd1a609d654a1289be389 (patch)
treea53a42d424ce36dd26c24a5a03140458013956ad
parent9cf61fb82cb715ab0af15343be258b2b227d85f4 (diff)
parent8c8c5bb7665c1ac50d2ad355b06f1ea02dc5b4c2 (diff)
downloadiced-773a23630be538372d5dd1a609d654a1289be389.tar.gz
iced-773a23630be538372d5dd1a609d654a1289be389.tar.bz2
iced-773a23630be538372d5dd1a609d654a1289be389.zip
Merge pull request #132 from hecrj/feature/read-clipboard
Clipboard access
Diffstat (limited to '')
-rw-r--r--.travis.yml15
-rw-r--r--README.md2
-rw-r--r--native/src/clipboard.rs8
-rw-r--r--native/src/element.rs7
-rw-r--r--native/src/lib.rs2
-rw-r--r--native/src/user_interface.rs10
-rw-r--r--native/src/widget.rs5
-rw-r--r--native/src/widget/button.rs5
-rw-r--r--native/src/widget/checkbox.rs3
-rw-r--r--native/src/widget/column.rs5
-rw-r--r--native/src/widget/container.rs5
-rw-r--r--native/src/widget/radio.rs3
-rw-r--r--native/src/widget/row.rs5
-rw-r--r--native/src/widget/scrollable.rs6
-rw-r--r--native/src/widget/slider.rs5
-rw-r--r--native/src/widget/text_input.rs110
-rw-r--r--winit/Cargo.toml1
-rw-r--r--winit/src/application.rs14
-rw-r--r--winit/src/clipboard.rs13
-rw-r--r--winit/src/lib.rs8
20 files changed, 172 insertions, 60 deletions
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 7d6826df..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-language: rust
-rust:
- - stable
- - beta
- - nightly
-matrix:
- allow_failures:
- - rust: nightly
- fast_finish: true
-before_install:
- - |
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
- sudo apt-get -qq update
- sudo apt-get install -y libasound2-dev libudev-dev
- fi
diff --git a/README.md b/README.md
index f12517c7..ec234e10 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Iced
-[![Build Status](https://travis-ci.org/hecrj/iced.svg?branch=master)](https://travis-ci.org/hecrj/iced)
+[![Test Status](https://github.com/hecrj/iced/workflows/Test/badge.svg)](https://github.com/hecrj/iced/actions)
[![Documentation](https://docs.rs/iced/badge.svg)][documentation]
[![Crates.io](https://img.shields.io/crates/v/iced.svg)](https://crates.io/crates/iced)
[![License](https://img.shields.io/crates/l/iced.svg)](https://github.com/hecrj/iced/blob/master/LICENSE)
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
+ }
+ }
+}
diff --git a/winit/Cargo.toml b/winit/Cargo.toml
index b5b07449..9d574a40 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 = { git = "https://github.com/hecrj/window_clipboard", rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf" }
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<Clipboard> {
+ window_clipboard::Clipboard::new(window).map(Clipboard).ok()
+ }
+}
+
+impl iced_native::Clipboard for Clipboard {
+ fn content(&self) -> Option<String> {
+ 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;