telar-ui-core 0.1.1

Widget kernel for Telar: containers, text, input handling, scrolling and canvas primitives.
Documentation
use geometry_core::Rect;
use layout_core::{LayoutError, LayoutStyle, NodeId};
use reactive_core::RwSignal;
use ui_tree::{NodeVec, RenderNode};

use crate::context;

pub struct LayoutLeaf {
    pub node: NodeId,
    pub rect: RwSignal<Rect>,
}

impl LayoutLeaf {
    pub fn register(layout_style: LayoutStyle) -> Result<Self, LayoutError> {
        let (node, rect) = context::new_leaf(layout_style)?;
        Ok(Self { node, rect })
    }

    pub(crate) fn at_layout_position(&self, content: RenderNode) -> RenderNode {
        let r = self.rect.get();
        RenderNode::Transform {
            matrix: [1.0, 0.0, 0.0, 1.0, r.x, r.y],
            children: NodeVec::collect([content]),
        }
    }
}

/// Resolves the `auto` sides of a media leaf (img/svg) against an intrinsic size: both auto → the
/// intrinsic size; one auto with the other a px length → derive the auto side from the intrinsic
/// aspect ratio; a percent side is left untouched. `intrinsic` is only evaluated when needed.
pub(crate) fn resolve_intrinsic_size(
    style: LayoutStyle,
    intrinsic: impl FnOnce() -> (f32, f32),
) -> LayoutStyle {
    match (style.is_width_auto(), style.is_height_auto()) {
        (true, true) => {
            let (iw, ih) = intrinsic();
            style.width(iw).height(ih)
        }
        (true, false) => match style.height_px() {
            Some(h) => {
                let (iw, ih) = intrinsic();
                if ih > 0.0 {
                    style.width(h * iw / ih)
                } else {
                    style
                }
            }
            None => style,
        },
        (false, true) => match style.width_px() {
            Some(w) => {
                let (iw, ih) = intrinsic();
                if iw > 0.0 {
                    style.height(w * ih / iw)
                } else {
                    style
                }
            }
            None => style,
        },
        (false, false) => style,
    }
}