diff options
Diffstat (limited to '')
38 files changed, 845 insertions, 266 deletions
diff --git a/native/src/element.rs b/native/src/element.rs index 955e1bee..2f1adeff 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -316,6 +316,22 @@ where              ) {                  self.operation.focusable(state, id);              } + +            fn scrollable( +                &mut self, +                state: &mut dyn widget::operation::Scrollable, +                id: Option<&widget::Id>, +            ) { +                self.operation.scrollable(state, id); +            } + +            fn text_input( +                &mut self, +                state: &mut dyn widget::operation::TextInput, +                id: Option<&widget::Id>, +            ) { +                self.operation.text_input(state, id); +            }          }          self.widget @@ -389,7 +405,7 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer, @@ -544,7 +560,7 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          state: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer, diff --git a/native/src/image.rs b/native/src/image.rs index 516eb2db..06fd7ae6 100644 --- a/native/src/image.rs +++ b/native/src/image.rs @@ -1,6 +1,7 @@  //! Load and draw raster graphics. -use crate::{Hasher, Rectangle}; +use crate::{Hasher, Rectangle, Size}; +use std::borrow::Cow;  use std::hash::{Hash, Hasher as _};  use std::path::PathBuf;  use std::sync::Arc; @@ -21,15 +22,19 @@ impl Handle {      }      /// Creates an image [`Handle`] containing the image pixels directly. This -    /// function expects the input data to be provided as a `Vec<u8>` of BGRA +    /// function expects the input data to be provided as a `Vec<u8>` of RGBA      /// pixels.      ///      /// This is useful if you have already decoded your image. -    pub fn from_pixels(width: u32, height: u32, pixels: Vec<u8>) -> Handle { -        Self::from_data(Data::Pixels { +    pub fn from_pixels( +        width: u32, +        height: u32, +        pixels: impl Into<Cow<'static, [u8]>>, +    ) -> Handle { +        Self::from_data(Data::Rgba {              width,              height, -            pixels, +            pixels: pixels.into(),          })      } @@ -39,8 +44,8 @@ impl Handle {      ///      /// This is useful if you already have your image loaded in-memory, maybe      /// because you downloaded or generated it procedurally. -    pub fn from_memory(bytes: Vec<u8>) -> Handle { -        Self::from_data(Data::Bytes(bytes)) +    pub fn from_memory(bytes: impl Into<Cow<'static, [u8]>>) -> Handle { +        Self::from_data(Data::Bytes(bytes.into()))      }      fn from_data(data: Data) -> Handle { @@ -86,16 +91,16 @@ pub enum Data {      Path(PathBuf),      /// In-memory data -    Bytes(Vec<u8>), +    Bytes(Cow<'static, [u8]>), -    /// Decoded image pixels in BGRA format. -    Pixels { +    /// Decoded image pixels in RGBA format. +    Rgba {          /// The width of the image.          width: u32,          /// The height of the image.          height: u32,          /// The pixels. -        pixels: Vec<u8>, +        pixels: Cow<'static, [u8]>,      },  } @@ -104,7 +109,7 @@ impl std::fmt::Debug for Data {          match self {              Data::Path(path) => write!(f, "Path({:?})", path),              Data::Bytes(_) => write!(f, "Bytes(...)"), -            Data::Pixels { width, height, .. } => { +            Data::Rgba { width, height, .. } => {                  write!(f, "Pixels({} * {})", width, height)              }          } @@ -121,7 +126,7 @@ pub trait Renderer: crate::Renderer {      type Handle: Clone + Hash;      /// Returns the dimensions of an image for the given [`Handle`]. -    fn dimensions(&self, handle: &Self::Handle) -> (u32, u32); +    fn dimensions(&self, handle: &Self::Handle) -> Size<u32>;      /// Draws an image with the given [`Handle`] and inside the provided      /// `bounds`. diff --git a/native/src/lib.rs b/native/src/lib.rs index 02269265..62b8f372 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -23,8 +23,8 @@  //! - Build a new renderer, see the [renderer] module.  //! - Build a custom widget, start at the [`Widget`] trait.  //! -//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.4/core -//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.4/winit +//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.5/core +//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.5/winit  //! [`druid`]: https://github.com/xi-editor/druid  //! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle  //! [renderer]: crate::renderer diff --git a/native/src/overlay.rs b/native/src/overlay.rs index 905d3389..0b05b058 100644 --- a/native/src/overlay.rs +++ b/native/src/overlay.rs @@ -11,7 +11,7 @@ use crate::layout;  use crate::mouse;  use crate::renderer;  use crate::widget; -use crate::widget::tree::{self, Tree}; +use crate::widget::Tree;  use crate::{Clipboard, Layout, Point, Rectangle, Shell, Size};  /// An interactive component that can be displayed on top of other widgets. @@ -42,31 +42,9 @@ where          cursor_position: Point,      ); -    /// Returns the [`Tag`] of the [`Widget`]. -    /// -    /// [`Tag`]: tree::Tag -    fn tag(&self) -> tree::Tag { -        tree::Tag::stateless() -    } - -    /// Returns the [`State`] of the [`Widget`]. -    /// -    /// [`State`]: tree::State -    fn state(&self) -> tree::State { -        tree::State::None -    } - -    /// Returns the state [`Tree`] of the children of the [`Widget`]. -    fn children(&self) -> Vec<Tree> { -        Vec::new() -    } - -    /// Reconciliates the [`Widget`] with the provided [`Tree`]. -    fn diff(&self, _tree: &mut Tree) {} - -    /// Applies an [`Operation`] to the [`Widget`]. +    /// Applies a [`widget::Operation`] to the [`Overlay`].      fn operate( -        &self, +        &mut self,          _layout: Layout<'_>,          _operation: &mut dyn widget::Operation<Message>,      ) { @@ -115,7 +93,7 @@ where  /// This method will generally only be used by advanced users that are  /// implementing the [`Widget`](crate::Widget) trait.  pub fn from_children<'a, Message, Renderer>( -    children: &'a [crate::Element<'_, Message, Renderer>], +    children: &'a mut [crate::Element<'_, Message, Renderer>],      tree: &'a mut Tree,      layout: Layout<'_>,      renderer: &Renderer, @@ -124,11 +102,11 @@ where      Renderer: crate::Renderer,  {      children -        .iter() +        .iter_mut()          .zip(&mut tree.children)          .zip(layout.children())          .filter_map(|((child, state), layout)| { -            child.as_widget().overlay(state, layout, renderer) +            child.as_widget_mut().overlay(state, layout, renderer)          })          .next()  } diff --git a/native/src/overlay/element.rs b/native/src/overlay/element.rs index b919c221..4f5ef32a 100644 --- a/native/src/overlay/element.rs +++ b/native/src/overlay/element.rs @@ -104,9 +104,9 @@ where              .draw(renderer, theme, style, layout, cursor_position)      } -    /// Applies an [`Operation`] to the [`Element`]. +    /// Applies a [`widget::Operation`] to the [`Element`].      pub fn operate( -        &self, +        &mut self,          layout: Layout<'_>,          operation: &mut dyn widget::Operation<Message>,      ) { @@ -141,6 +141,57 @@ where          self.content.layout(renderer, bounds, position)      } +    fn operate( +        &mut self, +        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::operation::Focusable, +                id: Option<&widget::Id>, +            ) { +                self.operation.focusable(state, id); +            } + +            fn scrollable( +                &mut self, +                state: &mut dyn widget::operation::Scrollable, +                id: Option<&widget::Id>, +            ) { +                self.operation.scrollable(state, id); +            } + +            fn text_input( +                &mut self, +                state: &mut dyn widget::operation::TextInput, +                id: Option<&widget::Id>, +            ) { +                self.operation.text_input(state, id) +            } +        } + +        self.content +            .operate(layout, &mut MapOperation { operation }); +    } +      fn on_event(          &mut self,          event: Event, diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs index dbcf23d4..099b1a97 100644 --- a/native/src/overlay/menu.rs +++ b/native/src/overlay/menu.rs @@ -9,7 +9,7 @@ use crate::text::{self, Text};  use crate::touch;  use crate::widget::container::{self, Container};  use crate::widget::scrollable::{self, Scrollable}; -use crate::widget::tree::{self, Tree}; +use crate::widget::Tree;  use crate::{      Clipboard, Color, Element, Layout, Length, Padding, Point, Rectangle,      Shell, Size, Vector, Widget, @@ -178,7 +178,7 @@ where              font,              text_size,              padding, -            style, +            style: style.clone(),          }));          state.tree.diff(&container as &dyn Widget<_, _>); @@ -199,18 +199,6 @@ where      Renderer: text::Renderer,      Renderer::Theme: StyleSheet + container::StyleSheet,  { -    fn tag(&self) -> tree::Tag { -        self.container.tag() -    } - -    fn state(&self) -> tree::State { -        self.container.state() -    } - -    fn children(&self) -> Vec<Tree> { -        self.container.children() -    } -      fn layout(          &self,          renderer: &Renderer, @@ -288,7 +276,7 @@ where          layout: Layout<'_>,          cursor_position: Point,      ) { -        let appearance = theme.appearance(self.style); +        let appearance = theme.appearance(&self.style);          let bounds = layout.bounds();          renderer.fill_quad( @@ -460,7 +448,7 @@ where          _cursor_position: Point,          viewport: &Rectangle,      ) { -        let appearance = theme.appearance(self.style); +        let appearance = theme.appearance(&self.style);          let bounds = layout.bounds();          let text_size = diff --git a/native/src/subscription.rs b/native/src/subscription.rs index 9775c84b..d24801d4 100644 --- a/native/src/subscription.rs +++ b/native/src/subscription.rs @@ -155,7 +155,7 @@ where  /// Check out the [`websocket`] example, which showcases this pattern to maintain a WebSocket  /// connection open.  /// -/// [`websocket`]: https://github.com/iced-rs/iced/tree/0.4/examples/websocket +/// [`websocket`]: https://github.com/iced-rs/iced/tree/0.5/examples/websocket  pub fn unfold<I, T, Fut, Message>(      id: I,      initial: T, diff --git a/native/src/svg.rs b/native/src/svg.rs index f86fec5b..a8e481d2 100644 --- a/native/src/svg.rs +++ b/native/src/svg.rs @@ -1,6 +1,7 @@  //! Load and draw vector graphics. -use crate::{Hasher, Rectangle}; +use crate::{Hasher, Rectangle, Size}; +use std::borrow::Cow;  use std::hash::{Hash, Hasher as _};  use std::path::PathBuf;  use std::sync::Arc; @@ -24,7 +25,7 @@ impl Handle {      ///      /// This is useful if you already have your SVG data in-memory, maybe      /// because you downloaded or generated it procedurally. -    pub fn from_memory(bytes: impl Into<Vec<u8>>) -> Handle { +    pub fn from_memory(bytes: impl Into<Cow<'static, [u8]>>) -> Handle {          Self::from_data(Data::Bytes(bytes.into()))      } @@ -64,7 +65,7 @@ pub enum Data {      /// In-memory data      ///      /// Can contain an SVG string or a gzip compressed data. -    Bytes(Vec<u8>), +    Bytes(Cow<'static, [u8]>),  }  impl std::fmt::Debug for Data { @@ -81,7 +82,7 @@ impl std::fmt::Debug for Data {  /// [renderer]: crate::renderer  pub trait Renderer: crate::Renderer {      /// Returns the default dimensions of an SVG for the given [`Handle`]. -    fn dimensions(&self, handle: &Handle) -> (u32, u32); +    fn dimensions(&self, handle: &Handle) -> Size<u32>;      /// Draws an SVG with the given [`Handle`] and inside the provided `bounds`.      fn draw(&mut self, handle: Handle, bounds: Rectangle); diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 344ba4d6..6b853da8 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -18,8 +18,8 @@ use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};  /// The [`integration_opengl`] & [`integration_wgpu`] examples use a  /// [`UserInterface`] to integrate Iced in an existing graphical application.  /// -/// [`integration_opengl`]: https://github.com/iced-rs/iced/tree/0.4/examples/integration_opengl -/// [`integration_wgpu`]: https://github.com/iced-rs/iced/tree/0.4/examples/integration_wgpu +/// [`integration_opengl`]: https://github.com/iced-rs/iced/tree/0.5/examples/integration_opengl +/// [`integration_wgpu`]: https://github.com/iced-rs/iced/tree/0.5/examples/integration_wgpu  #[allow(missing_debug_implementations)]  pub struct UserInterface<'a, Message, Renderer> {      root: Element<'a, Message, Renderer>, @@ -190,7 +190,7 @@ where          let mut state = State::Updated;          let mut manual_overlay = -            ManuallyDrop::new(self.root.as_widget().overlay( +            ManuallyDrop::new(self.root.as_widget_mut().overlay(                  &mut self.state,                  Layout::new(&self.base),                  renderer, @@ -226,7 +226,7 @@ where                      );                      manual_overlay = -                        ManuallyDrop::new(self.root.as_widget().overlay( +                        ManuallyDrop::new(self.root.as_widget_mut().overlay(                              &mut self.state,                              Layout::new(&self.base),                              renderer, @@ -285,6 +285,10 @@ where                      &mut shell,                  ); +                if matches!(event_status, event::Status::Captured) { +                    self.overlay = None; +                } +                  shell.revalidate_layout(|| {                      self.base = renderer.layout(                          &self.root, @@ -391,11 +395,11 @@ where          let viewport = Rectangle::with_size(self.bounds); -        let base_cursor = if let Some(overlay) = self.root.as_widget().overlay( -            &mut self.state, -            Layout::new(&self.base), -            renderer, -        ) { +        let base_cursor = if let Some(overlay) = self +            .root +            .as_widget_mut() +            .overlay(&mut self.state, Layout::new(&self.base), renderer) +        {              let overlay_layout = self                  .overlay                  .take() @@ -448,7 +452,7 @@ where          overlay              .as_ref()              .and_then(|layout| { -                root.as_widget() +                root.as_widget_mut()                      .overlay(&mut self.state, Layout::new(base), renderer)                      .map(|overlay| {                          let overlay_interaction = overlay.mouse_interaction( @@ -492,14 +496,19 @@ where              operation,          ); -        if let Some(layout) = self.overlay.as_ref() { -            if let Some(overlay) = self.root.as_widget().overlay( -                &mut self.state, -                Layout::new(&self.base), -                renderer, -            ) { -                overlay.operate(Layout::new(layout), operation); +        if let Some(mut overlay) = self.root.as_widget_mut().overlay( +            &mut self.state, +            Layout::new(&self.base), +            renderer, +        ) { +            if self.overlay.is_none() { +                self.overlay = Some(overlay.layout(renderer, self.bounds));              } + +            overlay.operate( +                Layout::new(self.overlay.as_ref().unwrap()), +                operation, +            );          }      } diff --git a/native/src/widget.rs b/native/src/widget.rs index 8890b8e7..36d679a4 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -107,12 +107,12 @@ use crate::{Clipboard, Layout, Length, Point, Rectangle, Shell};  /// - [`geometry`], a custom widget showcasing how to draw geometry with the  /// `Mesh2D` primitive in [`iced_wgpu`].  /// -/// [examples]: https://github.com/iced-rs/iced/tree/0.4/examples -/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.4/examples/bezier_tool -/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.4/examples/custom_widget -/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.4/examples/geometry +/// [examples]: https://github.com/iced-rs/iced/tree/0.5/examples +/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.5/examples/bezier_tool +/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.5/examples/custom_widget +/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.5/examples/geometry  /// [`lyon`]: https://github.com/nical/lyon -/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.4/wgpu +/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.5/wgpu  pub trait Widget<Message, Renderer>  where      Renderer: crate::Renderer, @@ -208,7 +208,7 @@ where      /// Returns the overlay of the [`Widget`], if there is any.      fn overlay<'a>( -        &'a self, +        &'a mut self,          _state: &'a mut Tree,          _layout: Layout<'_>,          _renderer: &Renderer, diff --git a/native/src/widget/action.rs b/native/src/widget/action.rs index 766e902b..9aa79dec 100644 --- a/native/src/widget/action.rs +++ b/native/src/widget/action.rs @@ -1,8 +1,10 @@ -use crate::widget::operation::{self, Operation}; +use crate::widget::operation::{self, Focusable, Operation, Scrollable};  use crate::widget::Id;  use iced_futures::MaybeSend; +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>>); @@ -24,7 +26,7 @@ impl<T> Action<T> {      {          Action(Box::new(Map {              operation: self.0, -            f: Box::new(f), +            f: Rc::new(f),          }))      } @@ -37,7 +39,7 @@ impl<T> Action<T> {  #[allow(missing_debug_implementations)]  struct Map<A, B> {      operation: Box<dyn Operation<A>>, -    f: Box<dyn Fn(A) -> B>, +    f: Rc<dyn Fn(A) -> B>,  }  impl<A, B> Operation<B> for Map<A, B> @@ -50,30 +52,44 @@ where          id: Option<&Id>,          operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),      ) { -        struct MapRef<'a, A, B> { +        struct MapRef<'a, A> {              operation: &'a mut dyn Operation<A>, -            f: &'a dyn Fn(A) -> B,          } -        impl<'a, A, B> Operation<B> for MapRef<'a, A, B> { +        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, f } = self; +                let Self { operation, .. } = self;                  operation.container(id, &mut |operation| { -                    operate_on_children(&mut MapRef { operation, f }); +                    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); +            }          } -        let Self { operation, f } = self; +        let Self { operation, .. } = self;          MapRef {              operation: operation.as_mut(), -            f,          }          .container(id, operate_on_children);      } @@ -85,4 +101,35 @@ where      ) {          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 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/native/src/widget/button.rs b/native/src/widget/button.rs index 14759cfd..bbd9451c 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -231,7 +231,7 @@ where              cursor_position,              self.on_press.is_some(),              theme, -            self.style, +            &self.style,              || tree.state.downcast_ref::<State>(),          ); @@ -260,12 +260,12 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'b, Message, Renderer>> { -        self.content.as_widget().overlay( +        self.content.as_widget_mut().overlay(              &mut tree.children[0],              layout.children().next().unwrap(),              renderer, @@ -361,7 +361,7 @@ pub fn draw<'a, Renderer: crate::Renderer>(      style_sheet: &dyn StyleSheet<          Style = <Renderer::Theme as StyleSheet>::Style,      >, -    style: <Renderer::Theme as StyleSheet>::Style, +    style: &<Renderer::Theme as StyleSheet>::Style,      state: impl FnOnce() -> &'a State,  ) -> Appearance  where @@ -426,12 +426,13 @@ pub fn layout<Renderer>(      padding: Padding,      layout_content: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,  ) -> layout::Node { -    let limits = limits.width(width).height(height).pad(padding); +    let limits = limits.width(width).height(height); -    let mut content = layout_content(renderer, &limits); -    content.move_to(Point::new(padding.left.into(), padding.top.into())); +    let mut content = layout_content(renderer, &limits.pad(padding)); +    let padding = padding.fit(content.size(), limits.max()); +    let size = limits.pad(padding).resolve(content.size()).pad(padding); -    let size = limits.resolve(content.size()).pad(padding); +    content.move_to(Point::new(padding.left.into(), padding.top.into()));      layout::Node::with_children(size, vec![content])  } diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 8f30037a..bec5c448 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -224,9 +224,9 @@ where          let mut children = layout.children();          let custom_style = if is_mouse_over { -            theme.hovered(self.style, self.is_checked) +            theme.hovered(&self.style, self.is_checked)          } else { -            theme.active(self.style, self.is_checked) +            theme.active(&self.style, self.is_checked)          };          { diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index a8b0f183..8030778b 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -242,12 +242,12 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'b, Message, Renderer>> { -        overlay::from_children(&self.children, tree, layout, renderer) +        overlay::from_children(&mut self.children, tree, layout, renderer)      }  } diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index b0c4938a..16d0cb61 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -228,7 +228,7 @@ where          cursor_position: Point,          viewport: &Rectangle,      ) { -        let style = theme.appearance(self.style); +        let style = theme.appearance(&self.style);          draw_background(renderer, &style, layout.bounds()); @@ -248,12 +248,12 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'b, Message, Renderer>> { -        self.content.as_widget().overlay( +        self.content.as_widget_mut().overlay(              &mut tree.children[0],              layout.children().next().unwrap(),              renderer, @@ -293,11 +293,11 @@ pub fn layout<Renderer>(          .max_width(max_width)          .max_height(max_height)          .width(width) -        .height(height) -        .pad(padding); +        .height(height); -    let mut content = layout_content(renderer, &limits.loose()); -    let size = limits.resolve(content.size()); +    let mut content = layout_content(renderer, &limits.pad(padding).loose()); +    let padding = padding.fit(content.size(), limits.max()); +    let size = limits.pad(padding).resolve(content.size());      content.move_to(Point::new(padding.left.into(), padding.top.into()));      content.align( @@ -309,7 +309,7 @@ pub fn layout<Renderer>(      layout::Node::with_children(size.pad(padding), vec![content])  } -/// Draws the background of a [`Container`] given its [`Style`] and its `bounds`. +/// Draws the background of a [`Container`] given its [`Appearance`] and its `bounds`.  pub fn draw_background<Renderer>(      renderer: &mut Renderer,      appearance: &Appearance, diff --git a/native/src/widget/helpers.rs b/native/src/widget/helpers.rs index 79751878..3bce9e60 100644 --- a/native/src/widget/helpers.rs +++ b/native/src/widget/helpers.rs @@ -1,4 +1,5 @@  //! Helper functions to create pure widgets. +use crate::overlay;  use crate::widget;  use crate::{Element, Length}; @@ -18,7 +19,7 @@ macro_rules! column {      );  } -/// Creates a [Row`] with the given children. +/// Creates a [`Row`] with the given children.  ///  /// [`Row`]: widget::Row  #[macro_export] @@ -84,6 +85,7 @@ pub fn button<'a, Message, Renderer>(  where      Renderer: crate::Renderer,      Renderer::Theme: widget::button::StyleSheet, +    <Renderer::Theme as widget::button::StyleSheet>::Style: Default,  {      widget::Button::new(content)  } @@ -208,7 +210,12 @@ where      T: ToString + Eq + 'static,      [T]: ToOwned<Owned = Vec<T>>,      Renderer: crate::text::Renderer, -    Renderer::Theme: widget::pick_list::StyleSheet, +    Renderer::Theme: widget::pick_list::StyleSheet +        + widget::scrollable::StyleSheet +        + overlay::menu::StyleSheet +        + widget::container::StyleSheet, +    <Renderer::Theme as overlay::menu::StyleSheet>::Style: +        From<<Renderer::Theme as widget::pick_list::StyleSheet>::Style>,  {      widget::PickList::new(options, selected, on_selected)  } diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index 91d68e34..8bd8ca1e 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -85,7 +85,7 @@ where  {      // The raw w/h of the underlying image      let image_size = { -        let (width, height) = renderer.dimensions(handle); +        let Size { width, height } = renderer.dimensions(handle);          Size::new(width as f32, height as f32)      }; @@ -149,7 +149,7 @@ where          _cursor_position: Point,          _viewport: &Rectangle,      ) { -        let (width, height) = renderer.dimensions(&self.handle); +        let Size { width, height } = renderer.dimensions(&self.handle);          let image_size = Size::new(width as f32, height as f32);          let bounds = layout.bounds(); diff --git a/native/src/widget/image/viewer.rs b/native/src/widget/image/viewer.rs index b1fe596c..9c83287e 100644 --- a/native/src/widget/image/viewer.rs +++ b/native/src/widget/image/viewer.rs @@ -108,7 +108,7 @@ where          renderer: &Renderer,          limits: &layout::Limits,      ) -> layout::Node { -        let (width, height) = renderer.dimensions(&self.handle); +        let Size { width, height } = renderer.dimensions(&self.handle);          let mut size = limits              .width(self.width) @@ -409,7 +409,7 @@ pub fn image_size<Renderer>(  where      Renderer: image::Renderer,  { -    let (width, height) = renderer.dimensions(handle); +    let Size { width, height } = renderer.dimensions(handle);      let (width, height) = {          let dimensions = (width as f32, height as f32); diff --git a/native/src/widget/operation.rs b/native/src/widget/operation.rs index ef636aa2..a0aa4117 100644 --- a/native/src/widget/operation.rs +++ b/native/src/widget/operation.rs @@ -1,9 +1,11 @@  //! Query or update internal widget state.  pub mod focusable;  pub mod scrollable; +pub mod text_input;  pub use focusable::Focusable;  pub use scrollable::Scrollable; +pub use text_input::TextInput;  use crate::widget::Id; @@ -28,6 +30,9 @@ pub trait Operation<T> {      /// Operates on a widget that can be scrolled.      fn scrollable(&mut self, _state: &mut dyn Scrollable, _id: Option<&Id>) {} +    /// Operates on a widget that has text input. +    fn text_input(&mut self, _state: &mut dyn TextInput, _id: Option<&Id>) {} +      /// Finishes the [`Operation`] and returns its [`Outcome`].      fn finish(&self) -> Outcome<T> {          Outcome::None @@ -58,3 +63,46 @@ where          }      }  } + +/// Produces an [`Operation`] that applies the given [`Operation`] to the +/// children of a container with the given [`Id`]. +pub fn scoped<T: 'static>( +    target: Id, +    operation: impl Operation<T> + 'static, +) -> impl Operation<T> { +    struct ScopedOperation<Message> { +        target: Id, +        operation: Box<dyn Operation<Message>>, +    } + +    impl<Message: 'static> Operation<Message> for ScopedOperation<Message> { +        fn container( +            &mut self, +            id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<Message>), +        ) { +            if id == Some(&self.target) { +                operate_on_children(self.operation.as_mut()); +            } else { +                operate_on_children(self); +            } +        } + +        fn finish(&self) -> Outcome<Message> { +            match self.operation.finish() { +                Outcome::Chain(next) => { +                    Outcome::Chain(Box::new(ScopedOperation { +                        target: self.target.clone(), +                        operation: next, +                    })) +                } +                outcome => outcome, +            } +        } +    } + +    ScopedOperation { +        target, +        operation: Box::new(operation), +    } +} diff --git a/native/src/widget/operation/focusable.rs b/native/src/widget/operation/focusable.rs index f17bf178..0067006b 100644 --- a/native/src/widget/operation/focusable.rs +++ b/native/src/widget/operation/focusable.rs @@ -167,3 +167,37 @@ pub fn focus_next<T>() -> impl Operation<T> {      count(|count| FocusNext { count, current: 0 })  } + +/// Produces an [`Operation`] that searches for the current focused widget +/// and stores its ID. This ignores widgets that do not have an ID. +pub fn find_focused() -> impl Operation<Id> { +    struct FindFocused { +        focused: Option<Id>, +    } + +    impl Operation<Id> for FindFocused { +        fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { +            if state.is_focused() && id.is_some() { +                self.focused = id.cloned(); +            } +        } + +        fn container( +            &mut self, +            _id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<Id>), +        ) { +            operate_on_children(self) +        } + +        fn finish(&self) -> Outcome<Id> { +            if let Some(id) = &self.focused { +                Outcome::Some(id.clone()) +            } else { +                Outcome::None +            } +        } +    } + +    FindFocused { focused: None } +} diff --git a/native/src/widget/operation/text_input.rs b/native/src/widget/operation/text_input.rs new file mode 100644 index 00000000..4c773e99 --- /dev/null +++ b/native/src/widget/operation/text_input.rs @@ -0,0 +1,131 @@ +//! Operate on widgets that have text input. +use crate::widget::operation::Operation; +use crate::widget::Id; + +/// The internal state of a widget that has text input. +pub trait TextInput { +    /// Moves the cursor of the text input to the front of the input text. +    fn move_cursor_to_front(&mut self); +    /// Moves the cursor of the text input to the end of the input text. +    fn move_cursor_to_end(&mut self); +    /// Moves the cursor of the text input to an arbitrary location. +    fn move_cursor_to(&mut self, position: usize); +    /// Selects all the content of the text input. +    fn select_all(&mut self); +} + +/// Produces an [`Operation`] that moves the cursor of the widget with the given [`Id`] to the +/// front. +pub fn move_cursor_to_front<T>(target: Id) -> impl Operation<T> { +    struct MoveCursor { +        target: Id, +    } + +    impl<T> Operation<T> for MoveCursor { +        fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { +            match id { +                Some(id) if id == &self.target => { +                    state.move_cursor_to_front(); +                } +                _ => {} +            } +        } + +        fn container( +            &mut self, +            _id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), +        ) { +            operate_on_children(self) +        } +    } + +    MoveCursor { target } +} + +/// Produces an [`Operation`] that moves the cursor of the widget with the given [`Id`] to the +/// end. +pub fn move_cursor_to_end<T>(target: Id) -> impl Operation<T> { +    struct MoveCursor { +        target: Id, +    } + +    impl<T> Operation<T> for MoveCursor { +        fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { +            match id { +                Some(id) if id == &self.target => { +                    state.move_cursor_to_end(); +                } +                _ => {} +            } +        } + +        fn container( +            &mut self, +            _id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), +        ) { +            operate_on_children(self) +        } +    } + +    MoveCursor { target } +} + +/// Produces an [`Operation`] that moves the cursor of the widget with the given [`Id`] to the +/// provided position. +pub fn move_cursor_to<T>(target: Id, position: usize) -> impl Operation<T> { +    struct MoveCursor { +        target: Id, +        position: usize, +    } + +    impl<T> Operation<T> for MoveCursor { +        fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { +            match id { +                Some(id) if id == &self.target => { +                    state.move_cursor_to(self.position); +                } +                _ => {} +            } +        } + +        fn container( +            &mut self, +            _id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), +        ) { +            operate_on_children(self) +        } +    } + +    MoveCursor { target, position } +} + +/// Produces an [`Operation`] that selects all the content of the widget with the given [`Id`]. +pub fn select_all<T>(target: Id) -> impl Operation<T> { +    struct MoveCursor { +        target: Id, +    } + +    impl<T> Operation<T> for MoveCursor { +        fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { +            match id { +                Some(id) if id == &self.target => { +                    state.select_all(); +                } +                _ => {} +            } +        } + +        fn container( +            &mut self, +            _id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), +        ) { +            operate_on_children(self) +        } +    } + +    MoveCursor { target } +} diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 45090ecf..edad993e 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -6,7 +6,7 @@  //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,  //! drag and drop, and hotkey support.  //! -//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid +//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.5/examples/pane_grid  mod axis;  mod configuration;  mod content; @@ -38,6 +38,7 @@ use crate::mouse;  use crate::overlay;  use crate::renderer;  use crate::touch; +use crate::widget;  use crate::widget::container;  use crate::widget::tree::{self, Tree};  use crate::{ @@ -85,7 +86,7 @@ use crate::{  /// let (mut state, _) = pane_grid::State::new(PaneState::SomePane);  ///  /// let pane_grid = -///     PaneGrid::new(&state, |pane, state| { +///     PaneGrid::new(&state, |pane, state, is_maximized| {  ///         pane_grid::Content::new(match state {  ///             PaneState::SomePane => text("This is some pane"),  ///             PaneState::AnotherKindOfPane => text("This is another kind of pane"), @@ -100,8 +101,7 @@ where      Renderer: crate::Renderer,      Renderer::Theme: StyleSheet + container::StyleSheet,  { -    state: &'a state::Internal, -    elements: Vec<(Pane, Content<'a, Message, Renderer>)>, +    contents: Contents<'a, Content<'a, Message, Renderer>>,      width: Length,      height: Length,      spacing: u16, @@ -119,22 +119,35 @@ where      /// Creates a [`PaneGrid`] with the given [`State`] and view function.      ///      /// The view function will be called to display each [`Pane`] present in the -    /// [`State`]. +    /// [`State`]. [`bool`] is set if the pane is maximized.      pub fn new<T>(          state: &'a State<T>, -        view: impl Fn(Pane, &'a T) -> Content<'a, Message, Renderer>, +        view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Renderer>,      ) -> Self { -        let elements = { -            state -                .panes -                .iter() -                .map(|(pane, pane_state)| (*pane, view(*pane, pane_state))) -                .collect() +        let contents = if let Some((pane, pane_state)) = +            state.maximized.and_then(|pane| { +                state.panes.get(&pane).map(|pane_state| (pane, pane_state)) +            }) { +            Contents::Maximized( +                pane, +                view(pane, pane_state, true), +                Node::Pane(pane), +            ) +        } else { +            Contents::All( +                state +                    .panes +                    .iter() +                    .map(|(pane, pane_state)| { +                        (*pane, view(*pane, pane_state, false)) +                    }) +                    .collect(), +                &state.internal, +            )          };          Self { -            elements, -            state: &state.internal, +            contents,              width: Length::Fill,              height: Length::Fill,              spacing: 0, @@ -208,6 +221,12 @@ where          self.style = style.into();          self      } + +    fn drag_enabled(&self) -> bool { +        (!self.contents.is_maximized()) +            .then(|| self.on_drag.is_some()) +            .unwrap_or_default() +    }  }  impl<'a, Message, Renderer> Widget<Message, Renderer> @@ -225,18 +244,25 @@ where      }      fn children(&self) -> Vec<Tree> { -        self.elements +        self.contents              .iter()              .map(|(_, content)| content.state())              .collect()      }      fn diff(&self, tree: &mut Tree) { -        tree.diff_children_custom( -            &self.elements, -            |state, (_, content)| content.diff(state), -            |(_, content)| content.state(), -        ) +        match &self.contents { +            Contents::All(contents, _) => tree.diff_children_custom( +                contents, +                |state, (_, content)| content.diff(state), +                |(_, content)| content.state(), +            ), +            Contents::Maximized(_, content, _) => tree.diff_children_custom( +                &[content], +                |state, content| content.diff(state), +                |content| content.state(), +            ), +        }      }      fn width(&self) -> Length { @@ -255,15 +281,32 @@ where          layout(              renderer,              limits, -            self.state, +            self.contents.layout(),              self.width,              self.height,              self.spacing, -            self.elements.iter().map(|(pane, content)| (*pane, content)), -            |element, renderer, limits| element.layout(renderer, limits), +            self.contents.iter(), +            |content, renderer, limits| content.layout(renderer, limits),          )      } +    fn operate( +        &self, +        tree: &mut Tree, +        layout: Layout<'_>, +        operation: &mut dyn widget::Operation<Message>, +    ) { +        operation.container(None, &mut |operation| { +            self.contents +                .iter() +                .zip(&mut tree.children) +                .zip(layout.children()) +                .for_each(|(((_pane, content), state), layout)| { +                    content.operate(state, layout, operation); +                }) +        }); +    } +      fn on_event(          &mut self,          tree: &mut Tree, @@ -276,28 +319,34 @@ where      ) -> event::Status {          let action = tree.state.downcast_mut::<state::Action>(); +        let on_drag = if self.drag_enabled() { +            &self.on_drag +        } else { +            &None +        }; +          let event_status = update(              action, -            self.state, +            self.contents.layout(),              &event,              layout,              cursor_position,              shell,              self.spacing, -            self.elements.iter().map(|(pane, content)| (*pane, content)), +            self.contents.iter(),              &self.on_click, -            &self.on_drag, +            on_drag,              &self.on_resize,          );          let picked_pane = action.picked_pane().map(|(pane, _)| pane); -        self.elements +        self.contents              .iter_mut()              .zip(&mut tree.children)              .zip(layout.children())              .map(|(((pane, content), tree), layout)| { -                let is_picked = picked_pane == Some(*pane); +                let is_picked = picked_pane == Some(pane);                  content.on_event(                      tree, @@ -323,14 +372,14 @@ where      ) -> mouse::Interaction {          mouse_interaction(              tree.state.downcast_ref(), -            self.state, +            self.contents.layout(),              layout,              cursor_position,              self.spacing,              self.on_resize.as_ref().map(|(leeway, _)| *leeway),          )          .unwrap_or_else(|| { -            self.elements +            self.contents                  .iter()                  .zip(&tree.children)                  .zip(layout.children()) @@ -341,7 +390,7 @@ where                          cursor_position,                          viewport,                          renderer, -                        self.on_drag.is_some(), +                        self.drag_enabled(),                      )                  })                  .max() @@ -361,7 +410,7 @@ where      ) {          draw(              tree.state.downcast_ref(), -            self.state, +            self.contents.layout(),              layout,              cursor_position,              renderer, @@ -370,11 +419,11 @@ where              viewport,              self.spacing,              self.on_resize.as_ref().map(|(leeway, _)| *leeway), -            self.style, -            self.elements +            &self.style, +            self.contents                  .iter()                  .zip(&tree.children) -                .map(|((pane, content), tree)| (*pane, (content, tree))), +                .map(|((pane, content), tree)| (pane, (content, tree))),              |(content, tree),               renderer,               style, @@ -395,13 +444,13 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'_, Message, Renderer>> { -        self.elements -            .iter() +        self.contents +            .iter_mut()              .zip(&mut tree.children)              .zip(layout.children())              .filter_map(|(((_, pane), tree), layout)| { @@ -429,24 +478,24 @@ where  pub fn layout<Renderer, T>(      renderer: &Renderer,      limits: &layout::Limits, -    state: &state::Internal, +    node: &Node,      width: Length,      height: Length,      spacing: u16, -    elements: impl Iterator<Item = (Pane, T)>, -    layout_element: impl Fn(T, &Renderer, &layout::Limits) -> layout::Node, +    contents: impl Iterator<Item = (Pane, T)>, +    layout_content: impl Fn(T, &Renderer, &layout::Limits) -> layout::Node,  ) -> layout::Node {      let limits = limits.width(width).height(height);      let size = limits.resolve(Size::ZERO); -    let regions = state.pane_regions(f32::from(spacing), size); -    let children = elements -        .filter_map(|(pane, element)| { +    let regions = node.pane_regions(f32::from(spacing), size); +    let children = contents +        .filter_map(|(pane, content)| {              let region = regions.get(&pane)?;              let size = Size::new(region.width, region.height); -            let mut node = layout_element( -                element, +            let mut node = layout_content( +                content,                  renderer,                  &layout::Limits::new(size, size),              ); @@ -464,13 +513,13 @@ pub fn layout<Renderer, T>(  /// accordingly.  pub fn update<'a, Message, T: Draggable>(      action: &mut state::Action, -    state: &state::Internal, +    node: &Node,      event: &Event,      layout: Layout<'_>,      cursor_position: Point,      shell: &mut Shell<'_, Message>,      spacing: u16, -    elements: impl Iterator<Item = (Pane, T)>, +    contents: impl Iterator<Item = (Pane, T)>,      on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>,      on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,      on_resize: &Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>, @@ -492,7 +541,7 @@ pub fn update<'a, Message, T: Draggable>(                              cursor_position.y - bounds.y,                          ); -                        let splits = state.split_regions( +                        let splits = node.split_regions(                              f32::from(spacing),                              Size::new(bounds.width, bounds.height),                          ); @@ -514,7 +563,7 @@ pub fn update<'a, Message, T: Draggable>(                                  layout,                                  cursor_position,                                  shell, -                                elements, +                                contents,                                  on_click,                                  on_drag,                              ); @@ -526,7 +575,7 @@ pub fn update<'a, Message, T: Draggable>(                              layout,                              cursor_position,                              shell, -                            elements, +                            contents,                              on_click,                              on_drag,                          ); @@ -539,7 +588,7 @@ pub fn update<'a, Message, T: Draggable>(          | Event::Touch(touch::Event::FingerLost { .. }) => {              if let Some((pane, _)) = action.picked_pane() {                  if let Some(on_drag) = on_drag { -                    let mut dropped_region = elements +                    let mut dropped_region = contents                          .zip(layout.children())                          .filter(|(_, layout)| {                              layout.bounds().contains(cursor_position) @@ -570,7 +619,7 @@ pub fn update<'a, Message, T: Draggable>(                  if let Some((split, _)) = action.picked_split() {                      let bounds = layout.bounds(); -                    let splits = state.split_regions( +                    let splits = node.split_regions(                          f32::from(spacing),                          Size::new(bounds.width, bounds.height),                      ); @@ -609,13 +658,13 @@ fn click_pane<'a, Message, T>(      layout: Layout<'_>,      cursor_position: Point,      shell: &mut Shell<'_, Message>, -    elements: impl Iterator<Item = (Pane, T)>, +    contents: impl Iterator<Item = (Pane, T)>,      on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>,      on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,  ) where      T: Draggable,  { -    let mut clicked_region = elements +    let mut clicked_region = contents          .zip(layout.children())          .filter(|(_, layout)| layout.bounds().contains(cursor_position)); @@ -642,7 +691,7 @@ fn click_pane<'a, Message, T>(  /// Returns the current [`mouse::Interaction`] of a [`PaneGrid`].  pub fn mouse_interaction(      action: &state::Action, -    state: &state::Internal, +    node: &Node,      layout: Layout<'_>,      cursor_position: Point,      spacing: u16, @@ -658,7 +707,7 @@ pub fn mouse_interaction(                  let bounds = layout.bounds();                  let splits = -                    state.split_regions(f32::from(spacing), bounds.size()); +                    node.split_regions(f32::from(spacing), bounds.size());                  let relative_cursor = Point::new(                      cursor_position.x - bounds.x, @@ -687,7 +736,7 @@ pub fn mouse_interaction(  /// Draws a [`PaneGrid`].  pub fn draw<Renderer, T>(      action: &state::Action, -    state: &state::Internal, +    node: &Node,      layout: Layout<'_>,      cursor_position: Point,      renderer: &mut Renderer, @@ -696,8 +745,8 @@ pub fn draw<Renderer, T>(      viewport: &Rectangle,      spacing: u16,      resize_leeway: Option<u16>, -    style: <Renderer::Theme as StyleSheet>::Style, -    elements: impl Iterator<Item = (Pane, T)>, +    style: &<Renderer::Theme as StyleSheet>::Style, +    contents: impl Iterator<Item = (Pane, T)>,      draw_pane: impl Fn(          T,          &mut Renderer, @@ -717,7 +766,7 @@ pub fn draw<Renderer, T>(          .and_then(|(split, axis)| {              let bounds = layout.bounds(); -            let splits = state.split_regions(f32::from(spacing), bounds.size()); +            let splits = node.split_regions(f32::from(spacing), bounds.size());              let (_axis, region, ratio) = splits.get(&split)?; @@ -736,7 +785,7 @@ pub fn draw<Renderer, T>(                  );                  let splits = -                    state.split_regions(f32::from(spacing), bounds.size()); +                    node.split_regions(f32::from(spacing), bounds.size());                  let (_split, axis, region) = hovered_split(                      splits.iter(), @@ -759,7 +808,7 @@ pub fn draw<Renderer, T>(      let mut render_picked_pane = None; -    for ((id, pane), layout) in elements.zip(layout.children()) { +    for ((id, pane), layout) in contents.zip(layout.children()) {          match picked_pane {              Some((dragging, origin)) if id == dragging => {                  render_picked_pane = Some((pane, origin, layout)); @@ -897,3 +946,49 @@ fn hovered_split<'a>(          })          .next()  } + +/// The visible contents of the [`PaneGrid`] +#[derive(Debug)] +pub enum Contents<'a, T> { +    /// All panes are visible +    All(Vec<(Pane, T)>, &'a state::Internal), +    /// A maximized pane is visible +    Maximized(Pane, T, Node), +} + +impl<'a, T> Contents<'a, T> { +    /// Returns the layout [`Node`] of the [`Contents`] +    pub fn layout(&self) -> &Node { +        match self { +            Contents::All(_, state) => state.layout(), +            Contents::Maximized(_, _, layout) => layout, +        } +    } + +    /// Returns an iterator over the values of the [`Contents`] +    pub fn iter(&self) -> Box<dyn Iterator<Item = (Pane, &T)> + '_> { +        match self { +            Contents::All(contents, _) => Box::new( +                contents.iter().map(|(pane, content)| (*pane, content)), +            ), +            Contents::Maximized(pane, content, _) => { +                Box::new(std::iter::once((*pane, content))) +            } +        } +    } + +    fn iter_mut(&mut self) -> Box<dyn Iterator<Item = (Pane, &mut T)> + '_> { +        match self { +            Contents::All(contents, _) => Box::new( +                contents.iter_mut().map(|(pane, content)| (*pane, content)), +            ), +            Contents::Maximized(pane, content, _) => { +                Box::new(std::iter::once((*pane, content))) +            } +        } +    } + +    fn is_maximized(&self) -> bool { +        matches!(self, Self::Maximized(..)) +    } +} diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index c236d820..5f269d1f 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -5,7 +5,7 @@ use crate::overlay;  use crate::renderer;  use crate::widget::container;  use crate::widget::pane_grid::{Draggable, TitleBar}; -use crate::widget::Tree; +use crate::widget::{self, Tree};  use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};  /// The content of a [`Pane`]. @@ -87,7 +87,7 @@ where      /// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`].      /// -    /// [`Renderer`]: iced_native::Renderer +    /// [`Renderer`]: crate::Renderer      pub fn draw(          &self,          tree: &Tree, @@ -103,7 +103,7 @@ where          let bounds = layout.bounds();          { -            let style = theme.appearance(self.style); +            let style = theme.appearance(&self.style);              container::draw_background(renderer, &style, bounds);          } @@ -183,6 +183,33 @@ where          }      } +    pub(crate) fn operate( +        &self, +        tree: &mut Tree, +        layout: Layout<'_>, +        operation: &mut dyn widget::Operation<Message>, +    ) { +        let body_layout = if let Some(title_bar) = &self.title_bar { +            let mut children = layout.children(); + +            title_bar.operate( +                &mut tree.children[1], +                children.next().unwrap(), +                operation, +            ); + +            children.next().unwrap() +        } else { +            layout +        }; + +        self.body.as_widget().operate( +            &mut tree.children[0], +            body_layout, +            operation, +        ); +    } +      pub(crate) fn on_event(          &mut self,          tree: &mut Tree, @@ -278,12 +305,12 @@ where      }      pub(crate) fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'b, Message, Renderer>> { -        if let Some(title_bar) = self.title_bar.as_ref() { +        if let Some(title_bar) = self.title_bar.as_mut() {              let mut children = layout.children();              let title_bar_layout = children.next()?; @@ -294,14 +321,14 @@ where              match title_bar.overlay(title_bar_state, title_bar_layout, renderer)              {                  Some(overlay) => Some(overlay), -                None => self.body.as_widget().overlay( +                None => self.body.as_widget_mut().overlay(                      body_state,                      children.next()?,                      renderer,                  ),              }          } else { -            self.body.as_widget().overlay( +            self.body.as_widget_mut().overlay(                  &mut tree.children[0],                  layout,                  renderer, diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs index cdca6267..c4ae0a0e 100644 --- a/native/src/widget/pane_grid/state.rs +++ b/native/src/widget/pane_grid/state.rs @@ -4,9 +4,9 @@  use crate::widget::pane_grid::{      Axis, Configuration, Direction, Node, Pane, Split,  }; -use crate::{Point, Rectangle, Size}; +use crate::{Point, Size}; -use std::collections::{BTreeMap, HashMap}; +use std::collections::HashMap;  /// The state of a [`PaneGrid`].  /// @@ -31,6 +31,11 @@ pub struct State<T> {      ///      /// [`PaneGrid`]: crate::widget::PaneGrid      pub internal: Internal, + +    /// The maximized [`Pane`] of the [`PaneGrid`]. +    /// +    /// [`PaneGrid`]: crate::widget::PaneGrid +    pub(super) maximized: Option<Pane>,  }  impl<T> State<T> { @@ -52,7 +57,11 @@ impl<T> State<T> {          let internal =              Internal::from_configuration(&mut panes, config.into(), 0); -        State { panes, internal } +        State { +            panes, +            internal, +            maximized: None, +        }      }      /// Returns the total amount of panes in the [`State`]. @@ -153,6 +162,7 @@ impl<T> State<T> {          node.split(new_split, axis, new_pane);          let _ = self.panes.insert(new_pane, state); +        let _ = self.maximized.take();          Some((new_pane, new_split))      } @@ -194,12 +204,39 @@ impl<T> State<T> {      /// Closes the given [`Pane`] and returns its internal state and its closest      /// sibling, if it exists.      pub fn close(&mut self, pane: &Pane) -> Option<(T, Pane)> { +        if self.maximized == Some(*pane) { +            let _ = self.maximized.take(); +        } +          if let Some(sibling) = self.internal.layout.remove(pane) {              self.panes.remove(pane).map(|state| (state, sibling))          } else {              None          }      } + +    /// Maximize the given [`Pane`]. Only this pane will be rendered by the +    /// [`PaneGrid`] until [`Self::restore()`] is called. +    /// +    /// [`PaneGrid`]: crate::widget::PaneGrid +    pub fn maximize(&mut self, pane: &Pane) { +        self.maximized = Some(*pane); +    } + +    /// Restore the currently maximized [`Pane`] to it's normal size. All panes +    /// will be rendered by the [`PaneGrid`]. +    /// +    /// [`PaneGrid`]: crate::widget::PaneGrid +    pub fn restore(&mut self) { +        let _ = self.maximized.take(); +    } + +    /// Returns the maximized [`Pane`] of the [`PaneGrid`]. +    /// +    /// [`PaneGrid`]: crate::widget::PaneGrid +    pub fn maximized(&self) -> Option<Pane> { +        self.maximized +    }  }  /// The internal state of a [`PaneGrid`]. @@ -226,11 +263,13 @@ impl Internal {                  let Internal {                      layout: a,                      last_id: next_id, +                    ..                  } = Self::from_configuration(panes, *a, next_id);                  let Internal {                      layout: b,                      last_id: next_id, +                    ..                  } = Self::from_configuration(panes, *b, next_id);                  ( @@ -304,25 +343,8 @@ impl Action {  }  impl Internal { -    /// Calculates the current [`Pane`] regions from the [`PaneGrid`] layout. -    /// -    /// [`PaneGrid`]: crate::widget::PaneGrid -    pub fn pane_regions( -        &self, -        spacing: f32, -        size: Size, -    ) -> BTreeMap<Pane, Rectangle> { -        self.layout.pane_regions(spacing, size) -    } - -    /// Calculates the current [`Split`] regions from the [`PaneGrid`] layout. -    /// -    /// [`PaneGrid`]: crate::widget::PaneGrid -    pub fn split_regions( -        &self, -        spacing: f32, -        size: Size, -    ) -> BTreeMap<Split, (Axis, Rectangle, f32)> { -        self.layout.split_regions(spacing, size) +    /// The layout [`Node`] of the [`Internal`] state +    pub fn layout(&self) -> &Node { +        &self.layout      }  } diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index eb85f924..28e4670f 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -4,7 +4,7 @@ use crate::mouse;  use crate::overlay;  use crate::renderer;  use crate::widget::container; -use crate::widget::Tree; +use crate::widget::{self, Tree};  use crate::{      Clipboard, Element, Layout, Padding, Point, Rectangle, Shell, Size,  }; @@ -114,7 +114,7 @@ where      /// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`].      /// -    /// [`Renderer`]: iced_native::Renderer +    /// [`Renderer`]: crate::Renderer      pub fn draw(          &self,          tree: &Tree, @@ -129,7 +129,7 @@ where          use container::StyleSheet;          let bounds = layout.bounds(); -        let style = theme.appearance(self.style); +        let style = theme.appearance(&self.style);          let inherited_style = renderer::Style {              text_color: style.text_color.unwrap_or(inherited_style.text_color),          }; @@ -257,6 +257,44 @@ where          layout::Node::with_children(node.size().pad(self.padding), vec![node])      } +    pub(crate) fn operate( +        &self, +        tree: &mut Tree, +        layout: Layout<'_>, +        operation: &mut dyn widget::Operation<Message>, +    ) { +        let mut children = layout.children(); +        let padded = children.next().unwrap(); + +        let mut children = padded.children(); +        let title_layout = children.next().unwrap(); +        let mut show_title = true; + +        if let Some(controls) = &self.controls { +            let controls_layout = children.next().unwrap(); + +            if title_layout.bounds().width + controls_layout.bounds().width +                > padded.bounds().width +            { +                show_title = false; +            } + +            controls.as_widget().operate( +                &mut tree.children[1], +                controls_layout, +                operation, +            ) +        }; + +        if show_title { +            self.content.as_widget().operate( +                &mut tree.children[0], +                title_layout, +                operation, +            ) +        } +    } +      pub(crate) fn on_event(          &mut self,          tree: &mut Tree, @@ -357,7 +395,7 @@ where      }      pub(crate) fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer, @@ -377,13 +415,13 @@ where          let controls_state = states.next().unwrap();          content -            .as_widget() +            .as_widget_mut()              .overlay(title_state, title_layout, renderer)              .or_else(move || { -                controls.as_ref().and_then(|controls| { +                controls.as_mut().and_then(|controls| {                      let controls_layout = children.next()?; -                    controls.as_widget().overlay( +                    controls.as_widget_mut().overlay(                          controls_state,                          controls_layout,                          renderer, diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index a92ea655..52cb1ad1 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -9,6 +9,8 @@ use crate::overlay::menu::{self, Menu};  use crate::renderer;  use crate::text::{self, Text};  use crate::touch; +use crate::widget::container; +use crate::widget::scrollable;  use crate::widget::tree::{self, Tree};  use crate::{      Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Size, @@ -42,7 +44,12 @@ where      T: ToString + Eq,      [T]: ToOwned<Owned = Vec<T>>,      Renderer: text::Renderer, -    Renderer::Theme: StyleSheet, +    Renderer::Theme: StyleSheet +        + scrollable::StyleSheet +        + menu::StyleSheet +        + container::StyleSheet, +    <Renderer::Theme as menu::StyleSheet>::Style: +        From<<Renderer::Theme as StyleSheet>::Style>,  {      /// The default padding of a [`PickList`].      pub const DEFAULT_PADDING: Padding = Padding::new(5); @@ -114,7 +121,12 @@ where      [T]: ToOwned<Owned = Vec<T>>,      Message: 'a,      Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet, +    Renderer::Theme: StyleSheet +        + scrollable::StyleSheet +        + menu::StyleSheet +        + container::StyleSheet, +    <Renderer::Theme as menu::StyleSheet>::Style: +        From<<Renderer::Theme as StyleSheet>::Style>,  {      fn tag(&self) -> tree::Tag {          tree::Tag::of::<State<T>>() @@ -202,12 +214,12 @@ where              &self.font,              self.placeholder.as_deref(),              self.selected.as_ref(), -            self.style, +            &self.style,          )      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          _renderer: &Renderer, @@ -221,7 +233,7 @@ where              self.text_size,              self.font.clone(),              &self.options, -            self.style, +            self.style.clone(),          )      }  } @@ -233,7 +245,12 @@ where      [T]: ToOwned<Owned = Vec<T>>,      Message: 'a,      Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet, +    Renderer::Theme: StyleSheet +        + scrollable::StyleSheet +        + menu::StyleSheet +        + container::StyleSheet, +    <Renderer::Theme as menu::StyleSheet>::Style: +        From<<Renderer::Theme as StyleSheet>::Style>,  {      fn from(pick_list: PickList<'a, T, Message, Renderer>) -> Self {          Self::new(pick_list) @@ -456,7 +473,12 @@ where      T: Clone + ToString,      Message: 'a,      Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet, +    Renderer::Theme: StyleSheet +        + scrollable::StyleSheet +        + menu::StyleSheet +        + container::StyleSheet, +    <Renderer::Theme as menu::StyleSheet>::Style: +        From<<Renderer::Theme as StyleSheet>::Style>,  {      if state.is_open {          let bounds = layout.bounds(); @@ -493,7 +515,7 @@ pub fn draw<T, Renderer>(      font: &Renderer::Font,      placeholder: Option<&str>,      selected: Option<&T>, -    style: <Renderer::Theme as StyleSheet>::Style, +    style: &<Renderer::Theme as StyleSheet>::Style,  ) where      Renderer: text::Renderer,      Renderer::Theme: StyleSheet, diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs index 5f8892fe..f059026f 100644 --- a/native/src/widget/progress_bar.rs +++ b/native/src/widget/progress_bar.rs @@ -124,7 +124,7 @@ where                  / (range_end - range_start)          }; -        let style = theme.appearance(self.style); +        let style = theme.appearance(&self.style);          renderer.fill_quad(              renderer::Quad { diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index 10e89870..b95ccc5b 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -230,9 +230,9 @@ where          let mut children = layout.children();          let custom_style = if is_mouse_over { -            theme.hovered(self.style, self.is_selected) +            theme.hovered(&self.style, self.is_selected)          } else { -            theme.active(self.style, self.is_selected) +            theme.active(&self.style, self.is_selected)          };          { diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs index eda7c2d3..c689ac13 100644 --- a/native/src/widget/row.rs +++ b/native/src/widget/row.rs @@ -229,12 +229,12 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'b, Message, Renderer>> { -        overlay::from_children(&self.children, tree, layout, renderer) +        overlay::from_children(&mut self.children, tree, layout, renderer)      }  } diff --git a/native/src/widget/rule.rs b/native/src/widget/rule.rs index 1d1c04cf..2dc7b6f0 100644 --- a/native/src/widget/rule.rs +++ b/native/src/widget/rule.rs @@ -88,7 +88,7 @@ where          _viewport: &Rectangle,      ) {          let bounds = layout.bounds(); -        let style = theme.style(self.style); +        let style = theme.appearance(&self.style);          let bounds = if self.is_horizontal {              let line_y = (bounds.y + (bounds.height / 2.0) diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index b445e505..a5e97aa7 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -233,7 +233,7 @@ where              self.scrollbar_width,              self.scrollbar_margin,              self.scroller_width, -            self.style, +            &self.style,              |renderer, layout, cursor_position, viewport| {                  self.content.as_widget().draw(                      &tree.children[0], @@ -276,13 +276,13 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'b, Message, Renderer>> {          self.content -            .as_widget() +            .as_widget_mut()              .overlay(                  &mut tree.children[0],                  layout.children().next().unwrap(), @@ -334,6 +334,12 @@ impl Id {      }  } +impl From<Id> for widget::Id { +    fn from(id: Id) -> Self { +        id.0 +    } +} +  /// Produces a [`Command`] that snaps the [`Scrollable`] with the given [`Id`]  /// to the provided `percentage`.  pub fn snap_to<Message: 'static>(id: Id, percentage: f32) -> Command<Message> { @@ -627,7 +633,7 @@ pub fn draw<Renderer>(      scrollbar_width: u16,      scrollbar_margin: u16,      scroller_width: u16, -    style: <Renderer::Theme as StyleSheet>::Style, +    style: &<Renderer::Theme as StyleSheet>::Style,      draw_content: impl FnOnce(&mut Renderer, Layout<'_>, Point, &Rectangle),  ) where      Renderer: crate::Renderer, diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index 011454de..87030a4d 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -222,7 +222,7 @@ where              self.value,              &self.range,              theme, -            self.style, +            &self.style,          )      } @@ -353,7 +353,7 @@ pub fn draw<T, R>(      value: T,      range: &RangeInclusive<T>,      style_sheet: &dyn StyleSheet<Style = <R::Theme as StyleSheet>::Style>, -    style: <R::Theme as StyleSheet>::Style, +    style: &<R::Theme as StyleSheet>::Style,  ) where      T: Into<f64> + Copy,      R: crate::Renderer, diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index aa68bfb8..1015ed0a 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -83,7 +83,7 @@ where          limits: &layout::Limits,      ) -> layout::Node {          // The raw w/h of the underlying image -        let (width, height) = renderer.dimensions(&self.handle); +        let Size { width, height } = renderer.dimensions(&self.handle);          let image_size = Size::new(width as f32, height as f32);          // The size to be available to the widget prior to `Shrink`ing @@ -120,7 +120,7 @@ where          _cursor_position: Point,          _viewport: &Rectangle,      ) { -        let (width, height) = renderer.dimensions(&self.handle); +        let Size { width, height } = renderer.dimensions(&self.handle);          let image_size = Size::new(width as f32, height as f32);          let bounds = layout.bounds(); diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs index dab6e874..be9e775e 100644 --- a/native/src/widget/text.rs +++ b/native/src/widget/text.rs @@ -74,7 +74,7 @@ where          self      } -    /// Sets the [`Color`] of the [`Text`]. +    /// Sets the style of the [`Text`].      pub fn style(          mut self,          style: impl Into<<Renderer::Theme as StyleSheet>::Style>, diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index ae0305dc..9391d1dd 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -165,7 +165,7 @@ where      }      /// Draws the [`TextInput`] with the given [`Renderer`], overriding its -    /// [`text_input::Value`] if provided. +    /// [`Value`] if provided.      ///      /// [`Renderer`]: text::Renderer      pub fn draw( @@ -188,7 +188,7 @@ where              self.size,              &self.font,              self.is_secure, -            self.style, +            &self.style,          )      }  } @@ -233,6 +233,7 @@ where          let state = tree.state.downcast_mut::<State>();          operation.focusable(state, self.id.as_ref().map(|id| &id.0)); +        operation.text_input(state, self.id.as_ref().map(|id| &id.0));      }      fn on_event( @@ -284,7 +285,7 @@ where              self.size,              &self.font,              self.is_secure, -            self.style, +            &self.style,          )      } @@ -332,11 +333,43 @@ impl Id {      }  } +impl From<Id> for widget::Id { +    fn from(id: Id) -> Self { +        id.0 +    } +} +  /// Produces a [`Command`] that focuses the [`TextInput`] with the given [`Id`].  pub fn focus<Message: 'static>(id: Id) -> Command<Message> {      Command::widget(operation::focusable::focus(id.0))  } +/// Produces a [`Command`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the +/// end. +pub fn move_cursor_to_end<Message: 'static>(id: Id) -> Command<Message> { +    Command::widget(operation::text_input::move_cursor_to_end(id.0)) +} + +/// Produces a [`Command`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the +/// front. +pub fn move_cursor_to_front<Message: 'static>(id: Id) -> Command<Message> { +    Command::widget(operation::text_input::move_cursor_to_front(id.0)) +} + +/// Produces a [`Command`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the +/// provided position. +pub fn move_cursor_to<Message: 'static>( +    id: Id, +    position: usize, +) -> Command<Message> { +    Command::widget(operation::text_input::move_cursor_to(id.0, position)) +} + +/// Produces a [`Command`] that selects all the content of the [`TextInput`] with the given [`Id`]. +pub fn select_all<Message: 'static>(id: Id) -> Command<Message> { +    Command::widget(operation::text_input::select_all(id.0)) +} +  /// Computes the layout of a [`TextInput`].  pub fn layout<Renderer>(      renderer: &Renderer, @@ -350,6 +383,8 @@ where  {      let text_size = size.unwrap_or_else(|| renderer.default_size()); +    let padding = padding.fit(Size::ZERO, limits.max()); +      let limits = limits          .pad(padding)          .width(width) @@ -742,7 +777,7 @@ pub fn draw<Renderer>(      size: Option<u16>,      font: &Renderer::Font,      is_secure: bool, -    style: <Renderer::Theme as StyleSheet>::Style, +    style: &<Renderer::Theme as StyleSheet>::Style,  ) where      Renderer: text::Renderer,      Renderer::Theme: StyleSheet, @@ -997,6 +1032,24 @@ impl operation::Focusable for State {      }  } +impl operation::TextInput for State { +    fn move_cursor_to_front(&mut self) { +        State::move_cursor_to_front(self) +    } + +    fn move_cursor_to_end(&mut self) { +        State::move_cursor_to_end(self) +    } + +    fn move_cursor_to(&mut self, position: usize) { +        State::move_cursor_to(self, position) +    } + +    fn select_all(&mut self) { +        State::select_all(self) +    } +} +  mod platform {      use crate::keyboard; diff --git a/native/src/widget/toggler.rs b/native/src/widget/toggler.rs index c5c2d82a..37cafd92 100644 --- a/native/src/widget/toggler.rs +++ b/native/src/widget/toggler.rs @@ -260,9 +260,9 @@ where          let is_mouse_over = bounds.contains(cursor_position);          let style = if is_mouse_over { -            theme.hovered(self.style, self.is_active) +            theme.hovered(&self.style, self.is_active)          } else { -            theme.active(self.style, self.is_active) +            theme.active(&self.style, self.is_active)          };          let border_radius = bounds.height as f32 / BORDER_RADIUS_RATIO; diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs index 674f2ba6..084dc269 100644 --- a/native/src/widget/tooltip.rs +++ b/native/src/widget/tooltip.rs @@ -201,7 +201,7 @@ where              self.gap,              self.padding,              self.snap_within_viewport, -            self.style, +            &self.style,              |renderer, limits| {                  Widget::<(), Renderer>::layout(tooltip, renderer, limits)              }, @@ -221,12 +221,12 @@ where      }      fn overlay<'b>( -        &'b self, +        &'b mut self,          tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer,      ) -> Option<overlay::Element<'b, Message, Renderer>> { -        self.content.as_widget().overlay( +        self.content.as_widget_mut().overlay(              &mut tree.children[0],              layout,              renderer, @@ -275,7 +275,7 @@ pub fn draw<Renderer>(      gap: u16,      padding: u16,      snap_within_viewport: bool, -    style: <Renderer::Theme as container::StyleSheet>::Style, +    style: &<Renderer::Theme as container::StyleSheet>::Style,      layout_text: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,      draw_text: impl FnOnce(          &mut Renderer, diff --git a/native/src/widget/tree.rs b/native/src/widget/tree.rs index a8b1a185..0af40c33 100644 --- a/native/src/widget/tree.rs +++ b/native/src/widget/tree.rs @@ -30,7 +30,7 @@ impl Tree {          }      } -    /// Creates a new [`Tree`] for the provided [`Element`]. +    /// Creates a new [`Tree`] for the provided [`Widget`].      pub fn new<'a, Message, Renderer>(          widget: impl Borrow<dyn Widget<Message, Renderer> + 'a>,      ) -> Self @@ -46,10 +46,10 @@ impl Tree {          }      } -    /// Reconciliates the current tree with the provided [`Element`]. +    /// Reconciliates the current tree with the provided [`Widget`].      /// -    /// If the tag of the [`Element`] matches the tag of the [`Tree`], then the -    /// [`Element`] proceeds with the reconciliation (i.e. [`Widget::diff`] is called). +    /// If the tag of the [`Widget`] matches the tag of the [`Tree`], then the +    /// [`Widget`] proceeds with the reconciliation (i.e. [`Widget::diff`] is called).      ///      /// Otherwise, the whole [`Tree`] is recreated.      /// @@ -67,7 +67,7 @@ impl Tree {          }      } -    /// Reconciliates the children of the tree with the provided list of [`Element`]. +    /// Reconciliates the children of the tree with the provided list of widgets.      pub fn diff_children<'a, Message, Renderer>(          &mut self,          new_children: &[impl Borrow<dyn Widget<Message, Renderer> + 'a>], @@ -81,7 +81,7 @@ impl Tree {          )      } -    /// Reconciliates the children of the tree with the provided list of [`Element`] using custom +    /// Reconciliates the children of the tree with the provided list of widgets using custom      /// logic both for diffing and creating new widget state.      pub fn diff_children_custom<T>(          &mut self,  | 
