summaryrefslogtreecommitdiffstats
path: root/native/src
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2022-12-02 18:53:21 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2022-12-02 18:53:21 +0100
commit4029a1cdaaac1abbdcc141b20469a49670cd99b6 (patch)
tree71fa9d9c4aa1f02ce05771db43a4bb7bc6570e77 /native/src
parent676d8efe03ebdbeeb95aef96b8097395b788b1ab (diff)
parent8b55e9b9e6ba0b83038dd491dd34d95b4f9a381b (diff)
downloadiced-4029a1cdaaac1abbdcc141b20469a49670cd99b6.tar.gz
iced-4029a1cdaaac1abbdcc141b20469a49670cd99b6.tar.bz2
iced-4029a1cdaaac1abbdcc141b20469a49670cd99b6.zip
Merge branch 'master' into non-uniform-border-radius-for-quads
Diffstat (limited to 'native/src')
-rw-r--r--native/src/element.rs20
-rw-r--r--native/src/image.rs31
-rw-r--r--native/src/lib.rs4
-rw-r--r--native/src/overlay.rs34
-rw-r--r--native/src/overlay/element.rs55
-rw-r--r--native/src/overlay/menu.rs20
-rw-r--r--native/src/subscription.rs2
-rw-r--r--native/src/svg.rs9
-rw-r--r--native/src/user_interface.rs43
-rw-r--r--native/src/widget.rs12
-rw-r--r--native/src/widget/action.rs67
-rw-r--r--native/src/widget/button.rs17
-rw-r--r--native/src/widget/checkbox.rs4
-rw-r--r--native/src/widget/column.rs4
-rw-r--r--native/src/widget/container.rs16
-rw-r--r--native/src/widget/helpers.rs11
-rw-r--r--native/src/widget/image.rs4
-rw-r--r--native/src/widget/image/viewer.rs4
-rw-r--r--native/src/widget/operation.rs48
-rw-r--r--native/src/widget/operation/focusable.rs34
-rw-r--r--native/src/widget/operation/text_input.rs131
-rw-r--r--native/src/widget/pane_grid.rs221
-rw-r--r--native/src/widget/pane_grid/content.rs41
-rw-r--r--native/src/widget/pane_grid/state.rs68
-rw-r--r--native/src/widget/pane_grid/title_bar.rs52
-rw-r--r--native/src/widget/pick_list.rs38
-rw-r--r--native/src/widget/progress_bar.rs2
-rw-r--r--native/src/widget/radio.rs4
-rw-r--r--native/src/widget/row.rs4
-rw-r--r--native/src/widget/rule.rs2
-rw-r--r--native/src/widget/scrollable.rs14
-rw-r--r--native/src/widget/slider.rs4
-rw-r--r--native/src/widget/svg.rs4
-rw-r--r--native/src/widget/text.rs2
-rw-r--r--native/src/widget/text_input.rs61
-rw-r--r--native/src/widget/toggler.rs4
-rw-r--r--native/src/widget/tooltip.rs8
-rw-r--r--native/src/widget/tree.rs12
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,