use std::{
cmp::Ordering,
mem, ops,
sync::{
atomic::{AtomicBool, Ordering::Relaxed},
Arc,
},
};
use parking_lot::Mutex;
use task::ParallelIteratorExt;
use zng_app_context::context_local;
use zng_layout::unit::{Factor, PxSize, PxTransform, PxVector};
use zng_state_map::StateId;
use zng_task::{self as task, rayon::prelude::*};
use zng_unique_id::static_id;
use zng_var::{animation::Transitionable, impl_from_and_into_var};
use super::*;
#[macro_export]
macro_rules! ui_vec {
() => { $crate::widget::node::UiVec::new() };
($node:expr; $n:expr) => {
{
let mut n: usize = $n;
let mut vec = $crate::widget::node::UiVec::with_capacity(n);
while n > 0 {
vec.push($node);
n -= 1;
}
vec
}
};
($($nodes:tt)+) => {
$crate::ui_vec_items! {
match { $($nodes)+ }
result { }
}
};
}
#[doc(inline)]
pub use crate::ui_vec;
use crate::{
render::{FrameBuilder, FrameUpdate, FrameValueKey},
update::{EventUpdate, WidgetUpdates, UPDATES},
widget::{
base::{Parallel, PARALLEL_VAR},
info::{WidgetInfo, WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
WidgetUpdateMode, WIDGET,
},
};
#[macro_export]
#[doc(hidden)]
macro_rules! ui_vec_items {
(
match { #[$meta:meta] $($tt:tt)* }
result { $($r:tt)* }
) => {
$crate::ui_vec_items! {
match { $($tt)* }
result { $($r)* #[$meta] }
}
};
(
match { $node:expr, $($tt:tt)* }
result { $($r:tt)* }
) => {
$crate::ui_vec_items! {
match { $($tt)* }
result { $($r)* $crate::widget::node::UiNode::boxed($node), }
}
};
(
match { $node:expr }
result { $($r:tt)* }
) => {
$crate::ui_vec_items! {
match { }
result { $($r)* $crate::widget::node::UiNode::boxed($node) }
}
};
(
match { }
result { $($r:tt)* }
) => {
$crate::widget::node::UiVec(std::vec![
$($r)*
])
};
}
fn vec_for_each<F>(self_: &mut [BoxedUiNode], f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnMut(usize, &mut BoxedUiNode)> = Box::new(f);
vec_for_each_impl(self_, f)
}
fn vec_for_each_impl<F>(self_: &mut [BoxedUiNode], mut f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
self_.iter_mut().enumerate().for_each(|(i, n)| f(i, n))
}
fn vec_par_each<F>(self_: &mut Vec<BoxedUiNode>, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn Fn(usize, &mut BoxedUiNode) + Send + Sync> = Box::new(f);
par_each_impl(self_, f)
}
fn par_each_impl<F>(self_: &mut Vec<BoxedUiNode>, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
self_.par_iter_mut().enumerate().with_ctx().for_each(|(i, n)| f(i, n));
}
fn vec_par_fold_reduce<T, I, F, R>(self_: &mut Vec<BoxedUiNode>, identity: I, fold: F, reduce: 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,
{
#[cfg(feature = "dyn_closure")]
let identity: Box<dyn Fn() -> T + Send + Sync> = Box::new(identity);
#[cfg(feature = "dyn_closure")]
let fold: Box<dyn Fn(T, usize, &mut BoxedUiNode) -> T + Send + Sync> = Box::new(fold);
#[cfg(feature = "dyn_closure")]
let reduce: Box<dyn Fn(T, T) -> T + Send + Sync> = Box::new(reduce);
par_fold_reduce_impl(self_, identity, fold, reduce)
}
fn par_fold_reduce_impl<T, I, F, R>(self_: &mut Vec<BoxedUiNode>, identity: I, fold: F, reduce: 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,
{
self_
.par_iter_mut()
.enumerate()
.with_ctx()
.fold(&identity, move |a, (i, n)| fold(a, i, n))
.reduce(&identity, reduce)
}
impl UiNodeList for Vec<BoxedUiNode> {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
f(&mut self[index])
}
fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
vec_for_each(self, f)
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
vec_par_each(self, f)
}
fn par_fold_reduce<T, I, F, R>(&mut self, identity: I, fold: F, reduce: 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,
{
vec_par_fold_reduce(self, identity, fold, reduce)
}
fn len(&self) -> usize {
Vec::len(self)
}
fn boxed(self) -> BoxedUiNodeList {
Box::new(self)
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
vec.append(self)
}
}
#[derive(Default)]
pub struct UiVec(pub Vec<BoxedUiNode>);
impl UiVec {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
pub fn push(&mut self, node: impl UiNode) {
self.0.push(node.boxed())
}
pub fn insert(&mut self, index: usize, node: impl UiNode) {
self.0.insert(index, node.boxed())
}
}
impl ops::Deref for UiVec {
type Target = Vec<BoxedUiNode>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ops::DerefMut for UiVec {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<Vec<BoxedUiNode>> for UiVec {
fn from(vec: Vec<BoxedUiNode>) -> Self {
Self(vec)
}
}
impl From<UiVec> for Vec<BoxedUiNode> {
fn from(vec: UiVec) -> Self {
vec.0
}
}
impl<U: UiNode> FromIterator<U> for UiVec {
fn from_iter<T: IntoIterator<Item = U>>(iter: T) -> Self {
Self(Vec::from_iter(iter.into_iter().map(UiNode::boxed)))
}
}
impl IntoIterator for UiVec {
type Item = BoxedUiNode;
type IntoIter = std::vec::IntoIter<BoxedUiNode>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl UiNodeList for UiVec {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
self.0.with_node(index, f)
}
fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
self.0.for_each(f)
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
self.0.par_each(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.0.par_fold_reduce(identity, fold, reduce)
}
fn len(&self) -> usize {
self.0.len()
}
fn boxed(self) -> BoxedUiNodeList {
self.0.boxed()
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
self.0.drain_into(vec)
}
}
pub trait UiNodeListChain: UiNodeList {
fn chain<B>(self, other: B) -> UiNodeListChainImpl
where
B: UiNodeList,
Self: Sized;
}
impl<A: UiNodeList> UiNodeListChain for A {
fn chain<B>(self, other: B) -> UiNodeListChainImpl
where
B: UiNodeList,
{
UiNodeListChainImpl(self.boxed(), other.boxed())
}
}
fn chain_for_each<F>(self_: &mut UiNodeListChainImpl, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnMut(usize, &mut BoxedUiNode)> = Box::new(f);
chain_for_each_impl(self_, f)
}
fn chain_for_each_impl<F>(self_: &mut UiNodeListChainImpl, mut f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
self_.0.for_each(&mut f);
let offset = self_.0.len();
self_.1.for_each(move |i, n| f(i + offset, n))
}
fn chain_par_each<F>(self_: &mut UiNodeListChainImpl, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn Fn(usize, &mut BoxedUiNode) + Send + Sync> = Box::new(f);
chain_par_each_impl(self_, f)
}
fn chain_par_each_impl<F>(self_: &mut UiNodeListChainImpl, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
let offset = self_.0.len();
task::join(|| self_.0.par_each(&f), || self_.1.par_each(|i, n| f(i + offset, n)));
}
fn chain_par_fold_reduce<T, I, F, R>(self_: &mut UiNodeListChainImpl, 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,
{
#[cfg(feature = "dyn_closure")]
let identity: Box<dyn Fn() -> T + Send + Sync> = Box::new(identity);
#[cfg(feature = "dyn_closure")]
let fold: Box<dyn Fn(T, usize, &mut BoxedUiNode) -> T + Send + Sync> = Box::new(fold);
#[cfg(feature = "dyn_closure")]
let reduce: Box<dyn Fn(T, T) -> T + Send + Sync> = Box::new(reduce);
chain_par_fold_reduce_impl(self_, identity, fold, reduce)
}
fn chain_par_fold_reduce_impl<T, I, F, R>(self_: &mut UiNodeListChainImpl, 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,
{
let offset = self_.0.len();
let (a, b) = task::join(
|| self_.0.par_fold_reduce(&identity, &fold, &reduce),
|| self_.1.par_fold_reduce(&identity, |a, i, n| fold(a, i + offset, n), &reduce),
);
reduce(a, b)
}
pub struct UiNodeListChainImpl(pub BoxedUiNodeList, pub BoxedUiNodeList);
impl UiNodeList for UiNodeListChainImpl {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
assert_bounds(self.len(), index);
if index < self.0.len() {
self.0.with_node(index, f)
} else {
self.1.with_node(index - self.0.len(), f)
}
}
fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
chain_for_each(self, f)
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
chain_par_each(self, 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,
{
chain_par_fold_reduce(self, identity, fold, reduce)
}
fn len(&self) -> usize {
self.0.len() + self.1.len()
}
fn boxed(self) -> BoxedUiNodeList {
Box::new(self)
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
self.0.drain_into(vec);
self.1.drain_into(vec);
}
fn init_all(&mut self) {
if PARALLEL_VAR.get().contains(Parallel::INIT) {
task::join(|| self.0.init_all(), || self.1.init_all());
} else {
self.0.init_all();
self.1.init_all();
}
}
fn deinit_all(&mut self) {
if PARALLEL_VAR.get().contains(Parallel::DEINIT) {
task::join(|| self.0.deinit_all(), || self.1.deinit_all());
} else {
self.0.deinit_all();
self.1.deinit_all();
}
}
fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
if PARALLEL_VAR.get().contains(Parallel::INFO) {
let mut b = info.parallel_split();
task::join(|| self.0.info_all(info), || self.1.info_all(&mut b));
info.parallel_fold(b);
} else {
self.0.info_all(info);
self.1.info_all(info);
}
}
fn event_all(&mut self, update: &EventUpdate) {
if PARALLEL_VAR.get().contains(Parallel::EVENT) {
task::join(|| self.0.event_all(update), || self.1.event_all(update));
} else {
self.0.event_all(update);
self.1.event_all(update);
}
}
fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
if observer.is_reset_only() && PARALLEL_VAR.get().contains(Parallel::UPDATE) {
let (r0, r1) = task::join(
|| {
let mut r = false;
self.0.update_all(updates, &mut r);
r
},
|| {
let mut r = false;
self.1.update_all(updates, &mut r);
r
},
);
if r0 || r1 {
observer.reset();
}
} else {
self.0.update_all(updates, observer);
self.1.update_all(updates, &mut OffsetUiListObserver(self.0.len(), observer));
}
}
fn render_all(&mut self, frame: &mut FrameBuilder) {
if PARALLEL_VAR.get().contains(Parallel::RENDER) {
let mut b = frame.parallel_split();
task::join(|| self.0.render_all(frame), || self.1.render_all(&mut b));
frame.parallel_fold(b);
} else {
self.0.render_all(frame);
self.1.render_all(frame);
}
}
fn render_update_all(&mut self, update: &mut FrameUpdate) {
if PARALLEL_VAR.get().contains(Parallel::RENDER) {
let mut b = update.parallel_split();
task::join(|| self.0.render_update_all(update), || self.1.render_update_all(&mut b));
update.parallel_fold(b);
} else {
self.0.render_update_all(update);
self.1.render_update_all(update);
}
}
}
#[expect(non_camel_case_types)]
pub struct SORTING_LIST;
impl SORTING_LIST {
pub fn is_inside_list(&self) -> bool {
!SORTING_LIST_PARENT.is_default()
}
pub fn invalidate_sort(&self) {
SORTING_LIST_PARENT.get().store(true, Relaxed)
}
fn with<R>(&self, action: impl FnOnce() -> R) -> (R, bool) {
SORTING_LIST_PARENT.with_context(&mut Some(Arc::new(AtomicBool::new(false))), || {
let r = action();
(r, SORTING_LIST_PARENT.get().load(Relaxed))
})
}
}
context_local! {
static SORTING_LIST_PARENT: AtomicBool = AtomicBool::new(false);
}
pub struct SortingList {
list: BoxedUiNodeList,
map: Vec<usize>,
sort: Box<dyn Fn(&mut BoxedUiNode, &mut BoxedUiNode) -> Ordering + Send + 'static>,
}
impl SortingList {
pub fn new(list: impl UiNodeList, sort: impl Fn(&mut BoxedUiNode, &mut BoxedUiNode) -> Ordering + Send + 'static) -> Self {
Self {
list: list.boxed(),
map: vec![],
sort: Box::new(sort),
}
}
fn update_map(&mut self) {
let map = &mut self.map;
let len = self.list.len();
if len == 0 {
map.clear();
} else if map.len() != len {
map.clear();
map.extend(0..len);
let mut taken_a = NilUiNode.boxed();
map.sort_by(|&a, &b| {
self.list.with_node(a, |a| mem::swap(a, &mut taken_a));
let result = self.list.with_node(b, |b| (self.sort)(&mut taken_a, b));
self.list.with_node(a, |a| mem::swap(a, &mut taken_a));
result
})
}
}
pub fn list(&mut self) -> &mut BoxedUiNodeList {
&mut self.list
}
pub fn invalidate_sort(&mut self) {
self.map.clear()
}
fn with_map<R>(&mut self, f: impl FnOnce(&[usize], &mut BoxedUiNodeList) -> R) -> R {
self.update_map();
let (r, resort) = SORTING_LIST.with(|| f(&self.map, &mut self.list));
if resort {
self.invalidate_sort();
}
r
}
}
impl UiNodeList for SortingList {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
self.with_map(|map, list| list.with_node(map[index], f))
}
fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
self.with_map(|map, list| {
for (index, map) in map.iter().enumerate() {
list.with_node(*map, |n| f(index, n))
}
});
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
self.for_each(f)
}
fn par_fold_reduce<T, I, F, R>(&mut self, identity: I, fold: F, _: 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,
{
let mut r = Some(identity());
self.for_each(|i, n| {
r = Some(fold(r.take().unwrap(), i, n));
});
r.unwrap()
}
fn len(&self) -> usize {
self.list.len()
}
fn boxed(self) -> BoxedUiNodeList {
Box::new(self)
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
let start = vec.len();
self.with_map(|map, list| {
list.drain_into(vec);
sort_by_indices(&mut vec[start..], map.to_vec());
});
self.map.clear();
}
fn init_all(&mut self) {
let _ = SORTING_LIST.with(|| self.list.init_all());
self.invalidate_sort();
}
fn deinit_all(&mut self) {
let _ = SORTING_LIST.with(|| self.list.deinit_all());
self.invalidate_sort();
}
fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
self.list.info_all(info);
}
fn event_all(&mut self, update: &EventUpdate) {
self.list.event_all(update);
}
fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
let mut changed = false;
let (_, resort) = SORTING_LIST.with(|| self.list.update_all(updates, &mut (observer, &mut changed as _)));
if changed || resort {
self.invalidate_sort();
}
}
fn render_all(&mut self, frame: &mut FrameBuilder) {
self.for_each(|_, n| n.render(frame));
}
fn render_update_all(&mut self, update: &mut FrameUpdate) {
self.list.render_update_all(update);
}
fn is_empty(&self) -> bool {
self.len() == 0
}
}
fn sort_by_indices<T>(data: &mut [T], mut indices: Vec<usize>) {
for idx in 0..data.len() {
if indices[idx] != idx {
let mut current_idx = idx;
loop {
let target_idx = indices[current_idx];
indices[current_idx] = current_idx;
if indices[target_idx] == target_idx {
break;
}
data.swap(current_idx, target_idx);
current_idx = target_idx;
}
}
}
}
#[derive(Default, Debug)]
struct ZIndexCtx {
panel_id: Option<WidgetId>,
resort: AtomicBool,
}
context_local! {
static Z_INDEX_CTX: ZIndexCtx = ZIndexCtx::default();
}
#[expect(non_camel_case_types)]
pub struct Z_INDEX;
impl Z_INDEX {
fn with(&self, panel_id: WidgetId, action: impl FnOnce()) -> bool {
let ctx = ZIndexCtx {
panel_id: Some(panel_id),
resort: AtomicBool::new(false),
};
Z_INDEX_CTX.with_context(&mut Some(Arc::new(ctx)), || {
action();
Z_INDEX_CTX.get().resort.load(Relaxed)
})
}
pub fn get(&self) -> ZIndex {
WIDGET.get_state(*Z_INDEX_ID).unwrap_or_default()
}
pub fn get_wgt(&self, widget: &mut impl UiNode) -> ZIndex {
widget.with_context(WidgetUpdateMode::Ignore, || self.get()).unwrap_or_default()
}
pub fn set(&self, index: ZIndex) -> bool {
let z_ctx = Z_INDEX_CTX.get();
let valid = z_ctx.panel_id == WIDGET.parent_id() && z_ctx.panel_id.is_some();
if valid {
z_ctx.resort.store(true, Relaxed);
WIDGET.set_state(*Z_INDEX_ID, index);
}
valid
}
}
static_id! {
static ref Z_INDEX_ID: StateId<ZIndex>;
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Transitionable)]
pub struct ZIndex(pub u32);
impl ZIndex {
pub const BACK: ZIndex = ZIndex(0);
pub const DEFAULT: ZIndex = ZIndex(u32::MAX / 2);
pub const FRONT: ZIndex = ZIndex(u32::MAX);
pub fn saturating_add(self, other: impl Into<Self>) -> Self {
ZIndex(self.0.saturating_add(other.into().0))
}
pub fn saturating_sub(self, other: impl Into<Self>) -> Self {
ZIndex(self.0.saturating_sub(other.into().0))
}
}
impl Default for ZIndex {
fn default() -> Self {
ZIndex::DEFAULT
}
}
impl<Z: Into<ZIndex>> ops::Add<Z> for ZIndex {
type Output = Self;
fn add(self, rhs: Z) -> Self::Output {
self.saturating_add(rhs)
}
}
impl<Z: Into<ZIndex>> ops::AddAssign<Z> for ZIndex {
fn add_assign(&mut self, rhs: Z) {
*self = *self + rhs;
}
}
impl<Z: Into<ZIndex>> ops::Sub<Z> for ZIndex {
type Output = Self;
fn sub(self, rhs: Z) -> Self::Output {
self.saturating_sub(rhs)
}
}
impl<Z: Into<ZIndex>> ops::SubAssign<Z> for ZIndex {
fn sub_assign(&mut self, rhs: Z) {
*self = *self - rhs;
}
}
impl ops::Mul<Factor> for ZIndex {
type Output = Self;
fn mul(self, rhs: Factor) -> Self::Output {
ZIndex(self.0 * rhs)
}
}
impl ops::Div<Factor> for ZIndex {
type Output = Self;
fn div(self, rhs: Factor) -> Self::Output {
ZIndex(self.0 / rhs)
}
}
impl ops::MulAssign<Factor> for ZIndex {
fn mul_assign(&mut self, rhs: Factor) {
self.0 *= rhs;
}
}
impl ops::DivAssign<Factor> for ZIndex {
fn div_assign(&mut self, rhs: Factor) {
self.0 /= rhs;
}
}
impl fmt::Debug for ZIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let z = *self;
if f.alternate() {
write!(f, "ZIndex::")?;
}
if z == Self::DEFAULT {
write!(f, "DEFAULT")
} else if z == Self::BACK {
write!(f, "BACK")
} else if z == Self::FRONT {
write!(f, "FRONT")
} else if z > Self::DEFAULT {
if z > Self::FRONT - 10000 {
write!(f, "FRONT-{}", Self::FRONT.0 - z.0)
} else {
write!(f, "DEFAULT+{}", z.0 - Self::DEFAULT.0)
}
} else if z < Self::BACK + 10000 {
write!(f, "BACK+{}", z.0 - Self::BACK.0)
} else {
write!(f, "DEFAULT-{}", Self::DEFAULT.0 - z.0)
}
}
}
impl_from_and_into_var! {
fn from(index: u32) -> ZIndex {
ZIndex(index)
}
}
pub trait UiNodeListObserver {
fn inserted(&mut self, index: usize);
fn removed(&mut self, index: usize);
fn moved(&mut self, removed_index: usize, inserted_index: usize);
fn reset(&mut self);
fn is_reset_only(&self) -> bool;
}
impl UiNodeListObserver for () {
fn is_reset_only(&self) -> bool {
true
}
fn reset(&mut self) {}
fn inserted(&mut self, _: usize) {}
fn removed(&mut self, _: usize) {}
fn moved(&mut self, _: usize, _: usize) {}
}
impl UiNodeListObserver for bool {
fn is_reset_only(&self) -> bool {
true
}
fn reset(&mut self) {
*self = true;
}
fn inserted(&mut self, _: usize) {
*self = true;
}
fn removed(&mut self, _: usize) {
*self = true;
}
fn moved(&mut self, _: usize, _: usize) {
*self = true;
}
}
pub struct OffsetUiListObserver<'o>(pub usize, pub &'o mut dyn UiNodeListObserver);
impl<'o> UiNodeListObserver for OffsetUiListObserver<'o> {
fn is_reset_only(&self) -> bool {
self.1.is_reset_only()
}
fn reset(&mut self) {
self.1.reset()
}
fn inserted(&mut self, index: usize) {
self.1.inserted(index + self.0)
}
fn removed(&mut self, index: usize) {
self.1.removed(index + self.0)
}
fn moved(&mut self, removed_index: usize, inserted_index: usize) {
self.1.moved(removed_index + self.0, inserted_index + self.0)
}
}
impl UiNodeListObserver for (&mut dyn UiNodeListObserver, &mut dyn UiNodeListObserver) {
fn is_reset_only(&self) -> bool {
self.0.is_reset_only() && self.1.is_reset_only()
}
fn reset(&mut self) {
self.0.reset();
self.1.reset();
}
fn inserted(&mut self, index: usize) {
self.0.inserted(index);
self.1.inserted(index);
}
fn removed(&mut self, index: usize) {
self.0.removed(index);
self.1.removed(index);
}
fn moved(&mut self, removed_index: usize, inserted_index: usize) {
self.0.moved(removed_index, inserted_index);
self.1.moved(removed_index, inserted_index);
}
}
pub struct EditableUiNodeList {
vec: Vec<BoxedUiNode>,
ctrl: EditableUiNodeListRef,
}
impl Default for EditableUiNodeList {
fn default() -> Self {
Self {
vec: vec![],
ctrl: EditableUiNodeListRef::new(true),
}
}
}
impl Drop for EditableUiNodeList {
fn drop(&mut self) {
self.ctrl.0.lock().alive = false;
}
}
impl EditableUiNodeList {
pub fn new() -> Self {
Self::default()
}
pub fn from_vec(vec: impl Into<Vec<BoxedUiNode>>) -> Self {
let mut s = Self::new();
s.vec = vec.into();
s
}
pub fn reference(&self) -> EditableUiNodeListRef {
self.ctrl.clone()
}
fn fulfill_requests(&mut self, observer: &mut dyn UiNodeListObserver) {
if let Some(r) = self.ctrl.take_requests() {
if r.clear {
self.clear();
observer.reset();
for (i, mut wgt) in r.insert {
wgt.init();
WIDGET.update_info();
if i < self.len() {
self.insert(i, wgt);
} else {
self.push(wgt);
}
}
for mut wgt in r.push {
wgt.init();
WIDGET.update_info();
self.push(wgt);
}
for (r, i) in r.move_index {
if r < self.len() {
let wgt = self.vec.remove(r);
if i < self.len() {
self.vec.insert(i, wgt);
} else {
self.vec.push(wgt);
}
WIDGET.update_info();
}
}
for (id, to) in r.move_id {
if let Some(r) = self
.vec
.iter_mut()
.position(|w| w.with_context(WidgetUpdateMode::Ignore, || WIDGET.id() == id).unwrap_or(false))
{
let i = to(r, self.len());
if r != i {
let wgt = self.vec.remove(r);
if i < self.len() {
self.vec.insert(i, wgt);
} else {
self.vec.push(wgt);
}
WIDGET.update_info();
}
}
}
} else {
let mut removed = false;
for mut retain in r.retain {
let mut i = 0;
self.vec.retain_mut(|n| {
let r = retain(n);
if !r {
n.deinit();
removed = true;
observer.removed(i);
} else {
i += 1;
}
r
});
}
if removed {
WIDGET.update_info();
}
for (i, mut wgt) in r.insert {
wgt.init();
WIDGET.update_info();
if i < self.len() {
self.insert(i, wgt);
observer.inserted(i);
} else {
observer.inserted(self.len());
self.push(wgt);
}
}
for mut wgt in r.push {
wgt.init();
WIDGET.update_info();
observer.inserted(self.len());
self.push(wgt);
}
for (r, i) in r.move_index {
if r < self.len() {
let wgt = self.vec.remove(r);
if i < self.len() {
self.vec.insert(i, wgt);
observer.moved(r, i);
} else {
let i = self.vec.len();
self.vec.push(wgt);
observer.moved(r, i);
}
WIDGET.update_info();
}
}
for (id, to) in r.move_id {
if let Some(r) = self
.vec
.iter_mut()
.position(|w| w.with_context(WidgetUpdateMode::Ignore, || WIDGET.id() == id).unwrap_or(false))
{
let i = to(r, self.len());
if r != i {
let wgt = self.vec.remove(r);
if i < self.len() {
self.vec.insert(i, wgt);
observer.moved(r, i);
} else {
let i = self.vec.len();
self.vec.push(wgt);
observer.moved(r, i);
}
WIDGET.update_info();
}
}
}
}
}
}
}
impl ops::Deref for EditableUiNodeList {
type Target = Vec<BoxedUiNode>;
fn deref(&self) -> &Self::Target {
&self.vec
}
}
impl ops::DerefMut for EditableUiNodeList {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.vec
}
}
impl UiNodeList for EditableUiNodeList {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
self.vec.with_node(index, f)
}
fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
self.vec.for_each(f)
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
self.vec.par_each(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.vec.par_fold_reduce(identity, fold, reduce)
}
fn len(&self) -> usize {
self.vec.len()
}
fn boxed(self) -> BoxedUiNodeList {
Box::new(self)
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
vec.append(&mut self.vec)
}
fn init_all(&mut self) {
self.ctrl.0.lock().target = Some(WIDGET.id());
self.vec.init_all();
}
fn deinit_all(&mut self) {
self.ctrl.0.lock().target = None;
self.vec.deinit_all();
}
fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
self.vec.info_all(info);
}
fn event_all(&mut self, update: &EventUpdate) {
self.vec.event_all(update)
}
fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
self.vec.update_all(updates, &mut ());
self.fulfill_requests(observer);
}
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.vec.measure_each(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.vec.layout_each(wl, layout, fold_size)
}
fn render_all(&mut self, frame: &mut FrameBuilder) {
self.vec.render_all(frame)
}
fn render_update_all(&mut self, update: &mut FrameUpdate) {
self.vec.render_update_all(update)
}
}
type NodeMoveToFn = fn(usize, usize) -> usize;
#[derive(Clone, Debug)]
pub struct EditableUiNodeListRef(Arc<Mutex<EditRequests>>);
struct EditRequests {
target: Option<WidgetId>,
insert: Vec<(usize, BoxedUiNode)>,
push: Vec<BoxedUiNode>,
retain: Vec<Box<dyn FnMut(&mut BoxedUiNode) -> bool + Send>>,
move_index: Vec<(usize, usize)>,
move_id: Vec<(WidgetId, NodeMoveToFn)>,
clear: bool,
alive: bool,
}
impl fmt::Debug for EditRequests {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EditRequests")
.field("target", &self.target)
.field("insert.len", &self.insert.len())
.field("push.len", &self.push.len())
.field("retain.len", &self.retain.len())
.field("move_index", &self.move_index)
.field("move_id", &self.move_id)
.field("clear", &self.clear)
.field("alive", &self.alive)
.finish()
}
}
impl EditableUiNodeListRef {
fn new(alive: bool) -> Self {
Self(Arc::new(Mutex::new(EditRequests {
target: None,
insert: vec![],
push: vec![],
retain: vec![],
move_index: vec![],
move_id: vec![],
clear: false,
alive,
})))
}
pub fn dummy() -> Self {
Self::new(false)
}
pub fn alive(&self) -> bool {
self.0.lock().alive
}
pub fn insert(&self, index: usize, widget: impl UiNode) {
let mut s = self.0.lock();
if !s.alive {
return;
}
s.insert.push((index, widget.boxed()));
UPDATES.update(s.target);
}
pub fn push(&self, widget: impl UiNode) {
let mut s = self.0.lock();
if !s.alive {
return;
}
s.push.push(widget.boxed());
UPDATES.update(s.target);
}
pub fn remove(&self, id: impl Into<WidgetId>) {
fn remove_impl(id: WidgetId) -> impl FnMut(&mut BoxedUiNode) -> bool + Send + 'static {
move |node| node.with_context(WidgetUpdateMode::Ignore, || WIDGET.id() != id).unwrap_or(true)
}
self.retain(remove_impl(id.into()))
}
pub fn retain(&self, predicate: impl FnMut(&mut BoxedUiNode) -> bool + Send + 'static) {
let mut s = self.0.lock();
if !s.alive {
return;
}
s.retain.push(Box::new(predicate));
UPDATES.update(s.target);
}
pub fn move_index(&self, remove_index: usize, insert_index: usize) {
if remove_index != insert_index {
let mut s = self.0.lock();
if !s.alive {
return;
}
s.move_index.push((remove_index, insert_index));
UPDATES.update(s.target);
}
}
pub fn move_id(&self, id: impl Into<WidgetId>, get_move_to: NodeMoveToFn) {
let mut s = self.0.lock();
if !s.alive {
return;
}
s.move_id.push((id.into(), get_move_to));
UPDATES.update(s.target);
}
pub fn clear(&self) {
let mut s = self.0.lock();
s.clear = true;
UPDATES.update(s.target);
}
fn take_requests(&self) -> Option<EditRequests> {
let mut s = self.0.lock();
if s.clear
|| !s.insert.is_empty()
|| !s.push.is_empty()
|| !s.retain.is_empty()
|| !s.move_index.is_empty()
|| !s.move_id.is_empty()
{
let empty = EditRequests {
target: s.target,
alive: s.alive,
insert: vec![],
push: vec![],
retain: vec![],
move_index: vec![],
move_id: vec![],
clear: false,
};
Some(mem::replace(&mut *s, empty))
} else {
None
}
}
}
fn many_list_index(lists: &Vec<BoxedUiNodeList>, index: usize) -> (usize, usize) {
let mut offset = 0;
for (li, list) in lists.iter().enumerate() {
let i = index - offset;
let len = list.len();
if i < len {
return (li, i);
}
offset += len;
}
panic!(
"'index out of bounds: the len is {} but the index is {}",
UiNodeList::len(lists),
index
);
}
fn vec_list_for_each<F>(self_: &mut Vec<BoxedUiNodeList>, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnMut(usize, &mut BoxedUiNode)> = Box::new(f);
vec_list_for_each_impl(self_, f)
}
fn vec_list_for_each_impl<F>(self_: &mut Vec<BoxedUiNodeList>, mut f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
let mut offset = 0;
for list in self_ {
list.for_each(|i, n| f(i + offset, n));
offset += list.len();
}
}
fn vec_list_par_each<F>(self_: &mut Vec<BoxedUiNodeList>, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn Fn(usize, &mut BoxedUiNode) + Send + Sync> = Box::new(f);
vec_list_par_each_impl(self_, f)
}
fn vec_list_par_each_impl<F>(self_: &mut Vec<BoxedUiNodeList>, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
task::scope(|s| {
let f = &f;
let mut offset = 0;
for list in self_ {
let len = list.len();
s.spawn(move |_| {
list.par_each(move |i, n| f(i + offset, n));
});
offset += len;
}
});
}
fn vec_list_par_fold_reduce<T, I, F, R>(self_: &mut [BoxedUiNodeList], 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,
{
#[cfg(feature = "dyn_closure")]
let identity: Box<dyn Fn() -> T + Send + Sync> = Box::new(identity);
#[cfg(feature = "dyn_closure")]
let fold: Box<dyn Fn(T, usize, &mut BoxedUiNode) -> T + Send + Sync> = Box::new(fold);
#[cfg(feature = "dyn_closure")]
let reduce: Box<dyn Fn(T, T) -> T + Send + Sync> = Box::new(reduce);
vec_list_par_fold_reduce_impl(self_, identity, fold, reduce)
}
fn vec_list_par_fold_reduce_impl<T, I, F, R>(self_: &mut [BoxedUiNodeList], 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,
{
let mut offset = 0;
let mut r = Some(identity());
for list in self_.chunks_mut(2) {
let b = if list.len() == 2 {
let mut pair = list.iter_mut();
let a = pair.next().unwrap();
let b = pair.next().unwrap();
let offset_b = offset + a.len();
let (a, b) = task::join(
|| a.par_fold_reduce(&identity, |a, i, n| fold(a, i + offset, n), &reduce),
|| b.par_fold_reduce(&identity, |a, i, n| fold(a, i + offset_b, n), &reduce),
);
reduce(a, b)
} else {
list[0].par_fold_reduce(&identity, |a, i, n| fold(a, i + offset, n), &reduce)
};
let a = r.take().unwrap();
r = Some(reduce(a, b));
offset += list.iter().map(|l| l.len()).sum::<usize>();
}
r.unwrap()
}
impl UiNodeList for Vec<BoxedUiNodeList> {
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
let (l, i) = many_list_index(self, index);
self[l].with_node(i, f)
}
fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
vec_list_for_each(self, f)
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
vec_list_par_each(self, 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,
{
vec_list_par_fold_reduce(self, identity, fold, reduce)
}
fn len(&self) -> usize {
self.iter().map(|l| l.len()).sum()
}
fn boxed(self) -> BoxedUiNodeList {
Box::new(self)
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
for mut list in self.drain(..) {
list.drain_into(vec);
}
}
fn is_empty(&self) -> bool {
self.iter().all(|l| l.is_empty())
}
fn init_all(&mut self) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::INIT) {
self.par_iter_mut().with_ctx().for_each(|l| l.init_all());
} else {
for l in self {
l.init_all();
}
}
}
fn deinit_all(&mut self) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::DEINIT) {
self.par_iter_mut().with_ctx().for_each(|l| l.deinit_all());
} else {
for list in self {
list.deinit_all();
}
}
}
fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
if self.len() > 1 && observer.is_reset_only() && PARALLEL_VAR.get().contains(Parallel::UPDATE) {
let r = self
.par_iter_mut()
.with_ctx()
.map(|l| {
let mut r = false;
l.update_all(updates, &mut r);
r
})
.any(std::convert::identity);
if r {
observer.reset();
}
} else {
let mut offset = 0;
for list in self {
list.update_all(updates, &mut OffsetUiListObserver(offset, observer));
offset += list.len();
}
}
}
fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::INFO) {
let b = self
.par_iter_mut()
.with_ctx()
.fold(
|| info.parallel_split(),
|mut info, list| {
list.info_all(&mut info);
info
},
)
.reduce(
|| info.parallel_split(),
|mut a, b| {
a.parallel_fold(b);
a
},
);
info.parallel_fold(b);
} else {
for list in self {
list.info_all(info);
}
}
}
fn event_all(&mut self, update: &EventUpdate) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::EVENT) {
self.par_iter_mut().with_ctx().for_each(|l| l.event_all(update));
} else {
for list in self {
list.event_all(update);
}
}
}
fn render_all(&mut self, frame: &mut FrameBuilder) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::RENDER) {
let b = self
.par_iter_mut()
.with_ctx()
.fold(
|| frame.parallel_split(),
|mut frame, list| {
list.render_all(&mut frame);
frame
},
)
.reduce(
|| frame.parallel_split(),
|mut a, b| {
a.parallel_fold(b);
a
},
);
frame.parallel_fold(b);
} else {
for list in self {
list.render_all(frame);
}
}
}
fn render_update_all(&mut self, update: &mut FrameUpdate) {
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::RENDER) {
let b = self
.par_iter_mut()
.with_ctx()
.fold(
|| update.parallel_split(),
|mut update, list| {
list.render_update_all(&mut update);
update
},
)
.reduce(
|| update.parallel_split(),
|mut a, b| {
a.parallel_fold(b);
a
},
);
update.parallel_fold(b);
} else {
for list in self {
list.render_update_all(update);
}
}
}
}
#[derive(Debug, Clone)]
pub struct PanelListRange {
range: Option<(WidgetId, WidgetId)>,
version: u8,
}
impl PanelListRange {
pub fn update(
parent: &WidgetInfo,
panel_id: impl Into<StateId<Self>>,
last_version: &mut Option<u8>,
) -> Option<crate::widget::info::iter::Children> {
let range = parent.meta().get_clone(panel_id);
if let Some(Self { range, version }) = range {
let version = Some(version);
if *last_version != version {
*last_version = version;
if let Some((s, e)) = range {
let tree = parent.tree();
if let (Some(s), Some(e)) = (tree.get(s), tree.get(e)) {
let parent = Some(parent);
if s.parent().as_ref() == parent && e.parent().as_ref() == parent {
return Some(crate::widget::info::iter::Children::new_range(s, e));
}
}
}
}
}
None
}
pub fn get(parent: &WidgetInfo, panel_id: impl Into<StateId<Self>>) -> Option<crate::widget::info::iter::Children> {
let range = parent.meta().get_clone(panel_id);
if let Some(Self { range: Some((s, e)), .. }) = range {
let tree = parent.tree();
if let (Some(s), Some(e)) = (tree.get(s), tree.get(e)) {
let parent = Some(parent);
if s.parent().as_ref() == parent && e.parent().as_ref() == parent {
return Some(crate::widget::info::iter::Children::new_range(s, e));
}
}
}
None
}
}
pub struct PanelList<D = DefaultPanelListData>
where
D: PanelListData,
{
list: BoxedUiNodeList,
data: Vec<Mutex<D>>, offset_key: FrameValueKey<PxTransform>,
info_id: Option<(StateId<PanelListRange>, u8, bool)>,
z_map: Vec<u64>,
z_naturally_sorted: bool,
}
impl PanelList<DefaultPanelListData> {
pub fn new(list: impl UiNodeList) -> Self {
Self::new_custom(list)
}
}
impl<D> PanelList<D>
where
D: PanelListData,
{
pub fn new_custom(list: impl UiNodeList) -> Self {
Self {
data: {
let mut d = vec![];
d.resize_with(list.len(), Default::default);
d
},
list: list.boxed(),
offset_key: FrameValueKey::new_unique(),
info_id: None,
z_map: vec![],
z_naturally_sorted: false,
}
}
pub fn track_info_range(mut self, info_id: impl Into<StateId<PanelListRange>>) -> Self {
self.info_id = Some((info_id.into(), 0, true));
self
}
pub fn into_parts(
self,
) -> (
BoxedUiNodeList,
Vec<Mutex<D>>,
FrameValueKey<PxTransform>,
Option<StateId<PanelListRange>>,
) {
(self.list, self.data, self.offset_key, self.info_id.map(|t| t.0))
}
pub fn from_parts(
list: BoxedUiNodeList,
data: Vec<Mutex<D>>,
offset_key: FrameValueKey<PxTransform>,
info_id: Option<StateId<PanelListRange>>,
) -> Self {
assert_eq!(list.len(), data.len());
Self {
list,
data,
offset_key,
info_id: info_id.map(|i| (i, 0, true)),
z_map: vec![],
z_naturally_sorted: false,
}
}
pub fn info_id(&self) -> Option<StateId<PanelListRange>> {
self.info_id.as_ref().map(|t| t.0)
}
pub fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode, &mut D) -> R,
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnOnce(&mut BoxedUiNode, &mut D) -> R> = Box::new(f);
self.with_node_impl(index, f)
}
fn with_node_impl<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode, &mut D) -> R,
{
let data = self.data[index].get_mut();
self.list.with_node(index, move |n| f(n, data))
}
pub fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode, &mut D),
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnMut(usize, &mut BoxedUiNode, &mut D)> = Box::new(f);
self.for_each_impl(f)
}
fn for_each_impl<F>(&mut self, mut f: F)
where
F: FnMut(usize, &mut BoxedUiNode, &mut D),
{
let data = &mut self.data;
self.list.for_each(move |i, n| f(i, n, data[i].get_mut()))
}
pub fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode, &mut D) + Send + Sync,
D: Sync,
{
#[cfg(feature = "dyn_closure")]
let f: Box<dyn Fn(usize, &mut BoxedUiNode, &mut D) + Send + Sync> = Box::new(f);
self.par_each_impl(f)
}
fn par_each_impl<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode, &mut D) + Send + Sync,
D: Sync,
{
let data = &self.data;
self.list.par_each(|i, n| {
f(
i,
n,
&mut data[i].try_lock().unwrap_or_else(|| panic!("data for `{i}` is already locked")),
)
})
}
pub 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, &mut D) -> T + Send + Sync,
R: Fn(T, T) -> T + Send + Sync,
{
#[cfg(feature = "dyn_closure")]
let identity: Box<dyn Fn() -> T + Send + Sync> = Box::new(identity);
#[cfg(feature = "dyn_closure")]
let fold: Box<dyn Fn(T, usize, &mut BoxedUiNode, &mut D) -> T + Send + Sync> = Box::new(fold);
#[cfg(feature = "dyn_closure")]
let reduce: Box<dyn Fn(T, T) -> T + Send + Sync> = Box::new(reduce);
self.par_fold_reduce_impl(identity, fold, reduce)
}
fn par_fold_reduce_impl<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, &mut D) -> T + Send + Sync,
R: Fn(T, T) -> T + Send + Sync,
{
let data = &self.data;
self.list.par_fold_reduce(
identity,
|a, i, n| {
fold(
a,
i,
n,
&mut data[i].try_lock().unwrap_or_else(|| panic!("data for `{i}` is already locked")),
)
},
reduce,
)
}
pub fn measure_each<F, S>(&mut self, wm: &mut WidgetMeasure, measure: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut D, &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 D, &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);
self.measure_each_impl(wm, measure, fold_size)
}
fn measure_each_impl<F, S>(&mut self, wm: &mut WidgetMeasure, measure: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut D, &mut WidgetMeasure) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
let data = &self.data;
self.list.measure_each(
wm,
|i, n, wm| {
measure(
i,
n,
&mut data[i].try_lock().unwrap_or_else(|| panic!("data for `{i}` is already locked")),
wm,
)
},
fold_size,
)
}
pub fn layout_each<F, S>(&mut self, wl: &mut WidgetLayout, layout: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut D, &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 D, &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);
self.layout_each_impl(wl, layout, fold_size)
}
fn layout_each_impl<F, S>(&mut self, wl: &mut WidgetLayout, layout: F, fold_size: S) -> PxSize
where
F: Fn(usize, &mut BoxedUiNode, &mut D, &mut WidgetLayout) -> PxSize + Send + Sync,
S: Fn(PxSize, PxSize) -> PxSize + Send + Sync,
{
let data = &self.data;
self.list.layout_each(
wl,
|i, n, wl| {
layout(
i,
n,
&mut data[i].try_lock().unwrap_or_else(|| panic!("data for `{i}` is already locked")),
wl,
)
},
fold_size,
)
}
pub fn for_each_z_sorted(&mut self, f: impl FnMut(usize, &mut BoxedUiNode, &mut D)) {
#[cfg(feature = "dyn_closure")]
let f: Box<dyn FnMut(usize, &mut BoxedUiNode, &mut D)> = Box::new(f);
self.for_each_z_sorted_impl(f)
}
fn for_each_z_sorted_impl(&mut self, mut f: impl FnMut(usize, &mut BoxedUiNode, &mut D)) {
if self.z_naturally_sorted {
self.for_each(f)
} else {
if self.z_map.len() != self.list.len() {
self.z_sort();
}
if self.z_naturally_sorted {
self.for_each(f);
} else {
for &index in self.z_map.iter() {
let index = index as usize;
let data = self.data[index].get_mut();
self.list.with_node(index, |node| f(index, node, data));
}
}
}
}
fn z_sort(&mut self) {
let len = self.list.len();
assert!(len <= u32::MAX as usize);
let mut prev_z = ZIndex::BACK;
let mut need_map = false;
let mut z_and_i = Vec::with_capacity(len);
let mut has_non_default_zs = false;
self.list.for_each(|i, node| {
let z = Z_INDEX.get_wgt(node);
z_and_i.push(((z.0 as u64) << 32) | i as u64);
need_map |= z < prev_z;
has_non_default_zs |= z != ZIndex::DEFAULT;
prev_z = z;
});
self.z_naturally_sorted = !need_map;
if need_map {
z_and_i.sort_unstable();
for z in &mut z_and_i {
*z &= u32::MAX as u64;
}
self.z_map = z_and_i;
} else {
self.z_map.clear();
}
}
pub fn z_map(&mut self, index: usize) -> usize {
if self.z_naturally_sorted {
return index;
}
if self.z_map.len() != self.list.len() {
self.z_sort();
}
if self.z_naturally_sorted {
return index;
}
self.z_map[index] as usize
}
pub fn data(&mut self, index: usize) -> &mut D {
self.data[index].get_mut()
}
pub fn commit_data(&mut self) -> PanelListDataChanges {
let mut changes = PanelListDataChanges::empty();
for data in self.data.iter_mut() {
changes |= data.get_mut().commit();
}
changes
}
pub fn offset_key(&self) -> FrameValueKey<PxTransform> {
self.offset_key
}
}
impl<D> UiNodeList for PanelList<D>
where
D: PanelListData,
{
fn with_node<R, F>(&mut self, index: usize, f: F) -> R
where
F: FnOnce(&mut BoxedUiNode) -> R,
{
self.list.with_node(index, f)
}
fn for_each<F>(&mut self, f: F)
where
F: FnMut(usize, &mut BoxedUiNode),
{
self.list.for_each(f)
}
fn par_each<F>(&mut self, f: F)
where
F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
{
self.list.par_each(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.list.par_fold_reduce(identity, fold, reduce)
}
fn len(&self) -> usize {
self.list.len()
}
fn boxed(self) -> BoxedUiNodeList {
Box::new(self)
}
fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
self.list.drain_into(vec);
self.data.clear();
self.z_map.clear();
self.z_naturally_sorted = true;
}
fn init_all(&mut self) {
self.z_map.clear();
let resort = Z_INDEX.with(WIDGET.id(), || self.list.init_all());
self.z_naturally_sorted = !resort;
self.data.resize_with(self.list.len(), Default::default);
}
fn deinit_all(&mut self) {
self.list.deinit_all();
}
fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
if self.list.is_empty() {
return;
}
self.list.info_all(info);
if let Some((id, version, pump_update)) = &mut self.info_id {
let start = self.list.with_node(0, |c| c.with_context(WidgetUpdateMode::Ignore, || WIDGET.id()));
let end = self
.list
.with_node(self.list.len() - 1, |c| c.with_context(WidgetUpdateMode::Ignore, || WIDGET.id()));
let range = match (start, end) {
(Some(s), Some(e)) => Some((s, e)),
_ => None,
};
info.set_meta(*id, PanelListRange { range, version: *version });
if mem::take(pump_update) {
self.list.for_each(|_, c| {
c.with_context(WidgetUpdateMode::Bubble, || WIDGET.update());
});
}
}
}
fn event_all(&mut self, update: &EventUpdate) {
self.list.event_all(update);
}
fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
let mut observer = PanelObserver {
changed: false,
data: &mut self.data,
observer,
};
let resort = Z_INDEX.with(WIDGET.id(), || self.list.update_all(updates, &mut observer));
let observer_changed = observer.changed;
if resort || (observer.changed && self.z_naturally_sorted) {
self.z_map.clear();
self.z_naturally_sorted = false;
WIDGET.render();
}
self.data.resize_with(self.list.len(), Default::default);
if observer_changed {
if let Some((_, v, u)) = &mut self.info_id {
if !*u {
*v = v.wrapping_add(1);
*u = true;
}
}
}
}
fn render_all(&mut self, frame: &mut FrameBuilder) {
let offset_key = self.offset_key;
if self.z_naturally_sorted && self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::RENDER) {
let b = self.par_fold_reduce(
|| frame.parallel_split(),
|mut frame, i, child, data| {
let offset = data.child_offset();
if data.define_reference_frame() {
frame.push_reference_frame(
(offset_key, i as u32).into(),
offset_key.bind_child(i as u32, offset.into(), false),
true,
true,
|frame| {
child.render(frame);
},
);
} else {
frame.push_child(offset, |frame| {
child.render(frame);
});
}
frame
},
|mut a, b| {
a.parallel_fold(b);
a
},
);
frame.parallel_fold(b);
} else {
self.for_each_z_sorted(|i, child, data| {
let offset = data.child_offset();
if data.define_reference_frame() {
frame.push_reference_frame(
(offset_key, i as u32).into(),
offset_key.bind_child(i as u32, offset.into(), false),
true,
true,
|frame| {
child.render(frame);
},
);
} else {
frame.push_child(offset, |frame| {
child.render(frame);
});
}
});
}
}
fn render_update_all(&mut self, update: &mut FrameUpdate) {
let offset_key = self.offset_key;
if self.len() > 1 && PARALLEL_VAR.get().contains(Parallel::RENDER) {
let b = self.par_fold_reduce(
|| update.parallel_split(),
|mut update, i, child, data| {
let offset = data.child_offset();
if data.define_reference_frame() {
update.with_transform(offset_key.update_child(i as u32, offset.into(), false), true, |update| {
child.render_update(update);
});
} else {
update.with_child(offset, |update| {
child.render_update(update);
});
}
update
},
|mut a, b| {
a.parallel_fold(b);
a
},
);
update.parallel_fold(b);
} else {
self.for_each(|i, child, data| {
let offset = data.child_offset();
if data.define_reference_frame() {
update.with_transform(offset_key.update_child(i as u32, offset.into(), false), true, |update| {
child.render_update(update);
});
} else {
update.with_child(offset, |update| {
child.render_update(update);
});
}
});
}
}
}
bitflags::bitflags! {
#[must_use = "|= with other item changes, call request_render"]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct PanelListDataChanges: u8 {
const CHILD_OFFSET = 0b01;
const DEFINE_REFERENCE_FRAME = 0b10;
}
}
impl PanelListDataChanges {
pub fn request_render(self) {
if self.contains(Self::DEFINE_REFERENCE_FRAME) {
WIDGET.render();
} else if self.contains(Self::CHILD_OFFSET) {
WIDGET.render_update();
}
}
}
#[derive(Clone, Debug, Default)]
pub struct DefaultPanelListData {
pub child_offset: PxVector,
pub define_reference_frame: bool,
prev_child_offset: PxVector,
prev_define_reference_frame: bool,
}
impl PanelListData for DefaultPanelListData {
fn child_offset(&self) -> PxVector {
self.child_offset
}
fn define_reference_frame(&self) -> bool {
self.define_reference_frame
}
fn commit(&mut self) -> PanelListDataChanges {
let mut changes = PanelListDataChanges::empty();
if self.define_reference_frame != self.prev_define_reference_frame {
changes |= PanelListDataChanges::DEFINE_REFERENCE_FRAME;
}
if self.child_offset != self.prev_child_offset {
changes |= PanelListDataChanges::CHILD_OFFSET;
}
self.prev_define_reference_frame = self.define_reference_frame;
self.prev_child_offset = self.child_offset;
changes
}
}
pub trait PanelListData: Default + Send + Any {
fn child_offset(&self) -> PxVector;
fn define_reference_frame(&self) -> bool;
fn commit(&mut self) -> PanelListDataChanges;
}
impl PanelListData for () {
fn child_offset(&self) -> PxVector {
PxVector::zero()
}
fn define_reference_frame(&self) -> bool {
false
}
fn commit(&mut self) -> PanelListDataChanges {
PanelListDataChanges::empty()
}
}
struct PanelObserver<'d, D>
where
D: PanelListData,
{
changed: bool,
data: &'d mut Vec<Mutex<D>>,
observer: &'d mut dyn UiNodeListObserver,
}
impl<'d, D> UiNodeListObserver for PanelObserver<'d, D>
where
D: PanelListData,
{
fn is_reset_only(&self) -> bool {
false
}
fn reset(&mut self) {
self.changed = true;
self.data.clear();
self.observer.reset();
}
fn inserted(&mut self, index: usize) {
self.changed = true;
self.data.insert(index, Default::default());
self.observer.inserted(index);
}
fn removed(&mut self, index: usize) {
self.changed = true;
self.data.remove(index);
self.observer.removed(index);
}
fn moved(&mut self, removed_index: usize, inserted_index: usize) {
self.changed = true;
let item = self.data.remove(removed_index);
self.data.insert(inserted_index, item);
self.observer.moved(removed_index, inserted_index);
}
}