Skip to main content

cranpose_ui/modifier/
layout_data.rs

1use std::{
2    hash::{Hash, Hasher},
3    rc::Rc,
4};
5
6use cranpose_foundation::{
7    DelegatableNode, InvalidationKind, ModifierNode, ModifierNodeContext, ModifierNodeElement,
8    NodeCapabilities, NodeState,
9};
10use cranpose_ui_layout::LayoutData;
11
12use super::{Modifier, inspector_metadata};
13
14impl Modifier {
15    /// Gives the parent layout `data`, which its measure policy reads with
16    /// [`cranpose_ui_layout::ParentData::layout_data`]. When a chain has more
17    /// than one, the parent sees the first. Compose's `ParentDataModifier`.
18    pub fn layout_data(self, data: impl LayoutData) -> Self {
19        let data: Rc<dyn LayoutData> = Rc::new(data);
20        let inspected = Rc::clone(&data);
21        let modifier = Self::with_element(LayoutDataElement { data }).with_inspector_metadata(
22            inspector_metadata("layoutData", move |info| {
23                info.add_property("data", format!("{inspected:?}"));
24            }),
25        );
26        self.then(modifier)
27    }
28}
29
30/// Holds the [`LayoutData`] that the chain gives the parent.
31#[derive(Debug)]
32pub(crate) struct LayoutDataNode {
33    data: Rc<dyn LayoutData>,
34    state: NodeState,
35}
36
37impl LayoutDataNode {
38    pub(crate) fn data(&self) -> &Rc<dyn LayoutData> {
39        &self.data
40    }
41}
42
43impl DelegatableNode for LayoutDataNode {
44    fn node_state(&self) -> &NodeState {
45        &self.state
46    }
47}
48
49impl ModifierNode for LayoutDataNode {
50    fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
51        context.invalidate(InvalidationKind::Layout);
52    }
53}
54
55#[derive(Debug)]
56struct LayoutDataElement {
57    data: Rc<dyn LayoutData>,
58}
59
60impl PartialEq for LayoutDataElement {
61    fn eq(&self, other: &Self) -> bool {
62        self.data.same_as(&*other.data)
63    }
64}
65
66impl Hash for LayoutDataElement {
67    /// Equal data has the same type, so the type is a hash equal elements share.
68    fn hash<H: Hasher>(&self, state: &mut H) {
69        self.data.as_any().type_id().hash(state);
70    }
71}
72
73impl ModifierNodeElement for LayoutDataElement {
74    type Node = LayoutDataNode;
75
76    fn create(&self) -> Self::Node {
77        LayoutDataNode {
78            data: Rc::clone(&self.data),
79            state: NodeState::new(),
80        }
81    }
82
83    fn update(&self, node: &mut Self::Node) {
84        if !node.data.same_as(&*self.data) {
85            node.data = Rc::clone(&self.data);
86        }
87    }
88
89    fn capabilities(&self) -> NodeCapabilities {
90        NodeCapabilities::LAYOUT
91    }
92}