hydrolysis 0.3.0

GPU-required self-drawn backend for WaterUI
//! Native-leaf measurement: the `HydroNativeView` measure trait, the native-view
//! type list, and the measure-path entry points the layout system uses to size
//! arbitrary sub-views.

use super::*;
use crate::engine::WidgetTheme;
use std::rc::Rc;

/// The measure half of a native leaf view. Rendering is owned by the retained
/// [`RenderNode`](crate::renderer::tree::RenderNode) tree; this trait only sizes a
/// leaf so the layout system can measure arbitrary sub-views through it.
pub(crate) trait HydroNativeView: View + Sized + 'static {
    fn intrinsic(
        state: &mut HydroState,
        view: &Self,
        env: &Environment,
        theme: &Rc<dyn WidgetTheme>,
    ) -> LayoutSize;
    fn dimensions(
        state: &mut HydroState,
        view: &Self,
        env: &Environment,
        theme: &Rc<dyn WidgetTheme>,
        _proposal: ProposalSize,
    ) -> ViewDimensions {
        ViewDimensions::new(Self::intrinsic(state, view, env, theme))
    }
}

pub(crate) fn unsupported_system_icon(icon: &SystemIcon) -> ! {
    panic!(
        "SystemIcon `{}` is unsupported on Hydrolysis because self-drawn backends have no \
         OS-supplied icon catalog; use a packaged WaterUI icon crate",
        icon.name.as_str()
    )
}

impl HydroNativeView for Native<SystemIcon> {
    fn intrinsic(
        _state: &mut HydroState,
        view: &Self,
        _env: &Environment,
        _theme: &Rc<dyn WidgetTheme>,
    ) -> LayoutSize {
        unsupported_system_icon(view.as_inner())
    }
}

/// Reaching `Native<MapConfig>` means `Map::body` found no `Hook<MapConfig>` —
/// no map realization was installed — and this backend ships no map engine of
/// its own.
pub(crate) fn unsupported_map() -> ! {
    panic!(
        "Map is unsupported on Hydrolysis because the backend has no map engine; install a \
         map realization such as `waterui_map_gpu::install` before rendering a `Map`"
    )
}

impl HydroNativeView for Native<MapConfig> {
    fn intrinsic(
        _state: &mut HydroState,
        _view: &Self,
        _env: &Environment,
        _theme: &Rc<dyn WidgetTheme>,
    ) -> LayoutSize {
        unsupported_map()
    }
}

/// Reaching `WebView` on a build without `hydrolysis_macos_system_webview`
/// means neither a `Hook<WebView>` engine realization nor the platform bridge
/// is present — the backend has nothing to draw a page with.
#[cfg(not(hydrolysis_macos_system_webview))]
pub(crate) fn unsupported_webview() -> ! {
    panic!(
        "WebView is unsupported on this Hydrolysis build because no web engine is bridged; \
         link a browser engine crate (`waterui-browser-cef`, `waterui-browser-wpe`) or enable \
         the `webview-system` and `winit` features on macOS"
    )
}

pub(crate) fn dimensions_for_native<V: HydroNativeView>(
    view: &AnyView,
    proposal: ProposalSize,
    state: &mut HydroState,
    env: &Environment,
    theme: &Rc<dyn WidgetTheme>,
) -> Option<ViewDimensions> {
    view.downcast_ref::<V>()
        .map(|native| V::dimensions(state, native, env, theme, proposal))
}

macro_rules! hydro_native_view_types {
    ($macro:ident) => {
        $macro!(Native<()>);
        $macro!(Native<Spacer>);
        $macro!(Native<TextConfig>);
        $macro!(Native<FixedContainer>);
        $macro!(Native<LazyContainer>);
        $macro!(Native<ScrollView>);
        $macro!(Native<NavigationView>);
        $macro!(Native<NavigationSplitLayout>);
        $macro!(Native<NavigationStack<(), ()>>);
        $macro!(Native<TabsLayout>);
        $macro!(Native<BadgeConfig>);
        $macro!(Native<ListConfig>);
        $macro!(Native<TableConfig>);
        $macro!(Native<ButtonConfig>);
        $macro!(Native<ResolvedMenu>);
        $macro!(Native<ToggleConfig>);
        $macro!(Native<SliderConfig>);
        $macro!(Native<StepperConfig>);
        $macro!(Native<ProgressConfig>);
        $macro!(Native<ColorPickerConfig>);
        $macro!(Native<DatePickerConfig>);
        $macro!(Native<ResolvedTextFieldConfig>);
        $macro!(Native<SecureFieldConfig>);
        $macro!(Native<PickerConfig>);
        $macro!(Native<Dynamic>);
        $macro!(Native<SystemIcon>);
        $macro!(Native<GpuSurface>);
        $macro!(Native<SceneView>);
        $macro!(Native<ViewEffectErased>);
        $macro!(Native<Color>);
        $macro!(Native<ResolvedColor>);
        $macro!(Native<ResolvedGradient>);
        $macro!(Native<ResolvedShape>);
        $macro!(Native<ResolvedMorphShape>);
        $macro!(Native<MapConfig>);
        $macro!(WebView);
    };
}

pub(crate) fn is_hydro_native_view(view: &AnyView) -> bool {
    macro_rules! check_native_view {
        ($ty:ty) => {
            if view.downcast_ref::<$ty>().is_some() {
                return true;
            }
        };
    }
    hydro_native_view_types!(check_native_view);
    false
}

pub(crate) fn dimensions_for_known_native_views(
    view: &AnyView,
    proposal: ProposalSize,
    state: &mut HydroState,
    env: &Environment,
    theme: &Rc<dyn WidgetTheme>,
) -> Option<ViewDimensions> {
    macro_rules! try_native_dimensions {
        ($ty:ty) => {
            if let Some(dimensions) =
                dimensions_for_native::<$ty>(view, proposal, state, env, theme)
            {
                return Some(dimensions);
            }
        };
    }
    hydro_native_view_types!(try_native_dimensions);
    None
}