hydrolysis 0.3.0

GPU-required self-drawn backend for WaterUI
use crate::renderer::{
    HydroNativeView, HydroState, measure_view_dimensions, measure_view_dimensions_with_proposal,
    normalize_layout_view,
};
use std::rc::Rc;
use waterui_core::dynamic::Dynamic;
use waterui_core::layout::{ProposalSize, Size as LayoutSize, ViewDimensions};
use waterui_core::{Environment, Native};

/// Measures a `Dynamic` node's current content if the node still owns it, or
/// falls back to the renderer's per-node dimension caches when the content has
/// already been handed to the render pipeline.
fn measure_dynamic(
    state: &mut HydroState,
    dynamic: &Dynamic,
    env: &Environment,
    proposal: ProposalSize,
    theme: &Rc<dyn crate::engine::WidgetTheme>,
) -> ViewDimensions {
    let identity = dynamic.identity();
    state
        .measurement
        .begin_dynamic_measurement(identity, proposal);
    let measure_content = |slot: &mut Option<waterui_core::AnyView>, state: &mut HydroState| {
        slot.take().map(|content| {
            let normalized = normalize_layout_view(content, env);
            let dimensions = if proposal == ProposalSize::UNSPECIFIED {
                measure_view_dimensions(&normalized, state, env, theme)
            } else {
                measure_view_dimensions_with_proposal(&normalized, proposal, state, env, theme)
            };
            *slot = Some(normalized);
            dimensions
        })
    };
    let initial = dynamic.with_unconnected_view_mut(|slot| measure_content(slot, state));
    let dimensions = match initial {
        Some(Some(dimensions)) => dimensions,
        Some(None) => {
            panic!("hydrolysis Dynamic measurement requires an initial view before layout")
        }
        None => {
            match dynamic.with_connected_pending_view_mut(|slot| measure_content(slot, state)) {
                Some(Some(dimensions)) => dimensions,
                Some(None) | None => state
                    .measurement
                    .dynamic_dimensions(identity, proposal)
                    .or_else(|| state.measurement.dynamic_intrinsic(identity))
                    .unwrap_or_else(|| {
                        panic!("hydrolysis Dynamic intrinsic cache miss for connected dynamic node")
                    }),
            }
        }
    };
    state
        .measurement
        .store_dynamic_dimensions(identity, proposal, dimensions.clone());
    state
        .measurement
        .finish_dynamic_measurement(identity, "after dynamic measurement");
    dimensions
}

impl HydroNativeView for Native<Dynamic> {
    fn intrinsic(
        state: &mut HydroState,
        view: &Self,
        env: &Environment,
        theme: &Rc<dyn crate::engine::WidgetTheme>,
    ) -> LayoutSize {
        measure_dynamic(
            state,
            view.as_inner(),
            env,
            ProposalSize::UNSPECIFIED,
            theme,
        )
        .size
    }

    fn dimensions(
        state: &mut HydroState,
        view: &Self,
        env: &Environment,
        theme: &Rc<dyn crate::engine::WidgetTheme>,
        proposal: ProposalSize,
    ) -> ViewDimensions {
        measure_dynamic(state, view.as_inner(), env, proposal, theme)
    }
}