pub mod auto_focusable;
pub mod focusable;
pub mod scrollable;
pub mod selection;
pub mod text_input;
pub use focusable::{FocusGroup, Focusable};
pub use scrollable::Scrollable;
pub use selection::Selectable;
pub use text_input::TextInput;
use crate::widget::Id;
use crate::{Rectangle, Vector};
use std::any::Any;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PaintedOffset(pub Vector);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Hidden;
use std::marker::PhantomData;
use std::sync::Arc;
pub trait Operation<T = ()>: Send {
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>));
fn container(&mut self, _id: Option<&Id>, _bounds: Rectangle) {}
fn scrollable(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
_content_bounds: Rectangle,
_translation: Vector,
_state: &mut dyn Scrollable,
) {
}
fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Focusable) {}
fn auto_focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle) {}
fn focus_order_hint(&mut self, _order: u32) {}
fn enter_focus_group(&mut self, _group: FocusGroup) {}
fn exit_focus_group(&mut self) {}
fn action_hintable(&mut self, _id: Option<&Id>, _bounds: Rectangle, _hints: &dyn Any) {}
fn text_input(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn TextInput) {}
fn text(&mut self, _id: Option<&Id>, _bounds: Rectangle, _text: &str) {}
fn selectable_text(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
_state: &mut dyn Selectable,
) {
}
fn custom(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Any) {}
fn finish(&self) -> Outcome<T> {
Outcome::None
}
}
impl<T, O> Operation<O> for Box<T>
where
T: Operation<O> + ?Sized,
{
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(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
self.as_mut().focusable(id, bounds, state);
}
fn auto_focusable(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.as_mut().auto_focusable(id, bounds);
}
fn focus_order_hint(&mut self, order: u32) {
self.as_mut().focus_order_hint(order);
}
fn enter_focus_group(&mut self, group: FocusGroup) {
self.as_mut().enter_focus_group(group);
}
fn exit_focus_group(&mut self) {
self.as_mut().exit_focus_group();
}
fn action_hintable(&mut self, id: Option<&Id>, bounds: Rectangle, hints: &dyn Any) {
self.as_mut().action_hintable(id, bounds, hints);
}
fn scrollable(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
content_bounds: Rectangle,
translation: Vector,
state: &mut dyn Scrollable,
) {
self.as_mut()
.scrollable(id, bounds, content_bounds, translation, state);
}
fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
self.as_mut().text_input(id, bounds, state);
}
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
self.as_mut().text(id, bounds, text);
}
fn selectable_text(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Selectable) {
self.as_mut().selectable_text(id, bounds, state);
}
fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
self.as_mut().custom(id, bounds, state);
}
fn finish(&self) -> Outcome<O> {
self.as_ref().finish()
}
}
pub enum Outcome<T> {
None,
Some(T),
Chain(Box<dyn Operation<T>>),
}
impl<T> fmt::Debug for Outcome<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::None => write!(f, "Outcome::None"),
Self::Some(output) => write!(f, "Outcome::Some({output:?})"),
Self::Chain(_) => write!(f, "Outcome::Chain(...)"),
}
}
}
pub fn black_box<'a, T, O>(operation: &'a mut dyn Operation<T>) -> impl Operation<O> + 'a
where
T: 'a,
{
struct BlackBox<'a, T> {
operation: &'a mut dyn Operation<T>,
}
impl<T, O> Operation<O> for BlackBox<'_, T> {
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>, bounds: Rectangle, state: &mut dyn Focusable) {
self.operation.focusable(id, bounds, state);
}
fn auto_focusable(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.auto_focusable(id, bounds);
}
fn focus_order_hint(&mut self, order: u32) {
self.operation.focus_order_hint(order);
}
fn enter_focus_group(&mut self, group: FocusGroup) {
self.operation.enter_focus_group(group);
}
fn exit_focus_group(&mut self) {
self.operation.exit_focus_group();
}
fn action_hintable(&mut self, id: Option<&Id>, bounds: Rectangle, hints: &dyn Any) {
self.operation.action_hintable(id, bounds, hints);
}
fn scrollable(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
content_bounds: Rectangle,
translation: Vector,
state: &mut dyn Scrollable,
) {
self.operation
.scrollable(id, bounds, content_bounds, translation, state);
}
fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
self.operation.text_input(id, bounds, state);
}
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
self.operation.text(id, bounds, text);
}
fn selectable_text(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
state: &mut dyn Selectable,
) {
self.operation.selectable_text(id, bounds, state);
}
fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
self.operation.custom(id, bounds, state);
}
fn finish(&self) -> Outcome<O> {
Outcome::None
}
}
BlackBox { operation }
}
pub fn map<A, B>(
operation: impl Operation<A>,
f: impl Fn(A) -> B + Send + Sync + 'static,
) -> impl Operation<B>
where
A: 'static,
B: 'static,
{
struct Map<O, A, B> {
operation: O,
f: Arc<dyn Fn(A) -> B + Send + Sync>,
}
impl<O, A, B> Operation<B> for Map<O, A, B>
where
O: Operation<A>,
A: 'static,
B: 'static,
{
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 traverse(&mut self, 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);
}
fn scrollable(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
content_bounds: Rectangle,
translation: Vector,
state: &mut dyn Scrollable,
) {
self.operation
.scrollable(id, bounds, content_bounds, translation, state);
}
fn focusable(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
state: &mut dyn Focusable,
) {
self.operation.focusable(id, bounds, state);
}
fn auto_focusable(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.auto_focusable(id, bounds);
}
fn focus_order_hint(&mut self, order: u32) {
self.operation.focus_order_hint(order);
}
fn enter_focus_group(&mut self, group: FocusGroup) {
self.operation.enter_focus_group(group);
}
fn exit_focus_group(&mut self) {
self.operation.exit_focus_group();
}
fn action_hintable(&mut self, id: Option<&Id>, bounds: Rectangle, hints: &dyn Any) {
self.operation.action_hintable(id, bounds, hints);
}
fn text_input(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
state: &mut dyn TextInput,
) {
self.operation.text_input(id, bounds, state);
}
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
self.operation.text(id, bounds, text);
}
fn selectable_text(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
state: &mut dyn Selectable,
) {
self.operation.selectable_text(id, bounds, state);
}
fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
self.operation.custom(id, bounds, state);
}
}
self.operation.traverse(&mut |operation| {
operate(&mut MapRef { operation });
});
}
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.container(id, bounds);
}
fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
self.operation.focusable(id, bounds, state);
}
fn auto_focusable(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.auto_focusable(id, bounds);
}
fn focus_order_hint(&mut self, order: u32) {
self.operation.focus_order_hint(order);
}
fn enter_focus_group(&mut self, group: FocusGroup) {
self.operation.enter_focus_group(group);
}
fn exit_focus_group(&mut self) {
self.operation.exit_focus_group();
}
fn action_hintable(&mut self, id: Option<&Id>, bounds: Rectangle, hints: &dyn Any) {
self.operation.action_hintable(id, bounds, hints);
}
fn scrollable(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
content_bounds: Rectangle,
translation: Vector,
state: &mut dyn Scrollable,
) {
self.operation
.scrollable(id, bounds, content_bounds, translation, state);
}
fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
self.operation.text_input(id, bounds, state);
}
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
self.operation.text(id, bounds, text);
}
fn selectable_text(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
state: &mut dyn Selectable,
) {
self.operation.selectable_text(id, bounds, state);
}
fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
self.operation.custom(id, bounds, state);
}
fn finish(&self) -> Outcome<B> {
match self.operation.finish() {
Outcome::None => Outcome::None,
Outcome::Some(output) => Outcome::Some((self.f)(output)),
Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
operation: next,
f: self.f.clone(),
})),
}
}
}
Map {
operation,
f: Arc::new(f),
}
}
pub fn then<A, B, O>(operation: impl Operation<A> + 'static, f: fn(A) -> O) -> impl Operation<B>
where
A: 'static,
B: Send + 'static,
O: Operation<B> + 'static,
{
struct Chain<T, O, A, B>
where
T: Operation<A>,
O: Operation<B>,
{
operation: T,
next: fn(A) -> O,
_result: PhantomData<B>,
}
impl<T, O, A, B> Operation<B> for Chain<T, O, A, B>
where
T: Operation<A> + 'static,
O: Operation<B> + 'static,
A: 'static,
B: Send + 'static,
{
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>, bounds: Rectangle, state: &mut dyn Focusable) {
self.operation.focusable(id, bounds, state);
}
fn auto_focusable(&mut self, id: Option<&Id>, bounds: Rectangle) {
self.operation.auto_focusable(id, bounds);
}
fn focus_order_hint(&mut self, order: u32) {
self.operation.focus_order_hint(order);
}
fn enter_focus_group(&mut self, group: FocusGroup) {
self.operation.enter_focus_group(group);
}
fn exit_focus_group(&mut self) {
self.operation.exit_focus_group();
}
fn action_hintable(&mut self, id: Option<&Id>, bounds: Rectangle, hints: &dyn Any) {
self.operation.action_hintable(id, bounds, hints);
}
fn scrollable(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
content_bounds: Rectangle,
translation: crate::Vector,
state: &mut dyn Scrollable,
) {
self.operation
.scrollable(id, bounds, content_bounds, translation, state);
}
fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
self.operation.text_input(id, bounds, state);
}
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
self.operation.text(id, bounds, text);
}
fn selectable_text(
&mut self,
id: Option<&Id>,
bounds: Rectangle,
state: &mut dyn Selectable,
) {
self.operation.selectable_text(id, bounds, state);
}
fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
self.operation.custom(id, bounds, state);
}
fn finish(&self) -> Outcome<B> {
match self.operation.finish() {
Outcome::None => Outcome::None,
Outcome::Some(value) => Outcome::Chain(Box::new((self.next)(value))),
Outcome::Chain(operation) => Outcome::Chain(Box::new(then(operation, self.next))),
}
}
}
Chain {
operation,
next: f,
_result: PhantomData,
}
}
pub fn scope<T: 'static>(target: Id, operation: impl Operation<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 traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Message>)) {
if self.current.as_ref() == Some(&self.target) {
self.operation.as_mut().traverse(operate);
} else {
operate(self);
}
self.current = None;
}
fn container(&mut self, id: Option<&Id>, _bounds: Rectangle) {
self.current = id.cloned();
}
fn finish(&self) -> Outcome<Message> {
match self.operation.finish() {
Outcome::Chain(next) => Outcome::Chain(Box::new(ScopedOperation {
target: self.target.clone(),
current: None,
operation: next,
})),
outcome => outcome,
}
}
}
ScopedOperation {
target,
current: None,
operation: Box::new(operation),
}
}