diff --git a/examples/typed_input/src/main.rs b/examples/typed_input/src/main.rs index aa67b22a..6b261ad0 100644 --- a/examples/typed_input/src/main.rs +++ b/examples/typed_input/src/main.rs @@ -37,12 +37,12 @@ impl TypedInputDemo { fn view(&self) -> Element { let lb_minute = Text::new("Typed Input:"); - let txt_minute = typed_input::TypedInput::new(self.value, Message::TypedInpChanged); + let txt_minute = typed_input::TypedInput::new(&self.value, Message::TypedInpChanged); Container::new( Row::new() .spacing(10) - .align_items(Alignment::Center) + .align_y(Alignment::Center) .push(lb_minute) .push(txt_minute), ) diff --git a/src/widgets/number_input.rs b/src/widgets/number_input.rs index 0428c7d3..78a79da8 100644 --- a/src/widgets/number_input.rs +++ b/src/widgets/number_input.rs @@ -30,6 +30,7 @@ use std::{ }; use crate::style::{self, Status}; +use crate::widgets::typed_input::TypedInput; pub use crate::{ core::icons::{bootstrap::icon_to_string, Bootstrap, BOOTSTRAP_FONT}, style::{ @@ -37,7 +38,6 @@ pub use crate::{ StyleFn, }, }; -use crate::widgets::typed_input::TypedInput; /// The default padding const DEFAULT_PADDING: f32 = 5.0; @@ -125,7 +125,7 @@ where max: Self::set_max(bounds.end_bound()), padding, size: None, - content: TypedInput::new(value, on_changed) + content: TypedInput::new(&value, on_changed) .padding(padding) .width(Length::Fixed(127.0)) .class(Theme::default_input()), @@ -453,14 +453,11 @@ where let child = state.children.get_mut(0).expect("fail to get child"); let text_input = child - .children - .get_mut(0) - .expect("fail to get text input") .state .downcast_mut::>(); let modifiers = state.state.downcast_mut::(); - let current_text = self.content.text().to_string(); + let current_text = self.content.text().to_owned(); let mut forward_to_text = |event, shell, child, clipboard| { self.content.on_event( @@ -492,9 +489,7 @@ where } let mut new_val = current_text; match text_input.cursor().state(&Value::new(&new_val)) { - cursor::State::Index(idx) - if idx >= 1 && idx <= new_val.len() => - { + cursor::State::Index(idx) if idx >= 1 && idx <= new_val.len() => { _ = new_val.remove(idx - 1); } cursor::State::Selection { start, end } @@ -511,17 +506,14 @@ where match T::from_str(&new_val) { Ok(val) - if (self.min..self.max).contains(&val) - && val != self.value => + if (self.min..self.max).contains(&val) && val != self.value => { self.value = val; forward_to_text(event, shell, child, clipboard) } - Ok(val) - if (self.min..self.max).contains(&val) => - { - forward_to_text(event, shell, child, clipboard) - } + Ok(val) if (self.min..self.max).contains(&val) => { + forward_to_text(event, shell, child, clipboard) + } Ok(_) => event::Status::Captured, _ => event::Status::Ignored, } @@ -560,11 +552,10 @@ where self.value = val; forward_to_text(event, shell, child, clipboard) } - Ok(val) - if (self.min..self.max).contains(&val) => - forward_to_text(event, shell, child, clipboard), - Ok(_) => - event::Status::Captured, + Ok(val) if (self.min..self.max).contains(&val) => { + forward_to_text(event, shell, child, clipboard) + } + Ok(_) => event::Status::Captured, _ => event::Status::Ignored, } } @@ -579,9 +570,10 @@ where event::Status::Captured } keyboard::Key::Named( - keyboard::key::Named::ArrowLeft | keyboard::key::Named::ArrowRight | - keyboard::key::Named::Home | - keyboard::key::Named::End, + keyboard::key::Named::ArrowLeft + | keyboard::key::Named::ArrowRight + | keyboard::key::Named::Home + | keyboard::key::Named::End, ) => forward_to_text(event, shell, child, clipboard), _ => event::Status::Ignored, }, diff --git a/src/widgets/typed_input.rs b/src/widgets/typed_input.rs index 570c7b08..75047809 100644 --- a/src/widgets/typed_input.rs +++ b/src/widgets/typed_input.rs @@ -2,17 +2,21 @@ //! //! *This API requires the following crate features to be activated: `typed_input`* -use iced::mouse::{self, Cursor}; -use iced::{widget::text_input::{self, TextInput}, Size, Event, event}; -use iced::advanced::layout::{Node, Limits, Layout}; -use iced::advanced::widget::{Tree, Widget, tree::{State, Tag}, Operation}; +use iced::advanced::layout::{Layout, Limits, Node}; +use iced::advanced::widget::{ + tree::{State, Tag}, + Operation, Tree, Widget, +}; use iced::advanced::{Clipboard, Shell}; -use iced::{Length, Rectangle, Element}; - -use std::{ - fmt::Display, - str::FromStr, +use iced::mouse::{self, Cursor}; +use iced::{ + event, + widget::text_input::{self, TextInput}, + Event, Size, }; +use iced::{Element, Length, Rectangle}; + +use std::{fmt::Display, str::FromStr}; /// The default padding const DEFAULT_PADDING: f32 = 5.0; @@ -72,26 +76,24 @@ where /// It expects: /// - the current value /// - a function that produces a message when the [`TypedInput`] changes - pub fn new(value: T, on_changed: F) -> Self + pub fn new(value: &T, on_changed: F) -> Self where F: 'static + Fn(T) -> Message + Copy, T: 'a + Clone, { let padding = DEFAULT_PADDING; - // let move_value = value.clone(); - // let convert_to_t = move |s: String| on_changed(T::from_str(&s).unwrap_or(move_value.clone())); - Self { - value: value.clone(), + Self { + value: value.clone(), text_input: text_input::TextInput::new("", format!("{value}").as_str()) .on_input(InternalMessage::OnChange) .on_submit(InternalMessage::OnSubmit) .padding(padding) .width(Length::Fixed(127.0)) - .class(::default()), + .class(::default()), text: value.to_string(), on_change: Box::new(on_changed), - on_submit: None, + on_submit: None, font: Renderer::Font::default(), } } @@ -157,11 +159,7 @@ where /// Sets the class of the input of the [`TypedInput`]. #[must_use] - pub fn class( - mut self, - class: impl Into<::Class<'a>>, - ) -> Self - { + pub fn class(mut self, class: impl Into<::Class<'a>>) -> Self { self.text_input = self.text_input.class(class); self } @@ -176,49 +174,48 @@ where Theme: text_input::Catalog, { fn tag(&self) -> Tag { - Tag::of::<()>() + as Widget<_, _, _>>::tag(&self.text_input) } fn state(&self) -> State { - State::new(()) + as Widget<_, _, _>>::state(&self.text_input) } fn children(&self) -> Vec { - vec![Tree { - tag: self.text_input.tag(), - state: self.text_input.state(), - children: self.text_input.children(), - }] + as Widget<_, _, _>>::children(&self.text_input) } - fn diff(&self, tree: &mut Tree) { - tree.diff_children_custom( - &[&self.text_input], - |state, content| content.diff(state), - |&content| Tree { - tag: content.tag(), - state: content.state(), - children: content.children(), - }, - ); + fn diff(&self, state: &mut Tree) { + as Widget<_, _, _>>::diff(&self.text_input, state); } fn size(&self) -> Size { as Widget<_, _, _>>::size(&self.text_input) } - fn layout(&self, tree: &mut Tree,renderer: &Renderer, limits: &Limits) -> Node { - let content = as Widget<_, _, _>>::layout(&self.text_input, &mut tree.children[0], renderer, limits); - let size = limits.resolve(Length::Shrink, Length::Shrink, content.size()); - Node::with_children( - size, - vec![ content ] - ) + fn layout(&self, state: &mut Tree, renderer: &Renderer, limits: &Limits) -> Node { + as Widget<_, _, _>>::layout(&self.text_input, state, renderer, limits) } - fn draw(&self, tree: &Tree, renderer: &mut Renderer, theme: &Theme, style: &iced::advanced::renderer::Style, layout: Layout<'_>, cursor: Cursor, viewport: &Rectangle) { - let mut children = layout.children(); - let text_input_layout = children.next().expect("fail to get TextInput layout"); - as Widget<_, _, _>>::draw(&self.text_input, &tree.children[0], renderer, theme, style, text_input_layout, cursor, viewport); + fn draw( + &self, + state: &Tree, + renderer: &mut Renderer, + theme: &Theme, + style: &iced::advanced::renderer::Style, + layout: Layout<'_>, + cursor: Cursor, + viewport: &Rectangle, + ) { + as Widget<_, _, _>>::draw( + &self.text_input, + state, + renderer, + theme, + style, + layout, + cursor, + viewport, + ); } fn mouse_interaction( @@ -229,17 +226,30 @@ where viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { - as Widget<_, _, _>>::mouse_interaction(&self.text_input, &state.children[0], layout.children().next().expect("TypedInput inner child Textbox was not created."), cursor, viewport, renderer) + as Widget<_, _, _>>::mouse_interaction( + &self.text_input, + state, + layout, + cursor, + viewport, + renderer, + ) } fn operate( &self, - tree: &mut Tree, + state: &mut Tree, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn Operation<()>, ) { - as Widget<_, _, _>>::operate(&self.text_input, &mut tree.children[0], layout.children().next().expect("TypedInput inner child Textbox was not created."), renderer, operation) + as Widget<_, _, _>>::operate( + &self.text_input, + state, + layout, + renderer, + operation, + ); } #[allow(clippy::too_many_lines, clippy::cognitive_complexity)] @@ -254,17 +264,19 @@ where shell: &mut Shell, viewport: &Rectangle, ) -> event::Status { - let text_input_layout = layout.children().next().expect("fail to get text_input layout"); - - let child = &mut state.children[0]; - let mut messages = Vec::new(); let mut sub_shell = Shell::new(&mut messages); let status = self.text_input.on_event( - child, event, text_input_layout, cursor, renderer, clipboard, &mut sub_shell, viewport, - ); - // todo!() - // println!("shell: {:?}", shell); + state, + event, + layout, + cursor, + renderer, + clipboard, + &mut sub_shell, + viewport, + ); + if let Some(redraw) = sub_shell.redraw_request() { shell.request_redraw(redraw); } @@ -296,7 +308,6 @@ where } status } - } impl<'a, T, Message, Theme, Renderer> From>