Introduce new iced_selector subcrate and refactor Operation

This commit is contained in:
Héctor Ramón Jiménez 2025-08-23 01:44:17 +02:00
parent 8ca25d627f
commit 63142d34fc
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
29 changed files with 839 additions and 521 deletions

View file

@ -18,25 +18,16 @@ use std::sync::Arc;
/// A piece of logic that can traverse the widget tree of an application in
/// order to query or update some widget state.
pub trait Operation<T = ()>: Send {
/// Operates on a widget that contains other widgets.
/// Requests further traversal of the widget tree to keep operating.
///
/// The `operate_on_children` function can be called to return control to
/// the widget tree and keep traversing it.
fn container(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
);
/// The provided `operate` closure may be called by an [`Operation`]
/// to return control to the widget tree and keep traversing it. If
/// the closure is not called, the children of the widget asking for
/// traversal will be skipped.
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>));
/// Operates on a widget that can be focused.
fn focusable(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
_state: &mut dyn Focusable,
) {
}
/// Operates on a widget that contains other widgets.
fn container(&mut self, _id: Option<&Id>, _bounds: Rectangle) {}
/// Operates on a widget that can be scrolled.
fn scrollable(
@ -49,6 +40,15 @@ pub trait Operation<T = ()>: Send {
) {
}
/// Operates on a widget that can be focused.
fn focusable(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
_state: &mut dyn Focusable,
) {
}
/// Operates on a widget that has text input.
fn text_input(
&mut self,
@ -80,13 +80,12 @@ impl<T, O> Operation<O> for Box<T>
where
T: Operation<O> + ?Sized,
{
fn container(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<O>),
) {
self.as_mut().container(id, bounds, operate_on_children);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>)) {
self.as_mut().traverse(operate);
}
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.as_mut().container(id, bounds);
}
fn focusable(
@ -179,17 +178,19 @@ where
}
impl<T, O> Operation<O> for BlackBox<'_, T> {
fn container(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<O>),
) {
self.operation.container(id, bounds, &mut |operation| {
operate_on_children(&mut BlackBox { operation });
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>))
where
Self: Sized,
{
self.operation.traverse(&mut |operation| {
operate(&mut BlackBox { operation });
});
}
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.container(id, bounds);
}
fn focusable(
&mut self,
id: Option<&Id>,
@ -267,28 +268,25 @@ where
A: 'static,
B: 'static,
{
fn container(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
) {
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
struct MapRef<'a, A> {
operation: &'a mut dyn Operation<A>,
}
impl<A, B> Operation<B> for MapRef<'_, A> {
fn container(
fn traverse(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
operate: &mut dyn FnMut(&mut dyn Operation<B>),
) {
self.operation.traverse(&mut |operation| {
operate(&mut MapRef { operation });
});
}
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
let Self { operation, .. } = self;
operation.container(id, bounds, &mut |operation| {
operate_on_children(&mut MapRef { operation });
});
operation.container(id, bounds);
}
fn scrollable(
@ -345,9 +343,13 @@ where
}
}
let Self { operation, .. } = self;
self.operation.traverse(&mut |operation| {
operate(&mut MapRef { operation });
});
}
MapRef { operation }.container(id, bounds, operate_on_children);
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.container(id, bounds);
}
fn focusable(
@ -444,17 +446,16 @@ where
A: 'static,
B: Send + 'static,
{
fn container(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
) {
self.operation.container(id, bounds, &mut |operation| {
operate_on_children(&mut black_box(operation));
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
self.operation.traverse(&mut |operation| {
operate(&mut black_box(operation));
});
}
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.container(id, bounds);
}
fn focusable(
&mut self,
id: Option<&Id>,
@ -531,21 +532,26 @@ pub fn scope<T: 'static>(
) -> impl Operation<T> {
struct ScopedOperation<Message> {
target: Id,
current: Option<Id>,
operation: Box<dyn Operation<Message>>,
}
impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {
fn container(
fn traverse(
&mut self,
id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<Message>),
operate: &mut dyn FnMut(&mut dyn Operation<Message>),
) {
if id == Some(&self.target) {
operate_on_children(self.operation.as_mut());
if self.current.as_ref() == Some(&self.target) {
self.operation.as_mut().traverse(operate);
} else {
operate_on_children(self);
operate(self);
}
self.current = None;
}
fn container(&mut self, id: Option<&Id>, _bounds: Rectangle) {
self.current = id.cloned();
}
fn finish(&self) -> Outcome<Message> {
@ -553,6 +559,7 @@ pub fn scope<T: 'static>(
Outcome::Chain(next) => {
Outcome::Chain(Box::new(ScopedOperation {
target: self.target.clone(),
current: None,
operation: next,
}))
}
@ -563,6 +570,7 @@ pub fn scope<T: 'static>(
ScopedOperation {
target,
current: None,
operation: Box::new(operation),
}
}

View file

@ -48,13 +48,8 @@ pub fn focus<T>(target: Id) -> impl Operation<T> {
}
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}
@ -75,13 +70,8 @@ pub fn unfocus<T>() -> impl Operation<T> {
state.unfocus();
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}
@ -109,13 +99,11 @@ pub fn count() -> impl Operation<Count> {
self.count.total += 1;
}
fn container(
fn traverse(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<Count>),
operate: &mut dyn FnMut(&mut dyn Operation<Count>),
) {
operate_on_children(self);
operate(self);
}
fn finish(&self) -> Outcome<Count> {
@ -163,13 +151,8 @@ where
self.current += 1;
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}
@ -205,13 +188,8 @@ where
self.current += 1;
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}
@ -237,13 +215,11 @@ pub fn find_focused() -> impl Operation<Id> {
}
}
fn container(
fn traverse(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<Id>),
operate: &mut dyn FnMut(&mut dyn Operation<Id>),
) {
operate_on_children(self);
operate(self);
}
fn finish(&self) -> Outcome<Id> {
@ -279,17 +255,15 @@ pub fn is_focused(target: Id) -> impl Operation<bool> {
}
}
fn container(
fn traverse(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<bool>),
operate: &mut dyn FnMut(&mut dyn Operation<bool>),
) {
if self.is_focused.is_some() {
return;
}
operate_on_children(self);
operate(self);
}
fn finish(&self) -> Outcome<bool> {

View file

@ -28,13 +28,8 @@ pub fn snap_to<T>(target: Id, offset: RelativeOffset) -> impl Operation<T> {
}
impl<T> Operation<T> for SnapTo {
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
fn scrollable(
@ -63,13 +58,8 @@ pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
}
impl<T> Operation<T> for ScrollTo {
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
fn scrollable(
@ -98,13 +88,8 @@ pub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
}
impl<T> Operation<T> for ScrollBy {
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
fn scrollable(

View file

@ -45,13 +45,8 @@ pub fn move_cursor_to_front<T>(target: Id) -> impl Operation<T> {
}
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}
@ -80,13 +75,8 @@ pub fn move_cursor_to_end<T>(target: Id) -> impl Operation<T> {
}
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}
@ -116,13 +106,8 @@ pub fn move_cursor_to<T>(target: Id, position: usize) -> impl Operation<T> {
}
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}
@ -150,13 +135,8 @@ pub fn select_all<T>(target: Id) -> impl Operation<T> {
}
}
fn container(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
operate(self);
}
}