From 80688689aa4b15bc23824df899974a9094a77b07 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 28 Jul 2022 02:46:51 +0200 Subject: Draft widget operations --- native/src/widget/operation.rs | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 native/src/widget/operation.rs (limited to 'native/src/widget/operation.rs') diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs new file mode 100644 index 00000000..b6c108e0 --- /dev/null +++ b/native/src/widget/operation.rs @@ -0,0 +1,62 @@ +use crate::widget::state; +use crate::widget::Id; + +pub trait Operation { + fn container( + &mut self, + id: Option<&Id>, + operate_on_children: &dyn Fn(&mut dyn Operation), + ); + + fn focusable( + &mut self, + _state: &mut dyn state::Focusable, + _id: Option<&Id>, + ) { + } + + fn finish(&self) -> Outcome { + Outcome::None + } +} + +pub enum Outcome { + None, + Some(T), + Chain(Box>), +} + +pub fn focus(target: Id) -> impl Operation { + struct Focus { + target: Id, + } + + impl Operation for Focus { + fn focusable( + &mut self, + state: &mut dyn state::Focusable, + id: Option<&Id>, + ) { + if state.is_focused() { + match id { + Some(id) if id == &self.target => { + state.focus(); + } + _ => { + state.unfocus(); + } + } + } + } + + fn container( + &mut self, + _id: Option<&Id>, + operate_on_children: &dyn Fn(&mut dyn Operation), + ) { + operate_on_children(self) + } + } + + Focus { target } +} -- cgit From 52f84e51e90db1c324310565f2aff8b7e6987cba Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 28 Jul 2022 03:53:47 +0200 Subject: Implement `Widget::operate` for `TextInput` --- native/src/widget/operation.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'native/src/widget/operation.rs') diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs index b6c108e0..2cfba005 100644 --- a/native/src/widget/operation.rs +++ b/native/src/widget/operation.rs @@ -5,7 +5,7 @@ pub trait Operation { fn container( &mut self, id: Option<&Id>, - operate_on_children: &dyn Fn(&mut dyn Operation), + operate_on_children: &mut dyn FnMut(&mut dyn Operation), ); fn focusable( @@ -37,14 +37,12 @@ pub fn focus(target: Id) -> impl Operation { state: &mut dyn state::Focusable, id: Option<&Id>, ) { - if state.is_focused() { - match id { - Some(id) if id == &self.target => { - state.focus(); - } - _ => { - state.unfocus(); - } + match id { + Some(id) if id == &self.target => { + state.focus(); + } + _ => { + state.unfocus(); } } } @@ -52,7 +50,7 @@ pub fn focus(target: Id) -> impl Operation { fn container( &mut self, _id: Option<&Id>, - operate_on_children: &dyn Fn(&mut dyn Operation), + operate_on_children: &mut dyn FnMut(&mut dyn Operation), ) { operate_on_children(self) } -- cgit From 77c6864e7c772c5e228bc09fe40c2c0b8884386d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 2 Aug 2022 04:20:47 +0200 Subject: Implement `focus_next` operation ... as well as a `count_focusable` composable helper! --- native/src/widget/operation.rs | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'native/src/widget/operation.rs') diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs index 2cfba005..5a0f0c18 100644 --- a/native/src/widget/operation.rs +++ b/native/src/widget/operation.rs @@ -58,3 +58,96 @@ pub fn focus(target: Id) -> impl Operation { Focus { target } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct FocusCount { + focused: Option, + total: usize, +} + +pub fn count_focusable(f: fn(FocusCount) -> O) -> impl Operation +where + O: Operation + 'static, +{ + struct CountFocusable { + count: FocusCount, + next: fn(FocusCount) -> O, + } + + impl Operation for CountFocusable + where + O: Operation + 'static, + { + fn focusable( + &mut self, + state: &mut dyn state::Focusable, + _id: Option<&Id>, + ) { + if state.is_focused() { + self.count.focused = Some(self.count.total); + } + + self.count.total += 1; + } + + fn container( + &mut self, + _id: Option<&Id>, + operate_on_children: &mut dyn FnMut(&mut dyn Operation), + ) { + operate_on_children(self) + } + + fn finish(&self) -> Outcome { + Outcome::Chain(Box::new((self.next)(self.count))) + } + } + + CountFocusable { + count: FocusCount::default(), + next: f, + } +} + +pub fn focus_next() -> impl Operation { + struct FocusNext { + count: FocusCount, + current: usize, + } + + impl Operation for FocusNext { + fn focusable( + &mut self, + state: &mut dyn state::Focusable, + _id: Option<&Id>, + ) { + if self.count.total == 0 { + return; + } + + match self.count.focused { + None if self.current == 0 => state.focus(), + Some(focused) if focused == self.current => state.unfocus(), + Some(focused) if focused + 1 == self.current => state.focus(), + Some(focused) + if focused == self.count.total - 1 && self.current == 0 => + { + state.focus() + } + _ => {} + } + + self.current += 1; + } + + fn container( + &mut self, + _id: Option<&Id>, + operate_on_children: &mut dyn FnMut(&mut dyn Operation), + ) { + operate_on_children(self) + } + } + + count_focusable(|count| FocusNext { count, current: 0 }) +} -- cgit From 6eb3dd7e5edc8847875c288c41d1dec8b1dad06e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 Aug 2022 03:24:44 +0200 Subject: Implement `focus_previous` operation --- native/src/widget/operation.rs | 47 +++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'native/src/widget/operation.rs') diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs index 5a0f0c18..caf7ba1c 100644 --- a/native/src/widget/operation.rs +++ b/native/src/widget/operation.rs @@ -109,13 +109,13 @@ where } } -pub fn focus_next() -> impl Operation { - struct FocusNext { +pub fn focus_previous() -> impl Operation { + struct FocusPrevious { count: FocusCount, current: usize, } - impl Operation for FocusNext { + impl Operation for FocusPrevious { fn focusable( &mut self, state: &mut dyn state::Focusable, @@ -125,15 +125,46 @@ pub fn focus_next() -> impl Operation { return; } + match self.count.focused { + None if self.current == self.count.total - 1 => state.focus(), + Some(0) if self.current == 0 => state.unfocus(), + Some(0) => {} + Some(focused) if focused == self.current => state.unfocus(), + Some(focused) if focused - 1 == self.current => state.focus(), + _ => {} + } + + self.current += 1; + } + + fn container( + &mut self, + _id: Option<&Id>, + operate_on_children: &mut dyn FnMut(&mut dyn Operation), + ) { + operate_on_children(self) + } + } + + count_focusable(|count| FocusPrevious { count, current: 0 }) +} + +pub fn focus_next() -> impl Operation { + struct FocusNext { + count: FocusCount, + current: usize, + } + + impl Operation for FocusNext { + fn focusable( + &mut self, + state: &mut dyn state::Focusable, + _id: Option<&Id>, + ) { match self.count.focused { None if self.current == 0 => state.focus(), Some(focused) if focused == self.current => state.unfocus(), Some(focused) if focused + 1 == self.current => state.focus(), - Some(focused) - if focused == self.count.total - 1 && self.current == 0 => - { - state.focus() - } _ => {} } -- cgit From 13dd1ca0a83cc95eea52e2106da9dc1ee1f37958 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 Aug 2022 03:55:41 +0200 Subject: Implement `scrollable::snap_to` operation --- native/src/widget/operation.rs | 173 +++-------------------------------------- 1 file changed, 9 insertions(+), 164 deletions(-) (limited to 'native/src/widget/operation.rs') diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs index caf7ba1c..4a075da9 100644 --- a/native/src/widget/operation.rs +++ b/native/src/widget/operation.rs @@ -1,4 +1,9 @@ -use crate::widget::state; +pub mod focusable; +pub mod scrollable; + +pub use focusable::Focusable; +pub use scrollable::Scrollable; + use crate::widget::Id; pub trait Operation { @@ -8,12 +13,9 @@ pub trait Operation { operate_on_children: &mut dyn FnMut(&mut dyn Operation), ); - fn focusable( - &mut self, - _state: &mut dyn state::Focusable, - _id: Option<&Id>, - ) { - } + fn focusable(&mut self, _state: &mut dyn Focusable, _id: Option<&Id>) {} + + fn scrollable(&mut self, _state: &mut dyn Scrollable, _id: Option<&Id>) {} fn finish(&self) -> Outcome { Outcome::None @@ -25,160 +27,3 @@ pub enum Outcome { Some(T), Chain(Box>), } - -pub fn focus(target: Id) -> impl Operation { - struct Focus { - target: Id, - } - - impl Operation for Focus { - fn focusable( - &mut self, - state: &mut dyn state::Focusable, - id: Option<&Id>, - ) { - match id { - Some(id) if id == &self.target => { - state.focus(); - } - _ => { - state.unfocus(); - } - } - } - - fn container( - &mut self, - _id: Option<&Id>, - operate_on_children: &mut dyn FnMut(&mut dyn Operation), - ) { - operate_on_children(self) - } - } - - Focus { target } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct FocusCount { - focused: Option, - total: usize, -} - -pub fn count_focusable(f: fn(FocusCount) -> O) -> impl Operation -where - O: Operation + 'static, -{ - struct CountFocusable { - count: FocusCount, - next: fn(FocusCount) -> O, - } - - impl Operation for CountFocusable - where - O: Operation + 'static, - { - fn focusable( - &mut self, - state: &mut dyn state::Focusable, - _id: Option<&Id>, - ) { - if state.is_focused() { - self.count.focused = Some(self.count.total); - } - - self.count.total += 1; - } - - fn container( - &mut self, - _id: Option<&Id>, - operate_on_children: &mut dyn FnMut(&mut dyn Operation), - ) { - operate_on_children(self) - } - - fn finish(&self) -> Outcome { - Outcome::Chain(Box::new((self.next)(self.count))) - } - } - - CountFocusable { - count: FocusCount::default(), - next: f, - } -} - -pub fn focus_previous() -> impl Operation { - struct FocusPrevious { - count: FocusCount, - current: usize, - } - - impl Operation for FocusPrevious { - fn focusable( - &mut self, - state: &mut dyn state::Focusable, - _id: Option<&Id>, - ) { - if self.count.total == 0 { - return; - } - - match self.count.focused { - None if self.current == self.count.total - 1 => state.focus(), - Some(0) if self.current == 0 => state.unfocus(), - Some(0) => {} - Some(focused) if focused == self.current => state.unfocus(), - Some(focused) if focused - 1 == self.current => state.focus(), - _ => {} - } - - self.current += 1; - } - - fn container( - &mut self, - _id: Option<&Id>, - operate_on_children: &mut dyn FnMut(&mut dyn Operation), - ) { - operate_on_children(self) - } - } - - count_focusable(|count| FocusPrevious { count, current: 0 }) -} - -pub fn focus_next() -> impl Operation { - struct FocusNext { - count: FocusCount, - current: usize, - } - - impl Operation for FocusNext { - fn focusable( - &mut self, - state: &mut dyn state::Focusable, - _id: Option<&Id>, - ) { - match self.count.focused { - None if self.current == 0 => state.focus(), - Some(focused) if focused == self.current => state.unfocus(), - Some(focused) if focused + 1 == self.current => state.focus(), - _ => {} - } - - self.current += 1; - } - - fn container( - &mut self, - _id: Option<&Id>, - operate_on_children: &mut dyn FnMut(&mut dyn Operation), - ) { - operate_on_children(self) - } - } - - count_focusable(|count| FocusNext { count, current: 0 }) -} -- cgit From 66f7d43dc98df96c8b19cfd2aef6dcdd4187316c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 5 Aug 2022 05:15:41 +0200 Subject: Write missing documentation in `iced_native` --- native/src/widget/operation.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'native/src/widget/operation.rs') diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs index 4a075da9..ef636aa2 100644 --- a/native/src/widget/operation.rs +++ b/native/src/widget/operation.rs @@ -1,3 +1,4 @@ +//! Query or update internal widget state. pub mod focusable; pub mod scrollable; @@ -6,24 +7,54 @@ pub use scrollable::Scrollable; use crate::widget::Id; +use std::fmt; + +/// A piece of logic that can traverse the widget tree of an application in +/// order to query or update some widget state. pub trait Operation { + /// Operates on a widget that contains other widgets. + /// + /// The `operate_on_children` function can be called to return control to + /// the widget tree and keep traversing it. fn container( &mut self, id: Option<&Id>, operate_on_children: &mut dyn FnMut(&mut dyn Operation), ); + /// Operates on a widget that can be focused. fn focusable(&mut self, _state: &mut dyn Focusable, _id: Option<&Id>) {} + /// Operates on a widget that can be scrolled. fn scrollable(&mut self, _state: &mut dyn Scrollable, _id: Option<&Id>) {} + /// Finishes the [`Operation`] and returns its [`Outcome`]. fn finish(&self) -> Outcome { Outcome::None } } +/// The result of an [`Operation`]. pub enum Outcome { + /// The [`Operation`] produced no result. None, + + /// The [`Operation`] produced some result. Some(T), + + /// The [`Operation`] needs to be followed by another [`Operation`]. Chain(Box>), } + +impl fmt::Debug for Outcome +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::None => write!(f, "Outcome::None"), + Self::Some(output) => write!(f, "Outcome::Some({:?})", output), + Self::Chain(_) => write!(f, "Outcome::Chain(...)"), + } + } +} -- cgit