@@ -628,6 +628,11 @@ pub enum TextDecoration {
628628pub type NodeIdContent = u64 ;
629629
630630/// The stable identity of a [`Node`], unique within the node's tree.
631+ ///
632+ /// Each tree (root or subtree) has its own independent ID space. The same
633+ /// `NodeId` value can exist in different trees without conflict. When working
634+ /// with multiple trees, the combination of `NodeId` and [`TreeId`] uniquely
635+ /// identifies a node.
631636#[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
632637#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
633638#[ cfg_attr( feature = "schemars" , derive( JsonSchema ) ) ]
@@ -778,6 +783,7 @@ enum PropertyValue {
778783 Rect ( Rect ) ,
779784 TextSelection ( Box < TextSelection > ) ,
780785 CustomActionVec ( Vec < CustomAction > ) ,
786+ TreeId ( TreeId ) ,
781787}
782788
783789#[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
@@ -894,6 +900,7 @@ enum PropertyId {
894900 Bounds ,
895901 TextSelection ,
896902 CustomActions ,
903+ TreeId ,
897904
898905 // This MUST be last.
899906 Unset ,
@@ -1695,7 +1702,8 @@ copy_type_getters! {
16951702 ( get_usize_property, usize , Usize ) ,
16961703 ( get_color_property, u32 , Color ) ,
16971704 ( get_text_decoration_property, TextDecoration , TextDecoration ) ,
1698- ( get_bool_property, bool , Bool )
1705+ ( get_bool_property, bool , Bool ) ,
1706+ ( get_tree_id_property, TreeId , TreeId )
16991707}
17001708
17011709box_type_setters ! {
@@ -1713,7 +1721,8 @@ copy_type_setters! {
17131721 ( set_usize_property, usize , Usize ) ,
17141722 ( set_color_property, u32 , Color ) ,
17151723 ( set_text_decoration_property, TextDecoration , TextDecoration ) ,
1716- ( set_bool_property, bool , Bool )
1724+ ( set_bool_property, bool , Bool ) ,
1725+ ( set_tree_id_property, TreeId , TreeId )
17171726}
17181727
17191728vec_type_methods ! {
@@ -2014,11 +2023,20 @@ property_methods! {
20142023 /// [`transform`]: Node::transform
20152024 ( Bounds , bounds, get_rect_property, Option <Rect >, set_bounds, set_rect_property, Rect , clear_bounds) ,
20162025
2017- ( TextSelection , text_selection, get_text_selection_property, Option <& TextSelection >, set_text_selection, set_text_selection_property, impl Into <Box <TextSelection >>, clear_text_selection)
2026+ ( TextSelection , text_selection, get_text_selection_property, Option <& TextSelection >, set_text_selection, set_text_selection_property, impl Into <Box <TextSelection >>, clear_text_selection) ,
2027+
2028+ /// The tree that this node grafts. When set, this node acts as a graft
2029+ /// point, and its child is the root of the specified subtree.
2030+ ///
2031+ /// A graft node must be created before its subtree is pushed.
2032+ ///
2033+ /// Removing a graft node or clearing this property removes its subtree,
2034+ /// unless a new graft node is provided in the same update.
2035+ ( TreeId , tree_id, get_tree_id_property, Option <TreeId >, set_tree_id, set_tree_id_property, TreeId , clear_tree_id)
20182036}
20192037
20202038impl Node {
2021- option_properties_debug_method ! { debug_option_properties, [ transform, bounds, text_selection, ] }
2039+ option_properties_debug_method ! { debug_option_properties, [ transform, bounds, text_selection, tree_id , ] }
20222040}
20232041
20242042#[ cfg( test) ]
@@ -2123,6 +2141,31 @@ mod text_selection {
21232141 }
21242142}
21252143
2144+ #[ cfg( test) ]
2145+ mod tree_id {
2146+ use super :: { Node , Role , TreeId , Uuid } ;
2147+
2148+ #[ test]
2149+ fn getter_should_return_default_value ( ) {
2150+ let node = Node :: new ( Role :: GenericContainer ) ;
2151+ assert ! ( node. tree_id( ) . is_none( ) ) ;
2152+ }
2153+ #[ test]
2154+ fn setter_should_update_the_property ( ) {
2155+ let mut node = Node :: new ( Role :: GenericContainer ) ;
2156+ let value = TreeId ( Uuid :: nil ( ) ) ;
2157+ node. set_tree_id ( value) ;
2158+ assert_eq ! ( node. tree_id( ) , Some ( value) ) ;
2159+ }
2160+ #[ test]
2161+ fn clearer_should_reset_the_property ( ) {
2162+ let mut node = Node :: new ( Role :: GenericContainer ) ;
2163+ node. set_tree_id ( TreeId ( Uuid :: nil ( ) ) ) ;
2164+ node. clear_tree_id ( ) ;
2165+ assert ! ( node. tree_id( ) . is_none( ) ) ;
2166+ }
2167+ }
2168+
21262169vec_property_methods ! {
21272170 ( CustomActions , CustomAction , custom_actions, get_custom_action_vec, set_custom_actions, set_custom_action_vec, push_custom_action, push_to_custom_action_vec, clear_custom_actions)
21282171}
@@ -2291,7 +2334,8 @@ impl Serialize for Properties {
22912334 Affine ,
22922335 Rect ,
22932336 TextSelection ,
2294- CustomActionVec
2337+ CustomActionVec ,
2338+ TreeId
22952339 } ) ;
22962340 }
22972341 map. end ( )
@@ -2421,7 +2465,8 @@ impl<'de> Visitor<'de> for PropertiesVisitor {
24212465 Affine { Transform } ,
24222466 Rect { Bounds } ,
24232467 TextSelection { TextSelection } ,
2424- CustomActionVec { CustomActions }
2468+ CustomActionVec { CustomActions } ,
2469+ TreeId { TreeId }
24252470 } ) ;
24262471 }
24272472
@@ -2651,14 +2696,26 @@ pub struct TreeUpdate {
26512696 /// a tree.
26522697 pub tree : Option < Tree > ,
26532698
2654- /// The identifier of the tree.
2699+ /// The identifier of the tree that this update applies to.
2700+ ///
2701+ /// Use [`TreeId::ROOT`] for the main/root tree. For subtrees, use a unique
2702+ /// [`TreeId`] that identifies the subtree.
2703+ ///
2704+ /// When updating a subtree (non-ROOT tree_id):
2705+ /// - A graft node with [`Node::tree_id`] set to this tree's ID must already
2706+ /// exist in the parent tree before the first subtree update.
2707+ /// - The first update for a subtree must include [`tree`](Self::tree) data.
26552708 pub tree_id : TreeId ,
26562709
26572710 /// The node within this tree that has keyboard focus when the native
26582711 /// host (e.g. window) has focus. If no specific node within the tree
26592712 /// has keyboard focus, this must be set to the root. The latest focus state
26602713 /// must be provided with every tree update, even if the focus state
26612714 /// didn't change in a given update.
2715+ ///
2716+ /// For subtrees, this specifies which node has focus when the subtree
2717+ /// itself is focused (i.e., when focus is on the graft node in the parent
2718+ /// tree).
26622719 pub focus : NodeId ,
26632720}
26642721
0 commit comments