zng-app 0.22.4

Part of the zng project.
Documentation
use std::ops::ControlFlow;

use zng_layout::unit::PxSize;
use zng_var::BoxAnyVarValue;

use crate::{
    render::{FrameBuilder, FrameUpdate},
    update::WidgetUpdates,
    widget::{
        WidgetUpdateMode,
        info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
        node::{UiNode, UiNodeImpl, UiNodeMethod},
    },
};

use super::UiNodeListObserver;

pub(super) struct TraceNode {
    node: UiNode,
    trace: Box<dyn FnMut(&mut dyn UiNodeImpl, UiNodeMethod, &mut dyn FnMut(&mut dyn UiNodeImpl)) + Send + 'static>,
}
impl TraceNode {
    pub(super) fn new<S>(node: UiNode, mut enter_mtd: impl FnMut(UiNodeMethod) -> S + Send + 'static) -> Self {
        Self {
            node,
            trace: Box::new(move |node, op, call| {
                let _span = if let Some(w) = node.as_widget() {
                    let mut s = None;
                    w.with_context(WidgetUpdateMode::Bubble, &mut || s = Some(enter_mtd(op)));
                    match s {
                        Some(s) => s,
                        None => enter_mtd(op),
                    }
                } else {
                    enter_mtd(op)
                };

                call(node);

                if let Some(w) = node.as_widget() {
                    let mut _span = Some(_span);
                    w.with_context(WidgetUpdateMode::Bubble, &mut || drop(_span.take()));
                }
            }),
        }
    }
}
impl UiNodeImpl for TraceNode {
    fn children_len(&self) -> usize {
        self.node.children_len()
    }

    fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
        self.node.0.with_child(index, visitor)
    }

    fn is_list(&self) -> bool {
        self.node.0.is_list()
    }

    fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
        self.node.0.for_each_child(visitor);
    }

    fn try_for_each_child(
        &mut self,
        visitor: &mut dyn FnMut(usize, &mut UiNode) -> ControlFlow<BoxAnyVarValue>,
    ) -> ControlFlow<BoxAnyVarValue> {
        self.node.0.try_for_each_child(visitor)
    }

    fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
        self.node.0.par_each_child(visitor);
    }

    fn par_fold_reduce(
        &mut self,
        identity: BoxAnyVarValue,
        fold: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
        reduce: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
    ) -> BoxAnyVarValue {
        self.node.0.par_fold_reduce(identity, fold, reduce)
    }

    fn init(&mut self) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::Init, &mut |n| n.init())
    }

    fn deinit(&mut self) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::Deinit, &mut |n| n.deinit())
    }

    fn info(&mut self, info: &mut WidgetInfoBuilder) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::Info, &mut |n| n.info(info))
    }

    fn update(&mut self, updates: &WidgetUpdates) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::Update, &mut |n| n.update(updates))
    }

    fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::UpdateList, &mut |n| {
            n.update_list(updates, observer)
        })
    }

    fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
        let mut out = PxSize::zero();
        (self.trace)(self.node.as_dyn(), UiNodeMethod::Measure, &mut |n| out = n.measure(wm));
        out
    }

    fn measure_list(
        &mut self,
        wm: &mut WidgetMeasure,
        measure: &(dyn Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync),
        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
    ) -> PxSize {
        let mut out = PxSize::zero();
        (self.trace)(self.node.as_dyn(), UiNodeMethod::MeasureList, &mut |n| {
            out = n.measure_list(wm, measure, fold_size)
        });
        out
    }

    fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
        let mut out = PxSize::zero();
        (self.trace)(self.node.as_dyn(), UiNodeMethod::Layout, &mut |n| out = n.layout(wl));
        out
    }

    fn layout_list(
        &mut self,
        wl: &mut WidgetLayout,
        layout: &(dyn Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync),
        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
    ) -> PxSize {
        let mut out = PxSize::zero();
        (self.trace)(self.node.as_dyn(), UiNodeMethod::LayoutList, &mut |n| {
            out = n.layout_list(wl, layout, fold_size)
        });
        out
    }

    fn render(&mut self, frame: &mut FrameBuilder) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::Render, &mut |n| n.render(frame))
    }

    fn render_list(&mut self, frame: &mut FrameBuilder, render: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::RenderList, &mut |n| n.render_list(frame, render))
    }

    fn render_update(&mut self, update: &mut FrameUpdate) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::RenderUpdate, &mut |n| n.render_update(update))
    }

    fn render_update_list(&mut self, update: &mut FrameUpdate, render_update: &(dyn Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync)) {
        (self.trace)(self.node.as_dyn(), UiNodeMethod::RenderUpdateList, &mut |n| {
            n.render_update_list(update, render_update)
        })
    }

    fn as_widget(&mut self) -> Option<&mut dyn super::WidgetUiNodeImpl> {
        self.node.0.as_widget()
    }
}