Skip to main content

ohos_arkui_binding/common/
node.rs

1//! Module common::node wrappers and related types.
2
3#[cfg(feature = "napi")]
4use napi_ohos::bindgen_prelude::{check_status, FromNapiValue, TypeName, ValidateNapiValue};
5#[cfg(feature = "napi")]
6use napi_sys_ohos as sys;
7use ohos_arkui_input_binding::{sys::ArkUI_NodeHandle, ArkUIErrorCode};
8use ohos_arkui_sys::{
9    ArkUI_IntOffset, ArkUI_IntSize, OH_ArkUI_GetContextByNode,
10    OH_ArkUI_NodeUtils_GetLayoutPositionInWindow, OH_ArkUI_NodeUtils_GetLayoutSize,
11    OH_ArkUI_NodeUtils_GetPositionWithTranslateInWindow,
12};
13
14#[cfg(feature = "napi")]
15use ohos_arkui_sys::OH_ArkUI_GetNodeHandleFromNapiValue;
16#[cfg(feature = "napi")]
17use std::ptr;
18
19use std::{cell::RefCell, rc::Rc};
20
21use crate::{
22    animate::options::Animation,
23    api::node_custom_event::{IntOffset, IntSize},
24    api::ARK_UI_NATIVE_ANIMATE_API_1,
25    check_arkui_status, ArkUIAttributeBasic, ArkUICommonAttribute, ArkUIError, ArkUINodeType,
26    EventHandle, NodeDirtyFlag, ARK_UI_NATIVE_NODE_API_1,
27};
28
29use super::ArkUIResult;
30
31#[derive(Clone)]
32/// High-level ArkUI node wrapper used by component APIs.
33pub struct ArkUINode {
34    /// Underlying native ArkUI node handle.
35    pub(crate) raw: ArkUI_NodeHandle,
36    /// Node type tag.
37    pub(crate) tag: ArkUINodeType,
38    /// Child nodes owned by this node in wrapper layer.
39    pub(crate) children: Vec<Rc<RefCell<ArkUINode>>>,
40    /// Event callbacks bound to this node.
41    pub(crate) event_handle: EventHandle,
42}
43
44impl ArkUINode {
45    /// Returns the native ArkUI node handle.
46    pub fn raw_handle(&self) -> ArkUI_NodeHandle {
47        self.raw
48    }
49
50    /// Immutable children view.
51    pub fn children(&self) -> &[Rc<RefCell<ArkUINode>>] {
52        self.children.as_slice()
53    }
54
55    /// Mutable children view.
56    pub fn children_mut(&mut self) -> &mut Vec<Rc<RefCell<ArkUINode>>> {
57        self.children.as_mut()
58    }
59
60    pub(crate) fn raw(&self) -> ArkUI_NodeHandle {
61        self.raw
62    }
63
64    pub fn from_raw_handle(raw: ArkUI_NodeHandle) -> Option<Self> {
65        if raw.is_null() {
66            return None;
67        }
68
69        Some(Self {
70            raw,
71            tag: ArkUINodeType::Custom,
72            children: vec![],
73            event_handle: Default::default(),
74        })
75    }
76
77    #[cfg(all(feature = "api-22", feature = "drawing"))]
78    pub fn text_layout_manager(&self) -> ArkUIResult<Option<crate::TextLayoutManager>> {
79        match self.get_attribute(crate::ArkUINodeAttributeType::TextLayoutManager)? {
80            crate::ArkUINodeAttributeItem::Object(ptr) => {
81                Ok(Some(crate::TextLayoutManager::from_raw(ptr.cast())))
82            }
83            _ => Ok(None),
84        }
85    }
86
87    /// Clear dom
88    /// We can't use drop impl, because it will be called when the object is dropped.
89    pub fn dispose(&mut self) -> ArkUIResult<()> {
90        let handle = &self.event_handle;
91        if handle.has_callback() {
92            ARK_UI_NATIVE_NODE_API_1.with(|api| api.remove_event_receiver(self))?;
93        }
94        // `disposeNode` tears down the native subtree. Disposing wrapper children again will
95        // double free the descendant handles during patch/remount flows.
96        ARK_UI_NATIVE_NODE_API_1.with(|api| api.dispose(self))?;
97        self.children.clear();
98        Ok(())
99    }
100
101    /// Runs an explicit ArkUI animation update against this node.
102    pub fn animate_to(&self, animation: &Animation) -> ArkUIResult<()> {
103        let context = unsafe { OH_ArkUI_GetContextByNode(self.raw()) };
104        if context.is_null() {
105            return Err(ArkUIError::new(
106                ArkUIErrorCode::ParamInvalid,
107                "OH_ArkUI_GetContextByNode returned null",
108            ));
109        }
110
111        let update_ctx_raw = animation.update_ctx.borrow().raw();
112        let finish_ctx_raw = animation.finish_ctx.borrow().raw();
113        ARK_UI_NATIVE_ANIMATE_API_1
114            .with(|api| api.animate_to(context, animation.raw(), update_ctx_raw, finish_ctx_raw))
115    }
116
117    /// Returns the layout size measured for this node.
118    pub fn layout_size(&self) -> ArkUIResult<IntSize> {
119        let mut size: ArkUI_IntSize = unsafe { std::mem::zeroed() };
120        unsafe { check_arkui_status!(OH_ArkUI_NodeUtils_GetLayoutSize(self.raw(), &mut size)) }?;
121        Ok(size.into())
122    }
123
124    /// Returns this node's layout position in the current window.
125    pub fn layout_position_in_window(&self) -> ArkUIResult<IntOffset> {
126        let mut offset: ArkUI_IntOffset = unsafe { std::mem::zeroed() };
127        unsafe {
128            check_arkui_status!(OH_ArkUI_NodeUtils_GetLayoutPositionInWindow(
129                self.raw(),
130                &mut offset
131            ))
132        }?;
133        Ok(offset.into())
134    }
135
136    /// Returns this node's translated position in the current window.
137    pub fn position_with_translate_in_window(&self) -> ArkUIResult<IntOffset> {
138        let mut offset: ArkUI_IntOffset = unsafe { std::mem::zeroed() };
139        unsafe {
140            check_arkui_status!(OH_ArkUI_NodeUtils_GetPositionWithTranslateInWindow(
141                self.raw(),
142                &mut offset
143            ))
144        }?;
145        Ok(offset.into())
146    }
147
148    /// Mark this node dirty so ArkUI recomputes the requested render pipeline stage.
149    pub fn mark_dirty(&self, dirty_flag: NodeDirtyFlag) -> ArkUIResult<()> {
150        ARK_UI_NATIVE_NODE_API_1.with(|api| api.mark_dirty(self, dirty_flag))
151    }
152}
153
154impl ArkUIAttributeBasic for ArkUINode {
155    fn raw(&self) -> &ArkUINode {
156        self
157    }
158
159    fn borrow_mut(&mut self) -> &mut ArkUINode {
160        self
161    }
162}
163
164impl ArkUICommonAttribute for ArkUINode {}
165
166/// This implementation just for event and animation to use it.
167/// When you need to create a new node, you should add raw and tag at the same time.
168impl Default for ArkUINode {
169    fn default() -> Self {
170        Self {
171            raw: std::ptr::null_mut(),
172            tag: ArkUINodeType::Custom,
173            children: vec![],
174            event_handle: Default::default(),
175        }
176    }
177}
178
179#[cfg(feature = "napi")]
180/// Convert ArkUI node to native node
181pub struct ArkUINodeRaw {
182    /// N-API environment.
183    pub(crate) env: sys::napi_env,
184    /// N-API value.
185    pub(crate) value: sys::napi_value,
186    /// Native ArkUI handle.
187    pub raw: ArkUI_NodeHandle,
188}
189
190#[cfg(feature = "napi")]
191impl TypeName for ArkUINodeRaw {
192    fn type_name() -> &'static str {
193        "ArkUINode"
194    }
195    fn value_type() -> napi_ohos::ValueType {
196        napi_ohos::ValueType::Object
197    }
198}
199
200#[cfg(feature = "napi")]
201impl ValidateNapiValue for ArkUINodeRaw {}
202
203#[cfg(feature = "napi")]
204impl FromNapiValue for ArkUINodeRaw {
205    unsafe fn from_napi_value(
206        env: sys::napi_env,
207        napi_val: sys::napi_value,
208    ) -> napi_ohos::Result<Self> {
209        let mut slot = ptr::null_mut();
210        unsafe {
211            check_status!(
212                OH_ArkUI_GetNodeHandleFromNapiValue(env, napi_val, &mut slot),
213                "Get Node failed."
214            )?
215        };
216        Ok(ArkUINodeRaw {
217            env,
218            value: napi_val,
219            raw: slot,
220        })
221    }
222}