cranpose 0.1.148

Cranpose runtime and UI facade
Documentation
use std::{cell::Cell, rc::Rc};

use cranpose_foundation::{
    Constraints, DelegatableNode, LayoutModifierNode, Measurable, ModifierNode,
    ModifierNodeContext, ModifierNodeElement, NodeCapabilities, NodeState,
};
use cranpose_ui::{Modifier, Size, WindowRootDescriptor, WindowRootNode};
use cranpose_ui_layout::LayoutModifierMeasureResult;

use crate::native_window::{
    NativeWindowOwner, NativeWindowParts, NativeWindowRoot, WindowConfig, WindowId,
    register_native_window, unregister_native_window,
};

pub(crate) fn window(modifier: Modifier, config: WindowConfig) -> Modifier {
    modifier.then(Modifier::with_element(NativeWindowElement { config }))
}

#[derive(Debug, PartialEq)]
pub(crate) struct NativeWindowElement {
    config: WindowConfig,
}

impl std::hash::Hash for NativeWindowElement {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.config.title().hash(state);
    }
}

impl ModifierNodeElement for NativeWindowElement {
    type Node = NativeWindowNode;

    fn create(&self) -> NativeWindowNode {
        let parts = self.config.clone().into_parts();
        let surface = Rc::new(NativeWindowRoot::new(Size::new(
            parts.options.width,
            parts.options.height,
        )));
        let descriptor: Rc<dyn WindowRootDescriptor> = surface.clone();
        NativeWindowNode {
            root: WindowRootNode::new(descriptor),
            surface,
            parts,
            key: Cell::new(None),
            owner: Rc::new(()),
        }
    }

    fn update(&self, node: &mut NativeWindowNode) {
        node.parts = self.config.clone().into_parts();
        node.register();
    }

    fn always_update(&self) -> bool {
        true
    }

    fn auto_invalidate_on_update(&self) -> bool {
        false
    }

    fn capabilities(&self) -> NodeCapabilities {
        NodeCapabilities::LAYOUT | NodeCapabilities::WINDOW_ROOT
    }

    fn inspector_name(&self) -> &'static str {
        "window"
    }
}

pub(crate) struct NativeWindowNode {
    root: WindowRootNode,
    surface: Rc<NativeWindowRoot>,
    parts: NativeWindowParts,
    key: Cell<Option<WindowId>>,
    owner: NativeWindowOwner,
}

impl NativeWindowNode {
    fn register(&self) {
        let Some(key) = self.key.get() else {
            return;
        };
        register_native_window(
            key,
            self.parts.options.clone(),
            self.parts.events.clone(),
            self.parts.state,
            Rc::clone(&self.surface),
            Rc::clone(&self.owner),
        );
    }
}

impl DelegatableNode for NativeWindowNode {
    fn node_state(&self) -> &NodeState {
        self.root.node_state()
    }
}

impl ModifierNode for NativeWindowNode {
    fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
        self.root.on_attach(context);
        let Some(node) = context.node_id() else {
            log::error!("window modifier attached to a node without an id; no window requested");
            return;
        };
        self.key.set(Some(WindowId::from_node(node)));
        self.register();
    }

    fn on_detach(&mut self) {
        self.root.on_detach();
        if let Some(key) = self.key.take() {
            unregister_native_window(key, Rc::clone(&self.owner));
        }
    }

    fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
        Some(self)
    }

    fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
        Some(self)
    }
}

impl LayoutModifierNode for NativeWindowNode {
    fn measure(
        &self,
        context: &mut dyn ModifierNodeContext,
        measurable: &dyn Measurable,
        constraints: Constraints,
    ) -> LayoutModifierMeasureResult {
        self.root.measure(context, measurable, constraints)
    }

    fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
        self.root.min_intrinsic_width(measurable, height)
    }

    fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
        self.root.max_intrinsic_width(measurable, height)
    }

    fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
        self.root.min_intrinsic_height(measurable, width)
    }

    fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
        self.root.max_intrinsic_height(measurable, width)
    }
}