use std::{
any::{Any, TypeId},
fmt,
};
mod adopt;
pub use adopt::*;
mod arc;
pub use arc::*;
mod extend;
pub use extend::*;
mod match_node;
pub use match_node::*;
mod when;
pub use when::*;
mod list;
pub use list::*;
use zng_app_proc_macros::{ui_node, widget};
use zng_layout::unit::PxSize;
use zng_var::{ContextInitHandle, ResponseVar, Var};
use crate::{
render::{FrameBuilder, FrameUpdate},
update::{EventUpdate, WidgetUpdates},
};
use super::{
base::{Parallel, PARALLEL_VAR},
info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
WidgetId, WidgetUpdateMode, WIDGET,
};
pub trait UiNode: Any + Send {
fn init(&mut self);
fn deinit(&mut self);
fn info(&mut self, info: &mut WidgetInfoBuilder);
fn event(&mut self, update: &EventUpdate);
fn update(&mut self, updates: &WidgetUpdates);
#[must_use]
fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize;
#[must_use]
fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize;
fn render(&mut self, frame: &mut FrameBuilder);
fn render_update(&mut self, update: &mut FrameUpdate);
fn boxed(self) -> BoxedUiNode
where
Self: Sized,
{
debug_assert_ne!(self.type_id(), TypeId::of::<BoxedUiNode>());
Box::new(self)
}
#[cfg(feature = "dyn_node")]
fn cfg_boxed(self) -> BoxedUiNode
where
Self: Sized,
{
self.boxed()
}
#[cfg(not(feature = "dyn_node"))]
fn cfg_boxed(self) -> Self
where
Self: Sized,
{
self
}
fn is_widget(&self) -> bool {
false
}
fn is_nil(&self) -> bool {
false
}
fn with_context<R, F>(&mut self, update_mode: WidgetUpdateMode, f: F) -> Option<R>
where
F: FnOnce() -> R,
{
let _ = (update_mode, f);
None
}
fn into_widget(self) -> BoxedUiNode
where
Self: Sized,
{
if self.is_widget() {
return self.boxed();
}
into_widget! {
child = self;
}
.boxed()
}
fn init_widget(mut self) -> (BoxedUiNode, ResponseVar<WidgetId>)
where
Self: Sized,
{
if let Some(id) = self.with_context(WidgetUpdateMode::Ignore, || WIDGET.id()) {
return (self.boxed(), crate::var::response_done_var(id));
}
let (responder, response) = crate::var::response_var();
let widget = match_widget(self.boxed(), move |c, op| {
if let UiNodeOp::Init = op {
c.init();
let widget_id = if let Some(id) = c.with_context(WidgetUpdateMode::Ignore, || WIDGET.id()) {
id
} else {
c.deinit();
let not_widget = std::mem::replace(c.child(), NilUiNode.boxed());
*c.child() = not_widget.into_widget();
c.init();
c.with_context(WidgetUpdateMode::Ignore, || WIDGET.id()).unwrap()
};
responder.respond(widget_id);
}
});
(widget.boxed(), response)
}
fn downcast_unbox<T: UiNode>(self) -> Result<T, BoxedUiNode>
where
Self: Sized,
{
let boxed = self.boxed();
if boxed.actual_type_id() == TypeId::of::<T>() {
Ok(*boxed.into_any_boxed().downcast().unwrap())
} else if TypeId::of::<T>() == TypeId::of::<BoxedUiNode>() {
Ok(*(Box::new(boxed) as Box<dyn Any>).downcast().unwrap())
} else {
Err(boxed)
}
}
fn actual_type_id(&self) -> TypeId {
self.type_id()
}
fn as_any(&self) -> &dyn Any
where
Self: Sized,
{
self
}
fn as_any_mut(&mut self) -> &mut dyn Any
where
Self: Sized,
{
self
}
fn trace<E, S>(self, mut enter_mtd: E) -> BoxedUiNode
where
Self: Sized,
E: FnMut(UiNodeOpMethod) -> S + Send + 'static,
{
match_node(self, move |node, op| {
let _span = enter_mtd(op.mtd());
node.op(op);
})
.boxed()
}
fn op(&mut self, op: UiNodeOp) {
match op {
UiNodeOp::Init => self.init(),
UiNodeOp::Deinit => self.deinit(),
UiNodeOp::Info { info } => self.info(info),
UiNodeOp::Event { update } => self.event(update),
UiNodeOp::Update { updates } => self.update(updates),
UiNodeOp::Measure { wm, desired_size } => *desired_size = self.measure(wm),
UiNodeOp::Layout { wl, final_size } => *final_size = self.layout(wl),
UiNodeOp::Render { frame } => self.render(frame),
UiNodeOp::RenderUpdate { update } => self.render_update(update),
}
}
}
#[allow(non_camel_case_types)]
#[widget($crate::widget::node::into_widget)]
struct into_widget(crate::widget::base::WidgetBase);
#[zng_app_proc_macros::property(CHILD, capture, widget_impl(into_widget))]
fn child(child: impl UiNode) {}
impl into_widget {
fn widget_intrinsic(&mut self) {
self.widget_builder().push_build_action(|b| {
let child = b.capture_ui_node(crate::property_id!(Self::child)).unwrap();
b.set_child(child);
});
}
}
pub trait UiNodeList: UiNodeListBoxed {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R;
fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode);
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync;
fn par_fold_reduce<T, I, F, R>(&mut self, identity: I, fold: F, reduce: R) -> T
where
T: Send + 'static,
I: Fn() -> T + Send + Sync,
F: Fn(T, usize, &mut BoxedUiNode) -> T + Send + Sync,
R: Fn(T, T) -> T + Send + Sync;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn boxed(self) -> BoxedUiNodeList;
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>);
fn init_all(&mut self) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::INIT) {
self.par_each(|_, c| {
c.init();
});
} else {
self.for_each(|_, c| {
c.init();
})
}
}
fn deinit_all(&mut self) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::DEINIT) {
self.par_each(|_, c| {
c.deinit();
});
} else {
self.for_each(|_, c| {
c.deinit();
});
}
}
fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::INFO) {
let p_info = self.par_fold_reduce(
|| info.parallel_split(),
|mut info, _, node| {
node.info(&mut info);
info
},
|mut a, b| {
a.parallel_fold(b);
a
},
);
info.parallel_fold(p_info);
} else {
self.for_each(|_, c| {
c.info(info);
});
}
}
fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
let _ = observer;
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::UPDATE) {
self.par_each(|_, c| {
c.update(updates);
});
} else {
self.for_each(|_, c| {
c.update(updates);
});
}
}
fn event_all(&mut self, update: &EventUpdate) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::EVENT) {
self.par_each(|_, c| {
c.event(update);
});
} else {
self.for_each(|_, c| {
c.event(update);
});
}
}
#[must_use]
fn measure_each<F, S>(&mut self, wm: &mut WidgetMeasure, measure: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetMeasure) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
Self: Sized,
{
default_measure_each(self, wm, measure, fold_size)
}
#[must_use]
fn layout_each<F, S>(&mut self, wl: &mut WidgetLayout, layout: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetLayout) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
Self: Sized,
{
default_layout_each(self, wl, layout, fold_size)
}
fn render_all(&mut self, frame: &mut FrameBuilder) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::RENDER) {
let p_frame = self.par_fold_reduce(
|| frame.parallel_split(),
|mut frame, _, node| {
node.render(&mut frame);
frame
},
|mut a, b| {
a.parallel_fold(b);
a
},
);
frame.parallel_fold(p_frame);
} else {
self.for_each(|_, c| {
c.render(frame);
})
}
}
fn render_update_all(&mut self, update: &mut FrameUpdate) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::RENDER) {
let p_update = self.par_fold_reduce(
|| update.parallel_split(),
|mut update, _, node| {
node.render_update(&mut update);
update
},
|mut a, b| {
a.parallel_fold(b);
a
},
);
update.parallel_fold(p_update);
} else {
self.for_each(|_, c| {
c.render_update(update);
})
}
}
fn downcast_unbox<L: UiNodeList>(self) -> Result<L, BoxedUiNodeList>
where
Self: Sized,
{
let boxed = self.boxed();
if boxed.actual_type_id() == TypeId::of::<L>() {
Ok(*boxed.into_any_boxed().downcast().unwrap())
} else if TypeId::of::<L>() == TypeId::of::<BoxedUiNodeList>() {
Ok(*(Box::new(boxed) as Box<dyn Any>).downcast().unwrap())
} else {
Err(boxed)
}
}
fn actual_type_id(&self) -> TypeId {
self.type_id()
}
fn as_any(&mut self) -> &mut dyn Any
where
Self: Sized,
{
self
}
fn op(&mut self, op: UiNodeOp)
where
Self: Sized,
{
match op {
UiNodeOp::Init => ui_node_list_default::init_all(self),
UiNodeOp::Deinit => ui_node_list_default::deinit_all(self),
UiNodeOp::Info { info } => ui_node_list_default::info_all(self, info),
UiNodeOp::Event { update } => ui_node_list_default::event_all(self, update),
UiNodeOp::Update { updates } => ui_node_list_default::update_all(self, updates),
UiNodeOp::Measure { wm, desired_size } => *desired_size = ui_node_list_default::measure_all(self, wm),
UiNodeOp::Layout { wl, final_size } => *final_size = ui_node_list_default::layout_all(self, wl),
UiNodeOp::Render { frame } => ui_node_list_default::render_all(self, frame),
UiNodeOp::RenderUpdate { update } => ui_node_list_default::render_update_all(self, update),
}
}
}
fn default_measure_each<F, S>(self_: &mut impl UiNodeList, wm: &mut WidgetMeasure, measure: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetMeasure) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
#[cfg(feature = "dyn_closure")]
let measure: Box<dyn Fn(usize, &mut BoxedUiNode, &mut WidgetMeasure) -> PxSize + Send + Sync> = Box::new(measure);
#[cfg(feature = "dyn_closure")]
let fold_size: Box<dyn Fn(PxSize, PxSize) -> PxSize + Send + Sync> = Box::new(fold_size);
default_measure_each_impl(self_, wm, measure, fold_size)
}
fn default_measure_each_impl<F, S>(self_: &mut impl UiNodeList, wm: &mut WidgetMeasure, measure: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetMeasure) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
if self_.len() > 1 && PARALLEL_VAR.get().contains(Parallel::LAYOUT) {
let (pwm, size) = self_.par_fold_reduce(
|| (wm.parallel_split(), PxSize::zero()),
|(mut a_wm, a_size), i, n| {
let b_size = measure(i, n, &mut a_wm);
(a_wm, fold_size(a_size, b_size))
},
|(mut awm, a_size), (bwm, b_size)| {
(
{
awm.parallel_fold(bwm);
awm
},
fold_size(a_size, b_size),
)
},
);
wm.parallel_fold(pwm);
size
} else {
let mut size = PxSize::zero();
self_.for_each(|i, n| {
let b = measure(i, n, wm);
size = fold_size(size, b);
});
size
}
}
fn default_layout_each<F, S>(self_: &mut impl UiNodeList, wl: &mut WidgetLayout, layout: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetLayout) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
#[cfg(feature = "dyn_closure")]
let layout: Box<dyn Fn(usize, &mut BoxedUiNode, &mut WidgetLayout) -> PxSize + Send + Sync> = Box::new(layout);
#[cfg(feature = "dyn_closure")]
let fold_size: Box<dyn Fn(PxSize, PxSize) -> PxSize + Send + Sync> = Box::new(fold_size);
default_layout_each_impl(self_, wl, layout, fold_size)
}
fn default_layout_each_impl<F, S>(self_: &mut impl UiNodeList, wl: &mut WidgetLayout, layout: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetLayout) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
if self_.len() > 1 && PARALLEL_VAR.get().contains(Parallel::LAYOUT) {
let (pwl, size) = self_.par_fold_reduce(
|| (wl.parallel_split(), PxSize::zero()),
|(mut awl, a_size), i, n| {
let b_size = layout(i, n, &mut awl);
(awl, fold_size(a_size, b_size))
},
|(mut awl, a_size), (bwl, b_size)| {
(
{
awl.parallel_fold(bwl);
awl
},
fold_size(a_size, b_size),
)
},
);
wl.parallel_fold(pwl);
size
} else {
let mut size = PxSize::zero();
self_.for_each(|i, n| {
let b = layout(i, n, wl);
size = fold_size(size, b);
});
size
}
}
#[doc(hidden)]
pub mod ui_node_list_default {
use super::*;
pub fn init_all(list: &mut impl UiNodeList) {
list.init_all();
}
pub fn deinit_all(list: &mut impl UiNodeList) {
list.deinit_all();
}
pub fn info_all(list: &mut impl UiNodeList, info: &mut WidgetInfoBuilder) {
list.info_all(info)
}
pub fn event_all(list: &mut impl UiNodeList, update: &EventUpdate) {
list.event_all(update);
}
pub fn update_all(list: &mut impl UiNodeList, updates: &WidgetUpdates) {
let mut changed = false;
list.update_all(updates, &mut changed);
if changed {
WIDGET.layout().render();
}
}
pub fn measure_all(list: &mut impl UiNodeList, wm: &mut WidgetMeasure) -> PxSize {
list.measure_each(wm, |_, n, wm| n.measure(wm), PxSize::max)
}
pub fn layout_all(list: &mut impl UiNodeList, wl: &mut WidgetLayout) -> PxSize {
list.layout_each(wl, |_, n, wl| n.layout(wl), PxSize::max)
}
pub fn render_all(list: &mut impl UiNodeList, frame: &mut FrameBuilder) {
list.render_all(frame);
}
pub fn render_update_all(list: &mut impl UiNodeList, update: &mut FrameUpdate) {
list.render_update_all(update)
}
}
#[doc(hidden)]
pub trait UiNodeBoxed: Any + Send {
fn info_boxed(&mut self, info: &mut WidgetInfoBuilder);
fn init_boxed(&mut self);
fn deinit_boxed(&mut self);
fn update_boxed(&mut self, updates: &WidgetUpdates);
fn event_boxed(&mut self, update: &EventUpdate);
fn measure_boxed(&mut self, wm: &mut WidgetMeasure) -> PxSize;
fn layout_boxed(&mut self, wl: &mut WidgetLayout) -> PxSize;
fn render_boxed(&mut self, frame: &mut FrameBuilder);
fn render_update_boxed(&mut self, update: &mut FrameUpdate);
fn is_widget_boxed(&self) -> bool;
fn is_nil_boxed(&self) -> bool;
fn with_context_boxed(&mut self, update_mode: WidgetUpdateMode, f: &mut dyn FnMut());
fn into_widget_boxed(self: Box<Self>) -> BoxedUiNode;
fn as_any_boxed(&self) -> &dyn Any;
fn as_any_mut_boxed(&mut self) -> &mut dyn Any;
fn actual_type_id_boxed(&self) -> TypeId;
fn into_any_boxed(self: Box<Self>) -> Box<dyn Any>;
}
impl<U: UiNode> UiNodeBoxed for U {
fn info_boxed(&mut self, info: &mut WidgetInfoBuilder) {
self.info(info);
}
fn init_boxed(&mut self) {
self.init();
}
fn deinit_boxed(&mut self) {
self.deinit();
}
fn update_boxed(&mut self, updates: &WidgetUpdates) {
self.update(updates);
}
fn event_boxed(&mut self, update: &EventUpdate) {
self.event(update);
}
fn measure_boxed(&mut self, wm: &mut WidgetMeasure) -> PxSize {
self.measure(wm)
}
fn layout_boxed(&mut self, wl: &mut WidgetLayout) -> PxSize {
self.layout(wl)
}
fn render_boxed(&mut self, frame: &mut FrameBuilder) {
self.render(frame);
}
fn render_update_boxed(&mut self, update: &mut FrameUpdate) {
self.render_update(update);
}
fn is_widget_boxed(&self) -> bool {
self.is_widget()
}
fn is_nil_boxed(&self) -> bool {
self.is_nil()
}
fn into_widget_boxed(self: Box<Self>) -> BoxedUiNode {
self.into_widget()
}
fn actual_type_id_boxed(&self) -> TypeId {
self.type_id()
}
fn into_any_boxed(self: Box<Self>) -> Box<dyn Any> {
self
}
fn with_context_boxed(&mut self, update_mode: WidgetUpdateMode, f: &mut dyn FnMut()) {
self.with_context(update_mode, f);
}
fn as_any_boxed(&self) -> &dyn Any {
self.as_any()
}
fn as_any_mut_boxed(&mut self) -> &mut dyn Any {
self.as_any_mut()
}
}
#[doc(hidden)]
pub trait UiNodeListBoxed: Any + Send {
fn with_node_boxed(&mut self, index: usize, f: &mut dyn FnMut(&mut BoxedUiNode));
fn for_each_boxed(&mut self, f: &mut dyn FnMut(usize, &mut BoxedUiNode));
fn par_each_boxed(&mut self, f: &(dyn Fn(usize, &mut BoxedUiNode) + Send + Sync));
fn par_fold_reduce_boxed(
&mut self,
identity: &(dyn Fn() -> Box<dyn Any + Send> + Send + Sync),
fold: &(dyn Fn(Box<dyn Any + Send>, usize, &mut BoxedUiNode) -> Box<dyn Any + Send> + Send + Sync),
reduce: &(dyn Fn(Box<dyn Any + Send>, Box<dyn Any + Send>) -> Box<dyn Any + Send> + Send + Sync),
) -> Box<dyn Any + Send>;
fn measure_each_boxed(
&mut self,
wm: &mut WidgetMeasure,
measure: &(dyn Fn(usize, &mut BoxedUiNode, &mut WidgetMeasure) -> PxSize + Send + Sync),
fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Send + Sync),
) -> PxSize;
fn layout_each_boxed(
&mut self,
wl: &mut WidgetLayout,
layout: &(dyn Fn(usize, &mut BoxedUiNode, &mut WidgetLayout) -> PxSize + Send + Sync),
fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Send + Sync),
) -> PxSize;
fn len_boxed(&self) -> usize;
fn drain_into_boxed(&mut self, vec: &mut Vec<BoxedUiNode>);
fn init_all_boxed(&mut self);
fn deinit_all_boxed(&mut self);
fn info_all_boxed(&mut self, info: &mut WidgetInfoBuilder);
fn event_all_boxed(&mut self, update: &EventUpdate);
fn update_all_boxed(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver);
fn render_all_boxed(&mut self, frame: &mut FrameBuilder);
fn render_update_all_boxed(&mut self, update: &mut FrameUpdate);
fn actual_type_id_boxed(&self) -> TypeId;
fn into_any_boxed(self: Box<Self>) -> Box<dyn Any>;
fn as_any_boxed(&mut self) -> &mut dyn Any;
}
impl<L: UiNodeList> UiNodeListBoxed for L {
fn with_node_boxed(&mut self, index: usize, f: &mut dyn FnMut(&mut BoxedUiNode)) {
self.with_node(index, f)
}
fn for_each_boxed(&mut self, f: &mut dyn FnMut(usize, &mut BoxedUiNode)) {
self.for_each(f);
}
fn par_each_boxed(&mut self, f: &(dyn Fn(usize, &mut BoxedUiNode) + Send + Sync)) {
self.par_each(f)
}
fn par_fold_reduce_boxed(
&mut self,
identity: &(dyn Fn() -> Box<dyn Any + Send> + Send + Sync),
fold: &(dyn Fn(Box<dyn Any + Send>, usize, &mut BoxedUiNode) -> Box<dyn Any + Send> + Send + Sync),
reduce: &(dyn Fn(Box<dyn Any + Send>, Box<dyn Any + Send>) -> Box<dyn Any + Send> + Send + Sync),
) -> Box<dyn Any + Send> {
self.par_fold_reduce(identity, fold, reduce)
}
fn measure_each_boxed(
&mut self,
wm: &mut WidgetMeasure,
measure: &(dyn Fn(usize, &mut BoxedUiNode, &mut WidgetMeasure) -> PxSize + Send + Sync),
fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Send + Sync),
) -> PxSize {
self.measure_each(wm, measure, fold_size)
}
fn layout_each_boxed(
&mut self,
wl: &mut WidgetLayout,
layout: &(dyn Fn(usize, &mut BoxedUiNode, &mut WidgetLayout) -> PxSize + Send + Sync),
fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Send + Sync),
) -> PxSize {
self.layout_each(wl, layout, fold_size)
}
fn len_boxed(&self) -> usize {
self.len()
}
fn drain_into_boxed(&mut self, vec: &mut Vec<BoxedUiNode>) {
self.drain_into(vec)
}
fn init_all_boxed(&mut self) {
self.init_all();
}
fn deinit_all_boxed(&mut self) {
self.deinit_all();
}
fn info_all_boxed(&mut self, info: &mut WidgetInfoBuilder) {
self.info_all(info);
}
fn event_all_boxed(&mut self, update: &EventUpdate) {
self.event_all(update);
}
fn update_all_boxed(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
self.update_all(updates, observer);
}
fn render_all_boxed(&mut self, frame: &mut FrameBuilder) {
self.render_all(frame);
}
fn render_update_all_boxed(&mut self, update: &mut FrameUpdate) {
self.render_update_all(update);
}
fn actual_type_id_boxed(&self) -> TypeId {
self.type_id()
}
fn into_any_boxed(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any_boxed(&mut self) -> &mut dyn Any {
self.as_any()
}
}
pub type BoxedUiNode = Box<dyn UiNodeBoxed>;
pub type BoxedUiNodeList = Box<dyn UiNodeListBoxed>;
impl UiNode for BoxedUiNode {
fn info(&mut self, info: &mut WidgetInfoBuilder) {
self.as_mut().info_boxed(info);
}
fn init(&mut self) {
self.as_mut().init_boxed();
}
fn deinit(&mut self) {
self.as_mut().deinit_boxed();
}
fn update(&mut self, updates: &WidgetUpdates) {
self.as_mut().update_boxed(updates);
}
fn event(&mut self, update: &EventUpdate) {
self.as_mut().event_boxed(update);
}
fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
self.as_mut().measure_boxed(wm)
}
fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
self.as_mut().layout_boxed(wl)
}
fn render(&mut self, frame: &mut FrameBuilder) {
self.as_mut().render_boxed(frame);
}
fn render_update(&mut self, update: &mut FrameUpdate) {
self.as_mut().render_update_boxed(update);
}
fn boxed(self) -> BoxedUiNode
where
Self: Sized,
{
self
}
fn actual_type_id(&self) -> TypeId {
self.as_ref().actual_type_id_boxed()
}
fn is_widget(&self) -> bool {
self.as_ref().is_widget_boxed()
}
fn is_nil(&self) -> bool {
self.as_ref().is_nil_boxed()
}
fn with_context<R, F>(&mut self, update_mode: WidgetUpdateMode, f: F) -> Option<R>
where
F: FnOnce() -> R,
{
let mut f = Some(f);
let mut r = None;
self.as_mut()
.with_context_boxed(update_mode, &mut || r = Some((f.take().unwrap())()));
r
}
fn into_widget(self) -> BoxedUiNode
where
Self: Sized,
{
self.into_widget_boxed()
}
fn as_any(&self) -> &dyn Any
where
Self: Sized,
{
self.as_ref().as_any_boxed()
}
fn as_any_mut(&mut self) -> &mut dyn Any
where
Self: Sized,
{
self.as_mut().as_any_mut_boxed()
}
}
impl UiNodeList for BoxedUiNodeList {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
let mut f = Some(f);
let mut r = None;
self.as_mut().with_node_boxed(index, &mut |n| r = Some((f.take().unwrap())(n)));
r.unwrap()
}
fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
self.as_mut().for_each_boxed(&mut f)
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
self.as_mut().par_each_boxed(&f)
}
fn par_fold_reduce<T, I, F, R>(&mut self, identity: I, fold: F, reduce: R) -> T
where
T: Send + 'static,
I: Fn() -> T + Send + Sync,
F: Fn(T, usize, &mut BoxedUiNode) -> T + Send + Sync,
R: Fn(T, T) -> T + Send + Sync,
{
self.as_mut()
.par_fold_reduce_boxed(
&move || Box::new(Some(identity())),
&move |mut r, i, n| {
let r_mut = r.downcast_mut::<Option<T>>().unwrap();
*r_mut = Some(fold(r_mut.take().unwrap(), i, n));
r
},
&|mut a, b| {
let a_mut = a.downcast_mut::<Option<T>>().unwrap();
*a_mut = Some(reduce(a_mut.take().unwrap(), b.downcast::<Option<T>>().unwrap().unwrap()));
a
},
)
.downcast::<Option<T>>()
.unwrap()
.unwrap()
}
fn len(&self) -> usize {
self.as_ref().len_boxed()
}
fn boxed(self) -> BoxedUiNodeList {
self
}
fn actual_type_id(&self) -> TypeId {
self.as_ref().actual_type_id_boxed()
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
self.as_mut().drain_into_boxed(vec)
}
fn init_all(&mut self) {
self.as_mut().init_all_boxed();
}
fn deinit_all(&mut self) {
self.as_mut().deinit_all_boxed();
}
fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
self.as_mut().update_all_boxed(updates, observer);
}
fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
self.as_mut().info_all_boxed(info);
}
fn event_all(&mut self, update: &EventUpdate) {
self.as_mut().event_all_boxed(update);
}
fn render_all(&mut self, frame: &mut FrameBuilder) {
self.as_mut().render_all_boxed(frame);
}
fn render_update_all(&mut self, update: &mut FrameUpdate) {
self.as_mut().render_update_all_boxed(update);
}
fn measure_each<F, S>(&mut self, wm: &mut WidgetMeasure, measure: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetMeasure) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
self.as_mut().measure_each_boxed(wm, &measure, &fold_size)
}
fn layout_each<F, S>(&mut self, wl: &mut WidgetLayout, layout: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut WidgetLayout) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
self.as_mut().layout_each_boxed(wl, &layout, &fold_size)
}
fn as_any(&mut self) -> &mut dyn Any
where
Self: Sized,
{
self.as_mut().as_any_boxed()
}
}
impl<U: UiNode> UiNode for Option<U> {
fn info(&mut self, info: &mut WidgetInfoBuilder) {
if let Some(node) = self {
node.info(info);
}
}
fn init(&mut self) {
if let Some(node) = self {
node.init();
}
}
fn deinit(&mut self) {
if let Some(node) = self {
node.deinit();
}
}
fn event(&mut self, update: &EventUpdate) {
if let Some(node) = self {
node.event(update);
}
}
fn update(&mut self, updates: &WidgetUpdates) {
if let Some(node) = self {
node.update(updates);
}
}
fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
if let Some(node) = self {
node.measure(wm)
} else {
PxSize::zero()
}
}
fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
if let Some(node) = self {
node.layout(wl)
} else {
PxSize::zero()
}
}
fn render(&mut self, frame: &mut FrameBuilder) {
if let Some(node) = self {
node.render(frame);
}
}
fn render_update(&mut self, update: &mut FrameUpdate) {
if let Some(node) = self {
node.render_update(update);
}
}
fn boxed(self) -> BoxedUiNode
where
Self: Sized,
{
match self {
Some(node) => node.boxed(),
None => NilUiNode.boxed(),
}
}
fn is_widget(&self) -> bool {
match self {
Some(node) => node.is_widget(),
None => false,
}
}
fn is_nil(&self) -> bool {
self.is_none()
}
fn with_context<R, F>(&mut self, update_mode: WidgetUpdateMode, f: F) -> Option<R>
where
F: FnOnce() -> R,
{
match self {
Some(node) => node.with_context(update_mode, f),
None => None,
}
}
fn into_widget(self) -> BoxedUiNode
where
Self: Sized,
{
match self {
Some(node) => node.into_widget(),
None => NilUiNode.into_widget(),
}
}
}
impl UiNodeList for Option<BoxedUiNode> {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
match self {
Some(node) => {
assert_bounds(1, index);
f(node)
}
None => {
assert_bounds(0, index);
unreachable!()
}
}
}
fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
if let Some(node) = self {
f(0, node);
}
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
if let Some(node) = self {
f(0, node);
}
}
fn par_fold_reduce<T, I, F, R>(&mut self, identity: I, fold: F, _: R) -> T
where
T: Send,
I: Fn() -> T + Send + Sync,
F: Fn(T, usize, &mut BoxedUiNode) -> T + Send + Sync,
R: Fn(T, T) -> T + Send + Sync,
{
if let Some(node) = self {
fold(identity(), 0, node)
} else {
identity()
}
}
fn len(&self) -> usize {
match self {
Some(_) => 1,
None => 0,
}
}
fn boxed(self) -> BoxedUiNodeList {
Box::new(self)
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
if let Some(n) = self.take() {
vec.push(n);
}
}
}
fn assert_bounds(len: usize, i: usize) {
if i >= len {
panic!("index `{i}` is >= len `{len}`")
}
}
pub struct NilUiNode;
#[super::ui_node(none)]
impl UiNode for NilUiNode {
fn measure(&mut self, _: &mut WidgetMeasure) -> PxSize {
PxSize::zero()
}
fn layout(&mut self, _: &mut WidgetLayout) -> PxSize {
PxSize::zero()
}
fn is_nil(&self) -> bool {
true
}
}
pub struct FillUiNode;
#[ui_node(none)]
impl UiNode for FillUiNode {}
pub fn with_new_context_init_id(child: impl UiNode) -> impl UiNode {
let mut id = None;
match_node(child, move |child, op| {
let is_deinit = matches!(op, UiNodeOp::Deinit);
id.get_or_insert_with(ContextInitHandle::new).with_context(|| child.op(op));
if is_deinit {
id = None;
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn downcast_unbox() {
fn node() -> impl UiNode {
NilUiNode
}
assert!(node().downcast_unbox::<NilUiNode>().is_ok())
}
#[test]
pub fn downcast_unbox_boxed() {
fn node() -> BoxedUiNode {
NilUiNode.boxed()
}
assert!(node().downcast_unbox::<NilUiNode>().is_ok())
}
#[test]
pub fn downcast_unbox_to_boxed() {
fn node() -> impl UiNode {
NilUiNode.boxed()
}
assert!(node().downcast_unbox::<BoxedUiNode>().is_ok())
}
#[test]
pub fn downcast_unbox_widget() {
fn node() -> BoxedUiNode {
NilUiNode.into_widget()
}
assert!(node().downcast_unbox::<BoxedUiNode>().is_ok())
}
}