diff options
-rw-r--r-- | native/src/element.rs | 37 | ||||
-rw-r--r-- | native/src/user_interface.rs | 8 | ||||
-rw-r--r-- | native/src/widget.rs | 1 | ||||
-rw-r--r-- | native/src/widget/action.rs | 6 | ||||
-rw-r--r-- | native/src/widget/button.rs | 16 | ||||
-rw-r--r-- | native/src/widget/column.rs | 19 | ||||
-rw-r--r-- | native/src/widget/container.rs | 17 | ||||
-rw-r--r-- | native/src/widget/operation.rs | 18 | ||||
-rw-r--r-- | native/src/widget/row.rs | 19 | ||||
-rw-r--r-- | native/src/widget/scrollable.rs | 16 | ||||
-rw-r--r-- | native/src/widget/text_input.rs | 39 | ||||
-rw-r--r-- | src/widget.rs | 4 |
12 files changed, 178 insertions, 22 deletions
diff --git a/native/src/element.rs b/native/src/element.rs index cc74035e..01b71aa4 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -3,6 +3,7 @@ use crate::layout; use crate::mouse; use crate::overlay; use crate::renderer; +use crate::widget; use crate::widget::tree::{self, Tree}; use crate::{Clipboard, Layout, Length, Point, Rectangle, Shell, Widget}; @@ -248,6 +249,42 @@ where self.widget.layout(renderer, limits) } + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + operation: &mut dyn widget::Operation<B>, + ) { + struct MapOperation<'a, B> { + operation: &'a mut dyn widget::Operation<B>, + } + + impl<'a, T, B> widget::Operation<T> for MapOperation<'a, B> { + fn container( + &mut self, + id: Option<&widget::Id>, + operate_on_children: &mut dyn FnMut( + &mut dyn widget::Operation<T>, + ), + ) { + self.operation.container(id, &mut |operation| { + operate_on_children(&mut MapOperation { operation }); + }); + } + + fn focusable( + &mut self, + state: &mut dyn widget::state::Focusable, + id: Option<&widget::Id>, + ) { + self.operation.focusable(state, id); + } + } + + self.widget + .operate(tree, layout, &mut MapOperation { operation }); + } + fn on_event( &mut self, tree: &mut Tree, diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 25557240..42669f95 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -485,9 +485,11 @@ where renderer: &Renderer, operation: &mut dyn widget::Operation<Message>, ) { - self.root - .as_widget() - .operate(Layout::new(&self.base), operation); + self.root.as_widget().operate( + &mut self.state, + Layout::new(&self.base), + operation, + ); if let Some(layout) = self.overlay.as_ref() { if let Some(overlay) = self.root.as_widget().overlay( diff --git a/native/src/widget.rs b/native/src/widget.rs index 79f6ae3a..56ba28c8 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -171,6 +171,7 @@ where /// Applies an [`Operation`] to the [`Widget`]. fn operate( &self, + _state: &mut Tree, _layout: Layout<'_>, _operation: &mut dyn Operation<Message>, ) { diff --git a/native/src/widget/action.rs b/native/src/widget/action.rs index 23ea4269..69723358 100644 --- a/native/src/widget/action.rs +++ b/native/src/widget/action.rs @@ -42,7 +42,7 @@ where fn container( &mut self, id: Option<&Id>, - operate_on_children: &dyn Fn(&mut dyn Operation<B>), + operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>), ) { struct MapRef<'a, A, B> { operation: &'a mut dyn Operation<A>, @@ -53,11 +53,11 @@ where fn container( &mut self, id: Option<&Id>, - operate_on_children: &dyn Fn(&mut dyn Operation<B>), + operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>), ) { let Self { operation, f } = self; - operation.container(id, &|operation| { + operation.container(id, &mut |operation| { operate_on_children(&mut MapRef { operation, f }); }); } diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index 6eac6c1b..6c0b8f6e 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -8,6 +8,7 @@ use crate::overlay; use crate::renderer; use crate::touch; use crate::widget::tree::{self, Tree}; +use crate::widget::Operation; use crate::{ Background, Clipboard, Color, Element, Layout, Length, Padding, Point, Rectangle, Shell, Vector, Widget, @@ -164,6 +165,21 @@ where ) } + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + operation: &mut dyn Operation<Message>, + ) { + operation.container(None, &mut |operation| { + self.content.as_widget().operate( + &mut tree.children[0], + layout.children().next().unwrap(), + operation, + ); + }); + } + fn on_event( &mut self, tree: &mut Tree, diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index 834f9858..a8b0f183 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -4,7 +4,7 @@ use crate::layout; use crate::mouse; use crate::overlay; use crate::renderer; -use crate::widget::Tree; +use crate::widget::{Operation, Tree}; use crate::{ Alignment, Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget, @@ -143,6 +143,23 @@ where ) } + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + operation: &mut dyn Operation<Message>, + ) { + operation.container(None, &mut |operation| { + self.children + .iter() + .zip(&mut tree.children) + .zip(layout.children()) + .for_each(|((child, state), layout)| { + child.as_widget().operate(state, layout, operation); + }) + }); + } + fn on_event( &mut self, tree: &mut Tree, diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index b0fa0315..2afad3f2 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -5,7 +5,7 @@ use crate::layout; use crate::mouse; use crate::overlay; use crate::renderer; -use crate::widget::Tree; +use crate::widget::{Operation, Tree}; use crate::{ Background, Clipboard, Color, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget, @@ -165,6 +165,21 @@ where ) } + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + operation: &mut dyn Operation<Message>, + ) { + operation.container(None, &mut |operation| { + self.content.as_widget().operate( + &mut tree.children[0], + layout.children().next().unwrap(), + operation, + ); + }); + } + fn on_event( &mut self, tree: &mut Tree, 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<T> { fn container( &mut self, id: Option<&Id>, - operate_on_children: &dyn Fn(&mut dyn Operation<T>), + operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), ); fn focusable( @@ -37,14 +37,12 @@ pub fn focus<T>(target: Id) -> impl Operation<T> { 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<T>(target: Id) -> impl Operation<T> { fn container( &mut self, _id: Option<&Id>, - operate_on_children: &dyn Fn(&mut dyn Operation<T>), + operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), ) { operate_on_children(self) } diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs index c342c277..eda7c2d3 100644 --- a/native/src/widget/row.rs +++ b/native/src/widget/row.rs @@ -4,7 +4,7 @@ use crate::layout::{self, Layout}; use crate::mouse; use crate::overlay; use crate::renderer; -use crate::widget::Tree; +use crate::widget::{Operation, Tree}; use crate::{ Alignment, Clipboard, Element, Length, Padding, Point, Rectangle, Shell, Widget, @@ -130,6 +130,23 @@ where ) } + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + operation: &mut dyn Operation<Message>, + ) { + operation.container(None, &mut |operation| { + self.children + .iter() + .zip(&mut tree.children) + .zip(layout.children()) + .for_each(|((child, state), layout)| { + child.as_widget().operate(state, layout, operation); + }) + }); + } + fn on_event( &mut self, tree: &mut Tree, diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index b40c3743..91c13eb5 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -6,6 +6,7 @@ use crate::overlay; use crate::renderer; use crate::touch; use crate::widget::tree::{self, Tree}; +use crate::widget::Operation; use crate::{ Background, Clipboard, Color, Element, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget, @@ -150,6 +151,21 @@ where ) } + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + operation: &mut dyn Operation<Message>, + ) { + operation.container(None, &mut |operation| { + self.content.as_widget().operate( + &mut tree.children[0], + layout.children().next().unwrap(), + operation, + ); + }); + } + fn on_event( &mut self, tree: &mut Tree, diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 1dbb8d6b..1ca5ccf2 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -19,11 +19,13 @@ use crate::mouse::{self, click}; use crate::renderer; use crate::text::{self, Text}; use crate::touch; +use crate::widget; +use crate::widget::operation::{self, Operation}; use crate::widget::state; use crate::widget::tree::{self, Tree}; use crate::{ - Clipboard, Color, Element, Layout, Length, Padding, Point, Rectangle, - Shell, Size, Vector, Widget, + Clipboard, Color, Command, Element, Layout, Length, Padding, Point, + Rectangle, Shell, Size, Vector, Widget, }; pub use iced_style::text_input::{Appearance, StyleSheet}; @@ -54,6 +56,7 @@ where Renderer: text::Renderer, Renderer::Theme: StyleSheet, { + id: Option<Id>, placeholder: String, value: Value, is_secure: bool, @@ -84,6 +87,7 @@ where F: 'a + Fn(String) -> Message, { TextInput { + id: None, placeholder: String::from(placeholder), value: Value::new(value), is_secure: false, @@ -98,6 +102,12 @@ where } } + /// Sets the [`Id`] of the [`TextInput`]. + pub fn id(mut self, id: Id) -> Self { + self.id = Some(id); + self + } + /// Converts the [`TextInput`] into a secure password input. pub fn password(mut self) -> Self { self.is_secure = true; @@ -215,6 +225,17 @@ where layout(renderer, limits, self.width, self.padding, self.size) } + fn operate( + &self, + tree: &mut Tree, + _layout: Layout<'_>, + operation: &mut dyn Operation<Message>, + ) { + let state = tree.state.downcast_mut::<State>(); + + operation.focusable(state, self.id.as_ref().map(|id| &id.0)); + } + fn on_event( &mut self, tree: &mut Tree, @@ -294,6 +315,19 @@ where } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Id(widget::Id); + +impl Id { + pub fn new(id: impl Into<std::borrow::Cow<'static, str>>) -> Self { + Self(widget::Id::new(id)) + } +} + +pub fn focus<Message: 'static>(id: Id) -> Command<Message> { + Command::widget(operation::focus(id.0)) +} + /// Computes the layout of a [`TextInput`]. pub fn layout<Renderer>( renderer: &Renderer, @@ -915,6 +949,7 @@ impl State { /// Focuses the [`TextInput`]. pub fn focus(&mut self) { self.is_focused = true; + self.move_cursor_to_end(); } /// Unfocuses the [`TextInput`]. diff --git a/src/widget.rs b/src/widget.rs index 4ddf0566..abffadd5 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -119,7 +119,9 @@ pub mod toggler { pub mod text_input { //! Display fields that can be filled with text. - pub use iced_native::widget::text_input::{Appearance, StyleSheet}; + pub use iced_native::widget::text_input::{ + focus, Appearance, Id, StyleSheet, + }; /// A field that can be filled with text. pub type TextInput<'a, Message, Renderer = crate::Renderer> = |