summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-05 06:23:40 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-05 06:23:40 +0100
commit8af69be47e88896b3c5f70174db609eee0c67971 (patch)
treebf9b04335def215c2c3bacda2afe4c2125346dc8
parent43414bbdfb080b7aa3c702d944cc9d0c9c0fd14b (diff)
downloadiced-8af69be47e88896b3c5f70174db609eee0c67971.tar.gz
iced-8af69be47e88896b3c5f70174db609eee0c67971.tar.bz2
iced-8af69be47e88896b3c5f70174db609eee0c67971.zip
Converge `Command` types from `iced_futures` and `iced_native`
-rw-r--r--core/src/widget/operation.rs116
-rw-r--r--futures/src/command.rs70
-rw-r--r--futures/src/lib.rs2
-rw-r--r--native/src/command.rs59
-rw-r--r--native/src/command/action.rs8
-rw-r--r--native/src/lib.rs1
-rw-r--r--native/src/widget.rs16
-rw-r--r--native/src/widget/action.rs153
-rw-r--r--winit/src/application.rs2
9 files changed, 161 insertions, 266 deletions
diff --git a/core/src/widget/operation.rs b/core/src/widget/operation.rs
index 53688a21..ad188c36 100644
--- a/core/src/widget/operation.rs
+++ b/core/src/widget/operation.rs
@@ -11,6 +11,7 @@ use crate::widget::Id;
use std::any::Any;
use std::fmt;
+use std::rc::Rc;
/// A piece of logic that can traverse the widget tree of an application in
/// order to query or update some widget state.
@@ -68,9 +69,122 @@ where
}
}
+/// Maps the output of an [`Operation`] using the given function.
+pub fn map<A, B>(
+ operation: Box<dyn Operation<A>>,
+ f: impl Fn(A) -> B + 'static,
+) -> impl Operation<B>
+where
+ A: 'static,
+ B: 'static,
+{
+ #[allow(missing_debug_implementations)]
+ struct Map<A, B> {
+ operation: Box<dyn Operation<A>>,
+ f: Rc<dyn Fn(A) -> B>,
+ }
+
+ impl<A, B> Operation<B> for Map<A, B>
+ where
+ A: 'static,
+ B: 'static,
+ {
+ fn container(
+ &mut self,
+ id: Option<&Id>,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
+ ) {
+ struct MapRef<'a, A> {
+ operation: &'a mut dyn Operation<A>,
+ }
+
+ impl<'a, A, B> Operation<B> for MapRef<'a, A> {
+ fn container(
+ &mut self,
+ id: Option<&Id>,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
+ ) {
+ let Self { operation, .. } = self;
+
+ operation.container(id, &mut |operation| {
+ operate_on_children(&mut MapRef { operation });
+ });
+ }
+
+ fn scrollable(
+ &mut self,
+ state: &mut dyn Scrollable,
+ id: Option<&Id>,
+ ) {
+ self.operation.scrollable(state, id);
+ }
+
+ fn focusable(
+ &mut self,
+ state: &mut dyn Focusable,
+ id: Option<&Id>,
+ ) {
+ self.operation.focusable(state, id);
+ }
+
+ fn text_input(
+ &mut self,
+ state: &mut dyn TextInput,
+ id: Option<&Id>,
+ ) {
+ self.operation.text_input(state, id);
+ }
+
+ fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
+ self.operation.custom(state, id);
+ }
+ }
+
+ let Self { operation, .. } = self;
+
+ MapRef {
+ operation: operation.as_mut(),
+ }
+ .container(id, operate_on_children);
+ }
+
+ fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
+ self.operation.focusable(state, id);
+ }
+
+ fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) {
+ self.operation.scrollable(state, id);
+ }
+
+ fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
+ self.operation.text_input(state, id);
+ }
+
+ fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
+ self.operation.custom(state, id);
+ }
+
+ fn finish(&self) -> Outcome<B> {
+ match self.operation.finish() {
+ Outcome::None => Outcome::None,
+ Outcome::Some(output) => Outcome::Some((self.f)(output)),
+ Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
+ operation: next,
+ f: self.f.clone(),
+ })),
+ }
+ }
+ }
+
+ Map {
+ operation,
+ f: Rc::new(f),
+ }
+}
+
/// Produces an [`Operation`] that applies the given [`Operation`] to the
/// children of a container with the given [`Id`].
-pub fn scoped<T: 'static>(
+pub fn scope<T: 'static>(
target: Id,
operation: impl Operation<T> + 'static,
) -> impl Operation<T> {
diff --git a/futures/src/command.rs b/futures/src/command.rs
deleted file mode 100644
index 3d1ec3f9..00000000
--- a/futures/src/command.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-/// A set of asynchronous actions to be performed by some runtime.
-#[must_use = "`Command` must be returned to runtime to take effect"]
-#[derive(Debug)]
-pub struct Command<T>(Internal<T>);
-
-#[derive(Debug)]
-enum Internal<T> {
- None,
- Single(T),
- Batch(Vec<T>),
-}
-
-impl<T> Command<T> {
- /// Creates an empty [`Command`].
- ///
- /// In other words, a [`Command`] that does nothing.
- pub const fn none() -> Self {
- Self(Internal::None)
- }
-
- /// Creates a [`Command`] that performs a single action.
- pub const fn single(action: T) -> Self {
- Self(Internal::Single(action))
- }
-
- /// Creates a [`Command`] that performs the actions of all the given
- /// commands.
- ///
- /// Once this command is run, all the commands will be executed at once.
- pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self {
- let mut batch = Vec::new();
-
- for Command(command) in commands {
- match command {
- Internal::None => {}
- Internal::Single(command) => batch.push(command),
- Internal::Batch(commands) => batch.extend(commands),
- }
- }
-
- Self(Internal::Batch(batch))
- }
-
- /// Applies a transformation to the result of a [`Command`].
- pub fn map<A>(self, f: impl Fn(T) -> A) -> Command<A>
- where
- T: 'static,
- {
- let Command(command) = self;
-
- match command {
- Internal::None => Command::none(),
- Internal::Single(action) => Command::single(f(action)),
- Internal::Batch(batch) => {
- Command(Internal::Batch(batch.into_iter().map(f).collect()))
- }
- }
- }
-
- /// Returns all of the actions of the [`Command`].
- pub fn actions(self) -> Vec<T> {
- let Command(command) = self;
-
- match command {
- Internal::None => Vec::new(),
- Internal::Single(action) => vec![action],
- Internal::Batch(batch) => batch,
- }
- }
-}
diff --git a/futures/src/lib.rs b/futures/src/lib.rs
index 39137de2..397fc2d2 100644
--- a/futures/src/lib.rs
+++ b/futures/src/lib.rs
@@ -20,7 +20,6 @@
pub use futures;
pub use iced_core as core;
-mod command;
mod maybe_send;
mod runtime;
@@ -28,7 +27,6 @@ pub mod backend;
pub mod executor;
pub mod subscription;
-pub use command::Command;
pub use executor::Executor;
pub use maybe_send::MaybeSend;
pub use platform::*;
diff --git a/native/src/command.rs b/native/src/command.rs
index 39bee8f6..cd4c51ff 100644
--- a/native/src/command.rs
+++ b/native/src/command.rs
@@ -3,37 +3,39 @@ mod action;
pub use action::Action;
-use crate::widget;
-
-use iced_futures::MaybeSend;
+use crate::core::widget;
+use crate::futures::MaybeSend;
use std::fmt;
use std::future::Future;
/// A set of asynchronous actions to be performed by some runtime.
#[must_use = "`Command` must be returned to runtime to take effect"]
-pub struct Command<T>(iced_futures::Command<Action<T>>);
+pub struct Command<T>(Internal<Action<T>>);
+
+#[derive(Debug)]
+enum Internal<T> {
+ None,
+ Single(T),
+ Batch(Vec<T>),
+}
impl<T> Command<T> {
/// Creates an empty [`Command`].
///
/// In other words, a [`Command`] that does nothing.
pub const fn none() -> Self {
- Self(iced_futures::Command::none())
+ Self(Internal::None)
}
/// Creates a [`Command`] that performs a single [`Action`].
pub const fn single(action: Action<T>) -> Self {
- Self(iced_futures::Command::single(action))
+ Self(Internal::Single(action))
}
/// Creates a [`Command`] that performs a [`widget::Operation`].
- pub fn widget(
- operation: impl iced_core::widget::Operation<T> + 'static,
- ) -> Self {
- Self(iced_futures::Command::single(Action::Widget(
- widget::Action::new(operation),
- )))
+ pub fn widget(operation: impl widget::Operation<T> + 'static) -> Self {
+ Self::single(Action::Widget(Box::new(operation)))
}
/// Creates a [`Command`] that performs the action of the given future.
@@ -51,9 +53,17 @@ impl<T> Command<T> {
///
/// Once this command is run, all the commands will be executed at once.
pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self {
- Self(iced_futures::Command::batch(
- commands.into_iter().map(|Command(command)| command),
- ))
+ let mut batch = Vec::new();
+
+ for Command(command) in commands {
+ match command {
+ Internal::None => {}
+ Internal::Single(command) => batch.push(command),
+ Internal::Batch(commands) => batch.extend(commands),
+ }
+ }
+
+ Self(Internal::Batch(batch))
}
/// Applies a transformation to the result of a [`Command`].
@@ -65,16 +75,27 @@ impl<T> Command<T> {
T: 'static,
A: 'static,
{
- let Command(command) = self;
-
- Command(command.map(move |action| action.map(f.clone())))
+ match self.0 {
+ Internal::None => Command::none(),
+ Internal::Single(action) => Command::single(action.map(f)),
+ Internal::Batch(batch) => Command(Internal::Batch(
+ batch
+ .into_iter()
+ .map(|action| action.map(f.clone()))
+ .collect(),
+ )),
+ }
}
/// Returns all of the actions of the [`Command`].
pub fn actions(self) -> Vec<Action<T>> {
let Command(command) = self;
- command.actions()
+ match command {
+ Internal::None => Vec::new(),
+ Internal::Single(action) => vec![action],
+ Internal::Batch(batch) => batch,
+ }
}
}
diff --git a/native/src/command/action.rs b/native/src/command/action.rs
index d1589c05..6c74f0ef 100644
--- a/native/src/command/action.rs
+++ b/native/src/command/action.rs
@@ -1,7 +1,7 @@
use crate::clipboard;
+use crate::core::widget;
use crate::font;
use crate::system;
-use crate::widget;
use crate::window;
use iced_futures::MaybeSend;
@@ -28,7 +28,7 @@ pub enum Action<T> {
System(system::Action<T>),
/// Run a widget action.
- Widget(widget::Action<T>),
+ Widget(Box<dyn widget::Operation<T>>),
/// Load a font from its bytes.
LoadFont {
@@ -59,7 +59,9 @@ impl<T> Action<T> {
Self::Clipboard(action) => Action::Clipboard(action.map(f)),
Self::Window(window) => Action::Window(window.map(f)),
Self::System(system) => Action::System(system.map(f)),
- Self::Widget(widget) => Action::Widget(widget.map(f)),
+ Self::Widget(operation) => {
+ Action::Widget(Box::new(widget::operation::map(operation, f)))
+ }
Self::LoadFont { bytes, tagger } => Action::LoadFont {
bytes,
tagger: Box::new(move |result| f(tagger(result))),
diff --git a/native/src/lib.rs b/native/src/lib.rs
index 2d2e5b38..aa45e57a 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -50,7 +50,6 @@ pub mod keyboard;
pub mod program;
pub mod system;
pub mod user_interface;
-pub mod widget;
pub mod window;
// We disable debug capabilities on release builds unless the `debug` feature
diff --git a/native/src/widget.rs b/native/src/widget.rs
deleted file mode 100644
index 0fdade54..00000000
--- a/native/src/widget.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//! Use the built-in widgets or create your own.
-//!
-//! # Built-in widgets
-//! Every built-in drawable widget has its own module with a `Renderer` trait
-//! that must be implemented by a [renderer] before being able to use it as
-//! a [`Widget`].
-//!
-//! # Custom widgets
-//! If you want to implement a custom widget, you simply need to implement the
-//! [`Widget`] trait. You can use the API of the built-in widgets as a guide or
-//! source of inspiration.
-//!
-//! [renderer]: crate::renderer
-mod action;
-
-pub use action::Action;
diff --git a/native/src/widget/action.rs b/native/src/widget/action.rs
deleted file mode 100644
index f50d7aec..00000000
--- a/native/src/widget/action.rs
+++ /dev/null
@@ -1,153 +0,0 @@
-use iced_core::widget::operation::{
- self, Focusable, Operation, Scrollable, TextInput,
-};
-use iced_core::widget::Id;
-use iced_futures::MaybeSend;
-
-use std::any::Any;
-use std::rc::Rc;
-
-/// An operation to be performed on the widget tree.
-#[allow(missing_debug_implementations)]
-pub struct Action<T>(Box<dyn Operation<T>>);
-
-impl<T> Action<T> {
- /// Creates a new [`Action`] with the given [`Operation`].
- pub fn new(operation: impl Operation<T> + 'static) -> Self {
- Self(Box::new(operation))
- }
-
- /// Maps the output of an [`Action`] using the given function.
- pub fn map<A>(
- self,
- f: impl Fn(T) -> A + 'static + MaybeSend + Sync,
- ) -> Action<A>
- where
- T: 'static,
- A: 'static,
- {
- Action(Box::new(Map {
- operation: self.0,
- f: Rc::new(f),
- }))
- }
-
- /// Consumes the [`Action`] and returns the internal [`Operation`].
- pub fn into_operation(self) -> Box<dyn Operation<T>> {
- self.0
- }
-}
-
-#[allow(missing_debug_implementations)]
-struct Map<A, B> {
- operation: Box<dyn Operation<A>>,
- f: Rc<dyn Fn(A) -> B>,
-}
-
-impl<A, B> Operation<B> for Map<A, B>
-where
- A: 'static,
- B: 'static,
-{
- fn container(
- &mut self,
- id: Option<&Id>,
- operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
- ) {
- struct MapRef<'a, A> {
- operation: &'a mut dyn Operation<A>,
- }
-
- impl<'a, A, B> Operation<B> for MapRef<'a, A> {
- fn container(
- &mut self,
- id: Option<&Id>,
- operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
- ) {
- let Self { operation, .. } = self;
-
- operation.container(id, &mut |operation| {
- operate_on_children(&mut MapRef { operation });
- });
- }
-
- fn scrollable(
- &mut self,
- state: &mut dyn Scrollable,
- id: Option<&Id>,
- ) {
- self.operation.scrollable(state, id);
- }
-
- fn focusable(
- &mut self,
- state: &mut dyn Focusable,
- id: Option<&Id>,
- ) {
- self.operation.focusable(state, id);
- }
-
- fn text_input(
- &mut self,
- state: &mut dyn TextInput,
- id: Option<&Id>,
- ) {
- self.operation.text_input(state, id);
- }
-
- fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
- self.operation.custom(state, id);
- }
- }
-
- let Self { operation, .. } = self;
-
- MapRef {
- operation: operation.as_mut(),
- }
- .container(id, operate_on_children);
- }
-
- fn focusable(
- &mut self,
- state: &mut dyn operation::Focusable,
- id: Option<&Id>,
- ) {
- self.operation.focusable(state, id);
- }
-
- fn scrollable(
- &mut self,
- state: &mut dyn operation::Scrollable,
- id: Option<&Id>,
- ) {
- self.operation.scrollable(state, id);
- }
-
- fn text_input(
- &mut self,
- state: &mut dyn operation::TextInput,
- id: Option<&Id>,
- ) {
- self.operation.text_input(state, id);
- }
-
- fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
- self.operation.custom(state, id);
- }
-
- fn finish(&self) -> operation::Outcome<B> {
- match self.operation.finish() {
- operation::Outcome::None => operation::Outcome::None,
- operation::Outcome::Some(output) => {
- operation::Outcome::Some((self.f)(output))
- }
- operation::Outcome::Chain(next) => {
- operation::Outcome::Chain(Box::new(Map {
- operation: next,
- f: self.f.clone(),
- }))
- }
- }
- }
-}
diff --git a/winit/src/application.rs b/winit/src/application.rs
index c95dbf62..d863c846 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -818,7 +818,7 @@ pub fn run_command<A, E>(
},
command::Action::Widget(action) => {
let mut current_cache = std::mem::take(cache);
- let mut current_operation = Some(action.into_operation());
+ let mut current_operation = Some(action);
let mut user_interface = build_user_interface(
application,