@effindomv2/fui-rs 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/COMMERCIAL.md +7 -0
  2. package/Cargo.toml +34 -0
  3. package/LICENSE.md +9 -0
  4. package/README.md +88 -0
  5. package/package.json +54 -0
  6. package/scripts/build.sh +227 -0
  7. package/scripts/check-runtime-dependency.sh +41 -0
  8. package/scripts/framework-host-services.ts +40 -0
  9. package/scripts/generate-host-events.ts +17 -0
  10. package/scripts/generate-host-services.ts +28 -0
  11. package/scripts/hostgen/common.ts +73 -0
  12. package/scripts/hostgen/registry.ts +159 -0
  13. package/scripts/hostgen/rust-host-events.ts +171 -0
  14. package/scripts/hostgen/rust-host-services.ts +257 -0
  15. package/src/animation.rs +625 -0
  16. package/src/app.rs +324 -0
  17. package/src/assets.rs +572 -0
  18. package/src/bindings/mod.rs +1 -0
  19. package/src/bindings/ui.rs +705 -0
  20. package/src/bitmap.rs +317 -0
  21. package/src/bridge_callbacks.rs +242 -0
  22. package/src/context_menu_manager.rs +332 -0
  23. package/src/controls/anti_selection_area.rs +54 -0
  24. package/src/controls/button.rs +542 -0
  25. package/src/controls/checkbox.rs +372 -0
  26. package/src/controls/combobox.rs +1574 -0
  27. package/src/controls/context_menu.rs +1367 -0
  28. package/src/controls/control_template_set.rs +46 -0
  29. package/src/controls/control_tokens.rs +596 -0
  30. package/src/controls/dialog.rs +590 -0
  31. package/src/controls/dropdown.rs +1010 -0
  32. package/src/controls/form.rs +229 -0
  33. package/src/controls/internal/button_presenter.rs +142 -0
  34. package/src/controls/internal/checkbox_indicator_presenter.rs +210 -0
  35. package/src/controls/internal/dropdown_chevron_presenter.rs +134 -0
  36. package/src/controls/internal/dropdown_field_presenter.rs +269 -0
  37. package/src/controls/internal/dropdown_option_row_presenter.rs +184 -0
  38. package/src/controls/internal/mod.rs +13 -0
  39. package/src/controls/internal/pressable_indicator_presenter.rs +26 -0
  40. package/src/controls/internal/pressable_labeled_control.rs +492 -0
  41. package/src/controls/internal/radio_indicator_presenter.rs +208 -0
  42. package/src/controls/internal/selectable_popup_list.rs +597 -0
  43. package/src/controls/internal/slider_presenter.rs +282 -0
  44. package/src/controls/internal/switch_indicator_presenter.rs +235 -0
  45. package/src/controls/internal/text_input_core.rs +1074 -0
  46. package/src/controls/internal/text_input_presenter.rs +108 -0
  47. package/src/controls/mod.rs +235 -0
  48. package/src/controls/nav_link.rs +395 -0
  49. package/src/controls/popup.rs +191 -0
  50. package/src/controls/progress_bar.rs +287 -0
  51. package/src/controls/radio_button.rs +348 -0
  52. package/src/controls/radio_group.rs +283 -0
  53. package/src/controls/selection_area.rs +82 -0
  54. package/src/controls/shared.rs +68 -0
  55. package/src/controls/slider.rs +701 -0
  56. package/src/controls/switch.rs +293 -0
  57. package/src/controls/templating.rs +49 -0
  58. package/src/controls/tests.rs +3905 -0
  59. package/src/controls/text_area.rs +207 -0
  60. package/src/controls/text_input.rs +192 -0
  61. package/src/debug.rs +146 -0
  62. package/src/drag_drop.rs +424 -0
  63. package/src/drag_gesture.rs +258 -0
  64. package/src/drawing.rs +385 -0
  65. package/src/event.rs +1603 -0
  66. package/src/external_drop.rs +467 -0
  67. package/src/fetch.rs +500 -0
  68. package/src/ffi.rs +3542 -0
  69. package/src/file.rs +1677 -0
  70. package/src/focus_adorner.rs +307 -0
  71. package/src/focus_visibility.rs +121 -0
  72. package/src/frame_scheduler.rs +159 -0
  73. package/src/frame_signal.rs +64 -0
  74. package/src/generated/ffi.rs +798 -0
  75. package/src/generated/framework_host_services.rs +74 -0
  76. package/src/generated/mod.rs +2 -0
  77. package/src/host_services.rs +162 -0
  78. package/src/image_sampling.rs +78 -0
  79. package/src/keyboard_scroll.rs +137 -0
  80. package/src/keyboard_scroll_tracker.rs +385 -0
  81. package/src/lib.rs +547 -0
  82. package/src/logger.rs +56 -0
  83. package/src/mobile_text_selection_toolbar.rs +1034 -0
  84. package/src/navigation.rs +48 -0
  85. package/src/node/core.rs +2210 -0
  86. package/src/node/custom_drawable.rs +149 -0
  87. package/src/node/flex_box.rs +874 -0
  88. package/src/node/grid.rs +304 -0
  89. package/src/node/helpers.rs +442 -0
  90. package/src/node/image.rs +506 -0
  91. package/src/node/mod.rs +315 -0
  92. package/src/node/scroll_bar.rs +845 -0
  93. package/src/node/scroll_box.rs +514 -0
  94. package/src/node/scroll_state.rs +121 -0
  95. package/src/node/scroll_view.rs +557 -0
  96. package/src/node/svg_node.rs +474 -0
  97. package/src/node/text_node.rs +633 -0
  98. package/src/node/virtual_list.rs +678 -0
  99. package/src/panic_hook.rs +36 -0
  100. package/src/persisted.rs +274 -0
  101. package/src/platform.rs +556 -0
  102. package/src/popup_presenter.rs +344 -0
  103. package/src/selection_handle_adorner.rs +838 -0
  104. package/src/signal.rs +134 -0
  105. package/src/text.rs +1065 -0
  106. package/src/theme.rs +571 -0
  107. package/src/timers.rs +106 -0
  108. package/src/tool_tip.rs +167 -0
  109. package/src/tool_tip_manager.rs +691 -0
  110. package/src/transitions.rs +41 -0
  111. package/src/typography.rs +520 -0
  112. package/src/viewport.rs +108 -0
  113. package/src/worker.rs +308 -0
  114. package/src/worker_job.rs +82 -0
  115. package/src/worker_runtime.rs +172 -0
@@ -0,0 +1,2210 @@
1
+ use super::*;
2
+ use crate::drag_drop::{
3
+ DragCompletedEventArgs, DragDataObject, DragDropEffects, DragEventArgs, DropProposal,
4
+ };
5
+ use crate::drag_gesture::{DragCompletedEvent, DragGesture, DragStartedEvent};
6
+ use crate::event::{SelectionChangedEventArgs, TextChangedEventArgs};
7
+ use crate::external_drop::ExternalDropEventArgs;
8
+ use crate::persisted::PersistedStateAdapter;
9
+ use crate::tool_tip::ToolTip;
10
+ use crate::transitions::NodeTransitions;
11
+
12
+ pub(crate) type PointerCallback = Rc<dyn Fn(&mut PointerEventArgs)>;
13
+ pub(crate) type WheelCallback = Rc<dyn Fn(&mut WheelEventArgs)>;
14
+ pub(crate) type GestureCallback = Rc<dyn Fn(&mut GestureEventArgs)>;
15
+ pub(crate) type KeyCallback = Rc<dyn Fn(&mut KeyEventArgs)>;
16
+ pub(crate) type LongPressCallback = Rc<dyn Fn(&mut LongPressEventArgs)>;
17
+ pub(crate) type FocusChangedCallback = Rc<dyn Fn(FocusChangedEventArgs)>;
18
+ pub(crate) type TextChangedCallback = Rc<dyn Fn(TextChangedEventArgs)>;
19
+ pub(crate) type TextReplacedCallback = Rc<dyn Fn(u32, u32, String)>;
20
+ pub(crate) type ScrollChangedCallback = Rc<dyn Fn(f32, f32, f32, f32, f32, f32)>;
21
+ pub(crate) type SelectionChangedCallback = Rc<dyn Fn(SelectionChangedEventArgs)>;
22
+ pub(crate) type CrossSelectionChangedCallback = Rc<dyn Fn(String)>;
23
+ pub(crate) type DrawCallback = Rc<dyn Fn(&mut DrawContext)>;
24
+ pub(crate) type ContextMenuCallback = Rc<dyn Fn(ContextMenuEventArgs)>;
25
+ pub(crate) type DragDataCallback = Rc<dyn Fn() -> Option<DragDataObject>>;
26
+ pub(crate) type DragCompletedCallback = Rc<dyn Fn(DragCompletedEventArgs)>;
27
+ pub(crate) type DragProposalCallback = Rc<dyn Fn(DragEventArgs) -> DropProposal>;
28
+ pub(crate) type DragEventCallback = Rc<dyn Fn(DragEventArgs)>;
29
+ pub(crate) type ExternalDragProposalCallback = Rc<dyn Fn(ExternalDropEventArgs) -> DropProposal>;
30
+ pub(crate) type ExternalDragEventCallback = Rc<dyn Fn(ExternalDropEventArgs)>;
31
+ pub(crate) type EffectiveEnabledChangedCallback = Rc<dyn Fn(bool)>;
32
+
33
+ pub(crate) fn is_primary_activation_pointer(event: &PointerEventArgs) -> bool {
34
+ event.button == 0
35
+ || event.pointer_type == PointerType::Touch
36
+ || event.pointer_type == PointerType::Pen
37
+ }
38
+
39
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40
+ pub struct NodeHandle(u64);
41
+
42
+ impl NodeHandle {
43
+ pub const INVALID: Self = Self(HandleValue::Invalid as u64);
44
+
45
+ pub(crate) fn from_raw(raw: u64) -> Self {
46
+ Self(raw)
47
+ }
48
+
49
+ pub fn raw(self) -> u64 {
50
+ self.0
51
+ }
52
+ }
53
+
54
+ #[derive(Clone, Copy, Debug, PartialEq)]
55
+ pub struct ContextMenuEventArgs {
56
+ pub target: NodeHandle,
57
+ pub x: f32,
58
+ pub y: f32,
59
+ }
60
+
61
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
62
+ pub(crate) enum NodeKind {
63
+ FlexBox,
64
+ Text,
65
+ Grid,
66
+ Image,
67
+ Svg,
68
+ ScrollView,
69
+ }
70
+
71
+ impl NodeKind {
72
+ pub(crate) fn node_type(self) -> NodeType {
73
+ match self {
74
+ Self::FlexBox => NodeType::FlexBox,
75
+ Self::Text => NodeType::Text,
76
+ Self::Grid => NodeType::Grid,
77
+ Self::Image => NodeType::Image,
78
+ Self::Svg => NodeType::Svg,
79
+ Self::ScrollView => NodeType::ScrollView,
80
+ }
81
+ }
82
+ }
83
+
84
+ #[derive(Clone, Default)]
85
+ pub(crate) struct EventHandlers {
86
+ pub(crate) pointer_click: Option<PointerCallback>,
87
+ pub(crate) pointer_down: Option<PointerCallback>,
88
+ pub(crate) pointer_move: Option<PointerCallback>,
89
+ pub(crate) pointer_up: Option<PointerCallback>,
90
+ pub(crate) pointer_enter: Option<PointerCallback>,
91
+ pub(crate) pointer_leave: Option<PointerCallback>,
92
+ pub(crate) pointer_cancel: Option<PointerCallback>,
93
+ pub(crate) wheel: Option<WheelCallback>,
94
+ pub(crate) pan_gesture: Option<GestureCallback>,
95
+ pub(crate) pinch_gesture: Option<GestureCallback>,
96
+ pub(crate) long_press: Option<LongPressCallback>,
97
+ pub(crate) long_press_minimum_duration_ms: i32,
98
+ pub(crate) long_press_movement_tolerance: f32,
99
+ pub(crate) key_down: Option<KeyCallback>,
100
+ pub(crate) key_up: Option<KeyCallback>,
101
+ pub(crate) focus_changed: Option<FocusChangedCallback>,
102
+ pub(crate) text_changed: Option<TextChangedCallback>,
103
+ pub(crate) text_replaced: Option<TextReplacedCallback>,
104
+ pub(crate) scroll_changed: Option<ScrollChangedCallback>,
105
+ pub(crate) selection_changed: Option<SelectionChangedCallback>,
106
+ pub(crate) cross_selection_changed: Option<CrossSelectionChangedCallback>,
107
+ }
108
+
109
+ impl EventHandlers {
110
+ pub(crate) fn new() -> Self {
111
+ Self {
112
+ long_press_minimum_duration_ms: DEFAULT_LONG_PRESS_MINIMUM_DURATION_MS,
113
+ long_press_movement_tolerance: DEFAULT_LONG_PRESS_MOVEMENT_TOLERANCE,
114
+ ..Self::default()
115
+ }
116
+ }
117
+ }
118
+ #[derive(Clone)]
119
+ pub(crate) struct NodeBehavior {
120
+ pub(crate) enabled: bool,
121
+ pub(crate) inherited_enabled: bool,
122
+ pub(crate) last_effective_enabled: bool,
123
+ pub(crate) interactive: bool,
124
+ pub(crate) focusable: Option<(bool, i32)>,
125
+ pub(crate) cursor: Option<CursorStyle>,
126
+ pub(crate) node_id: Option<String>,
127
+ pub(crate) semantic_role: Option<SemanticRole>,
128
+ pub(crate) semantic_label: Option<String>,
129
+ pub(crate) default_semantic_label: Option<String>,
130
+ pub(crate) semantic_disabled: Option<bool>,
131
+ pub(crate) semantic_checked: Option<SemanticCheckedState>,
132
+ pub(crate) semantic_selected: Option<bool>,
133
+ pub(crate) semantic_value_range: Option<(f32, f32, f32)>,
134
+ pub(crate) semantic_orientation: Option<Orientation>,
135
+ pub(crate) selectable_text: bool,
136
+ pub(crate) editable_text: bool,
137
+ pub(crate) text_content: Option<String>,
138
+ pub(crate) link_url: Option<String>,
139
+ pub(crate) image_url: Option<String>,
140
+ pub(crate) link_preview_pin: Option<Rc<dyn Fn()>>,
141
+ pub(crate) link_preview_release: Option<Rc<dyn Fn()>>,
142
+ pub(crate) context_menu_disabled: bool,
143
+ pub(crate) context_menu_handler: Option<ContextMenuCallback>,
144
+ pub(crate) tool_tip: Option<ToolTip>,
145
+ pub(crate) track_semantic_disabled_from_enabled: bool,
146
+ pub(crate) request_semantic_announcement: bool,
147
+ pub(crate) visibility: Option<Visibility>,
148
+ pub(crate) is_portal: bool,
149
+ pub(crate) fill_width: bool,
150
+ pub(crate) fill_height: bool,
151
+ pub(crate) fill_width_percent: Option<f32>,
152
+ pub(crate) fill_height_percent: Option<f32>,
153
+ pub(crate) min_width: Option<(f32, Unit)>,
154
+ pub(crate) max_width: Option<(f32, Unit)>,
155
+ pub(crate) min_height: Option<(f32, Unit)>,
156
+ pub(crate) max_height: Option<(f32, Unit)>,
157
+ pub(crate) flex_basis: Option<f32>,
158
+ pub(crate) justify_content: Option<JustifyContent>,
159
+ pub(crate) align_items: Option<AlignItems>,
160
+ pub(crate) align_self: Option<AlignSelf>,
161
+ pub(crate) margin: Option<(f32, f32, f32, f32)>,
162
+ pub(crate) position_type: Option<PositionType>,
163
+ pub(crate) position: Option<(f32, f32, f32, f32)>,
164
+ pub(crate) is_shared_size_scope: bool,
165
+ pub(crate) custom_drawable: bool,
166
+ pub(crate) flex_wrap: Option<FlexWrap>,
167
+ pub(crate) clip_to_bounds: Option<bool>,
168
+ pub(crate) selection_area: bool,
169
+ pub(crate) selection_area_barrier: bool,
170
+ pub(crate) preserve_selection_on_pointer_down: bool,
171
+ pub(crate) scroll_proxy_target: Option<u64>,
172
+ pub(crate) external_drop_allowed: bool,
173
+ }
174
+
175
+ impl Default for NodeBehavior {
176
+ fn default() -> Self {
177
+ Self {
178
+ enabled: true,
179
+ inherited_enabled: true,
180
+ last_effective_enabled: true,
181
+ interactive: false,
182
+ focusable: None,
183
+ cursor: None,
184
+ node_id: None,
185
+ semantic_role: None,
186
+ semantic_label: None,
187
+ default_semantic_label: None,
188
+ semantic_disabled: None,
189
+ semantic_checked: None,
190
+ semantic_selected: None,
191
+ semantic_value_range: None,
192
+ semantic_orientation: None,
193
+ selectable_text: false,
194
+ editable_text: false,
195
+ text_content: None,
196
+ link_url: None,
197
+ image_url: None,
198
+ link_preview_pin: None,
199
+ link_preview_release: None,
200
+ context_menu_disabled: false,
201
+ context_menu_handler: None,
202
+ tool_tip: None,
203
+ track_semantic_disabled_from_enabled: false,
204
+ request_semantic_announcement: false,
205
+ visibility: None,
206
+ is_portal: false,
207
+ fill_width: false,
208
+ fill_height: false,
209
+ fill_width_percent: None,
210
+ fill_height_percent: None,
211
+ min_width: None,
212
+ max_width: None,
213
+ min_height: None,
214
+ max_height: None,
215
+ flex_basis: None,
216
+ justify_content: None,
217
+ align_items: None,
218
+ align_self: None,
219
+ margin: None,
220
+ position_type: None,
221
+ position: None,
222
+ is_shared_size_scope: false,
223
+ custom_drawable: false,
224
+ flex_wrap: None,
225
+ clip_to_bounds: None,
226
+ selection_area: false,
227
+ selection_area_barrier: false,
228
+ preserve_selection_on_pointer_down: false,
229
+ scroll_proxy_target: None,
230
+ external_drop_allowed: false,
231
+ }
232
+ }
233
+ }
234
+
235
+ #[derive(Clone, Copy)]
236
+ pub(crate) struct BoxStyle {
237
+ pub(crate) radius_tl: f32,
238
+ pub(crate) radius_tr: f32,
239
+ pub(crate) radius_br: f32,
240
+ pub(crate) radius_bl: f32,
241
+ pub(crate) border_width: f32,
242
+ pub(crate) border_color: u32,
243
+ pub(crate) border_style: BorderStyle,
244
+ pub(crate) border_dash_on: f32,
245
+ pub(crate) border_dash_off: f32,
246
+ }
247
+
248
+ #[derive(Clone, Copy)]
249
+ pub(crate) struct DropShadow {
250
+ pub(crate) color: u32,
251
+ pub(crate) offset_x: f32,
252
+ pub(crate) offset_y: f32,
253
+ pub(crate) blur_sigma: f32,
254
+ pub(crate) spread: f32,
255
+ }
256
+ #[derive(Clone)]
257
+ pub(crate) struct LinearGradient {
258
+ pub(crate) sx: f32,
259
+ pub(crate) sy: f32,
260
+ pub(crate) ex: f32,
261
+ pub(crate) ey: f32,
262
+ pub(crate) offsets: Vec<f32>,
263
+ pub(crate) colors: Vec<u32>,
264
+ }
265
+ #[derive(Clone)]
266
+ pub(crate) struct FlexBoxProps {
267
+ pub(crate) width: Option<(f32, Unit)>,
268
+ pub(crate) height: Option<(f32, Unit)>,
269
+ pub(crate) bg_color: Option<u32>,
270
+ pub(crate) padding: Option<(f32, f32, f32, f32)>,
271
+ pub(crate) flex_direction: Option<FlexDirection>,
272
+ pub(crate) box_style: Option<BoxStyle>,
273
+ pub(crate) opacity: Option<f32>,
274
+ pub(crate) blur_sigma: Option<f32>,
275
+ pub(crate) drop_shadow: Option<DropShadow>,
276
+ pub(crate) background_blur_sigma: Option<f32>,
277
+ pub(crate) linear_gradient: Option<LinearGradient>,
278
+ pub(crate) transitions: Option<NodeTransitions>,
279
+ }
280
+
281
+ impl Default for FlexBoxProps {
282
+ fn default() -> Self {
283
+ Self {
284
+ width: None,
285
+ height: None,
286
+ bg_color: None,
287
+ padding: None,
288
+ flex_direction: None,
289
+ box_style: None,
290
+ opacity: None,
291
+ blur_sigma: None,
292
+ drop_shadow: None,
293
+ background_blur_sigma: None,
294
+ linear_gradient: None,
295
+ transitions: None,
296
+ }
297
+ }
298
+ }
299
+
300
+ #[derive(Clone, Default)]
301
+ pub(crate) struct TextProps {
302
+ pub(crate) content: String,
303
+ pub(crate) width: Option<(f32, Unit)>,
304
+ pub(crate) height: Option<(f32, Unit)>,
305
+ pub(crate) font_id: u32,
306
+ pub(crate) font_size: f32,
307
+ pub(crate) has_font: bool,
308
+ pub(crate) font_family: Option<FontFamily>,
309
+ pub(crate) font_weight: FontWeight,
310
+ pub(crate) font_style: FontStyle,
311
+ pub(crate) uses_direct_font_id: bool,
312
+ pub(crate) text_color: Option<u32>,
313
+ pub(crate) style_runs: Vec<u32>,
314
+ pub(crate) has_style_runs: bool,
315
+ pub(crate) line_height: Option<f32>,
316
+ pub(crate) text_align: Option<TextAlign>,
317
+ pub(crate) text_vertical_align: Option<TextVerticalAlign>,
318
+ pub(crate) text_limits: Option<(i32, i32)>,
319
+ pub(crate) wrapping: Option<bool>,
320
+ pub(crate) overflow: Option<TextOverflow>,
321
+ pub(crate) overflow_fade: Option<(bool, bool)>,
322
+ pub(crate) selectable: Option<(bool, u32)>,
323
+ pub(crate) uses_theme_selection_color: bool,
324
+ pub(crate) editable: Option<bool>,
325
+ pub(crate) editor_command_keys: Option<bool>,
326
+ pub(crate) editor_accepts_tab: Option<bool>,
327
+ pub(crate) obscured: Option<bool>,
328
+ pub(crate) caret_color: Option<u32>,
329
+ }
330
+
331
+ #[derive(Clone, Default)]
332
+ pub(crate) struct GridProps {
333
+ pub(crate) width: Option<(f32, Unit)>,
334
+ pub(crate) height: Option<(f32, Unit)>,
335
+ pub(crate) bg_color: Option<u32>,
336
+ pub(crate) padding: Option<(f32, f32, f32, f32)>,
337
+ pub(crate) columns: Vec<f32>,
338
+ pub(crate) column_types: Vec<GridUnit>,
339
+ pub(crate) rows: Vec<f32>,
340
+ pub(crate) row_types: Vec<GridUnit>,
341
+ pub(crate) column_shared_size_groups: Vec<(u32, String)>,
342
+ pub(crate) row_shared_size_groups: Vec<(u32, String)>,
343
+ }
344
+ #[derive(Clone)]
345
+ pub(crate) struct ImageProps {
346
+ pub(crate) width: Option<(f32, Unit)>,
347
+ pub(crate) height: Option<(f32, Unit)>,
348
+ pub(crate) texture_id: u32,
349
+ pub(crate) source_url: Option<String>,
350
+ pub(crate) object_fit: ObjectFit,
351
+ pub(crate) sampling_kind: ImageSamplingKind,
352
+ pub(crate) max_aniso: u32,
353
+ pub(crate) image_nine: Option<(f32, f32, f32, f32)>,
354
+ }
355
+
356
+ #[derive(Clone)]
357
+ pub(crate) struct SvgProps {
358
+ pub(crate) width: Option<(f32, Unit)>,
359
+ pub(crate) height: Option<(f32, Unit)>,
360
+ pub(crate) svg_id: u32,
361
+ pub(crate) source_url: Option<String>,
362
+ pub(crate) tint_color: u32,
363
+ pub(crate) sampling_kind: ImageSamplingKind,
364
+ pub(crate) max_aniso: u32,
365
+ pub(crate) opacity: Option<f32>,
366
+ }
367
+
368
+ #[derive(Clone)]
369
+ pub(crate) struct ScrollViewProps {
370
+ pub(crate) width: Option<(f32, Unit)>,
371
+ pub(crate) height: Option<(f32, Unit)>,
372
+ pub(crate) bg_color: Option<u32>,
373
+ pub(crate) padding: Option<(f32, f32, f32, f32)>,
374
+ pub(crate) enable_scroll_x: bool,
375
+ pub(crate) enable_scroll_y: bool,
376
+ pub(crate) friction: Option<f32>,
377
+ pub(crate) smooth_scrolling: bool,
378
+ pub(crate) scroll_offset: Option<(f32, f32)>,
379
+ pub(crate) content_size: Option<(f32, f32)>,
380
+ pub(crate) persist_scroll: bool,
381
+ pub(crate) transitions: Option<NodeTransitions>,
382
+ }
383
+
384
+ #[derive(Clone, Copy, Debug, Default)]
385
+ pub(crate) struct ScrollRoutingState {
386
+ pub(crate) enabled_x: bool,
387
+ pub(crate) enabled_y: bool,
388
+ pub(crate) offset_x: f32,
389
+ pub(crate) offset_y: f32,
390
+ pub(crate) content_width: f32,
391
+ pub(crate) content_height: f32,
392
+ pub(crate) viewport_width: f32,
393
+ pub(crate) viewport_height: f32,
394
+ }
395
+
396
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
397
+ pub(crate) struct GridPlacement {
398
+ pub(crate) row: u32,
399
+ pub(crate) col: u32,
400
+ pub(crate) row_span: u32,
401
+ pub(crate) col_span: u32,
402
+ }
403
+
404
+ pub(crate) struct NodeCore {
405
+ pub(crate) handle: NodeHandle,
406
+ pub(crate) kind: NodeKind,
407
+ pub(crate) parent: Weak<RefCell<NodeCore>>,
408
+ pub(crate) children: Vec<NodeRef>,
409
+ pub(crate) mounted: bool,
410
+ pub(crate) children_built: bool,
411
+ pub(crate) behavior: NodeBehavior,
412
+ pub(crate) handlers: EventHandlers,
413
+ pub(crate) draw_callback: Option<DrawCallback>,
414
+ pub(crate) retained_attachments: Vec<Rc<dyn Any>>,
415
+ pub(crate) persisted_state_adapters: Vec<Rc<dyn PersistedStateAdapter>>,
416
+ pub(crate) drag_data_callback: Option<DragDataCallback>,
417
+ pub(crate) drag_allowed_effects: DragDropEffects,
418
+ pub(crate) drag_completed_callback: Option<DragCompletedCallback>,
419
+ pub(crate) drop_allowed: bool,
420
+ pub(crate) drag_enter_callback: Option<DragProposalCallback>,
421
+ pub(crate) drag_over_callback: Option<DragProposalCallback>,
422
+ pub(crate) drag_leave_callback: Option<DragEventCallback>,
423
+ pub(crate) drop_callback: Option<DragEventCallback>,
424
+ pub(crate) external_drag_enter_callback: Option<ExternalDragProposalCallback>,
425
+ pub(crate) external_drag_over_callback: Option<ExternalDragProposalCallback>,
426
+ pub(crate) external_drag_leave_callback: Option<ExternalDragEventCallback>,
427
+ pub(crate) external_drop_callback: Option<ExternalDragEventCallback>,
428
+ pub(crate) drag_gesture: Option<Rc<RefCell<DragGesture>>>,
429
+ pub(crate) drag_click_pending: bool,
430
+ pub(crate) drag_click_pending_count: i32,
431
+ pub(crate) click_pending: bool,
432
+ pub(crate) click_pending_count: i32,
433
+ pub(crate) scroll_routing: Option<ScrollRoutingState>,
434
+ pub(crate) effective_enabled_changed_callbacks: Vec<EffectiveEnabledChangedCallback>,
435
+ }
436
+
437
+ impl NodeCore {
438
+ pub(crate) fn new(kind: NodeKind) -> Self {
439
+ Self {
440
+ handle: NodeHandle::INVALID,
441
+ kind,
442
+ parent: Weak::new(),
443
+ children: Vec::new(),
444
+ mounted: false,
445
+ children_built: false,
446
+ behavior: NodeBehavior::default(),
447
+ handlers: EventHandlers::new(),
448
+ draw_callback: None,
449
+ retained_attachments: Vec::new(),
450
+ persisted_state_adapters: Vec::new(),
451
+ drag_data_callback: None,
452
+ drag_allowed_effects: DragDropEffects::Copy,
453
+ drag_completed_callback: None,
454
+ drop_allowed: false,
455
+ drag_enter_callback: None,
456
+ drag_over_callback: None,
457
+ drag_leave_callback: None,
458
+ drop_callback: None,
459
+ external_drag_enter_callback: None,
460
+ external_drag_over_callback: None,
461
+ external_drag_leave_callback: None,
462
+ external_drop_callback: None,
463
+ drag_gesture: None,
464
+ drag_click_pending: false,
465
+ drag_click_pending_count: 0,
466
+ click_pending: false,
467
+ click_pending_count: 0,
468
+ scroll_routing: None,
469
+ effective_enabled_changed_callbacks: Vec::new(),
470
+ }
471
+ }
472
+ }
473
+
474
+ #[derive(Clone)]
475
+ #[doc(hidden)]
476
+ pub struct NodeRef {
477
+ inner: Rc<RefCell<NodeCore>>,
478
+ build_callback: Option<Rc<dyn Fn()>>,
479
+ }
480
+
481
+ #[derive(Clone)]
482
+ pub(crate) struct WeakNodeRef {
483
+ inner: Weak<RefCell<NodeCore>>,
484
+ }
485
+
486
+ impl WeakNodeRef {
487
+ pub(crate) fn upgrade(&self) -> Option<NodeRef> {
488
+ self.inner.upgrade().map(NodeRef::from_core)
489
+ }
490
+ }
491
+
492
+ #[derive(Clone)]
493
+ pub(crate) struct WeakFlexBox {
494
+ pub(crate) core: Weak<RefCell<NodeCore>>,
495
+ pub(crate) props: Weak<RefCell<FlexBoxProps>>,
496
+ pub(crate) active_animations: Weak<RefCell<crate::node::flex_box::FlexBoxAnimations>>,
497
+ }
498
+
499
+ impl WeakFlexBox {
500
+ pub(crate) fn upgrade(&self) -> Option<FlexBox> {
501
+ Some(FlexBox {
502
+ core: self.core.upgrade()?,
503
+ props: self.props.upgrade()?,
504
+ active_animations: self.active_animations.upgrade()?,
505
+ })
506
+ }
507
+ }
508
+
509
+ impl NodeRef {
510
+ pub(crate) fn from_core(inner: Rc<RefCell<NodeCore>>) -> Self {
511
+ Self {
512
+ inner,
513
+ build_callback: None,
514
+ }
515
+ }
516
+
517
+ pub(crate) fn from_node<T: Node>(inner: Rc<RefCell<NodeCore>>, node: T) -> Self {
518
+ Self {
519
+ inner,
520
+ build_callback: Some(Rc::new(move || node.build())),
521
+ }
522
+ }
523
+
524
+ pub(crate) fn with_build_callback(mut self, callback: impl Fn() + 'static) -> Self {
525
+ self.build_callback = Some(Rc::new(callback));
526
+ self
527
+ }
528
+
529
+ pub(crate) fn handle(&self) -> NodeHandle {
530
+ self.inner.borrow().handle
531
+ }
532
+
533
+ pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
534
+ Rc::ptr_eq(&self.inner, &other.inner)
535
+ }
536
+
537
+ pub(crate) fn parent(&self) -> Option<Self> {
538
+ self.inner.borrow().parent.upgrade().map(Self::from_core)
539
+ }
540
+
541
+ pub(crate) fn node_type(&self) -> NodeType {
542
+ self.inner.borrow().kind.node_type()
543
+ }
544
+
545
+ pub(crate) fn children(&self) -> Vec<Self> {
546
+ self.inner.borrow().children.clone()
547
+ }
548
+
549
+ pub(crate) fn append_child_ref(&self, child: &NodeRef) {
550
+ if Rc::ptr_eq(&self.inner, &child.inner) {
551
+ return;
552
+ }
553
+ if self
554
+ .inner
555
+ .borrow()
556
+ .children
557
+ .iter()
558
+ .any(|candidate| Rc::ptr_eq(&candidate.inner, &child.inner))
559
+ {
560
+ return;
561
+ }
562
+ if let Some(previous_parent) = child.inner.borrow().parent.upgrade() {
563
+ if Rc::ptr_eq(&previous_parent, &self.inner) {
564
+ return;
565
+ }
566
+ let child_handle = child.handle();
567
+ {
568
+ let mut previous_parent_core = previous_parent.borrow_mut();
569
+ previous_parent_core
570
+ .children
571
+ .retain(|candidate| !Rc::ptr_eq(&candidate.inner, &child.inner));
572
+ }
573
+ if previous_parent.borrow().handle != NodeHandle::INVALID
574
+ && child_handle != NodeHandle::INVALID
575
+ {
576
+ ui::remove_child(previous_parent.borrow().handle.raw(), child_handle.raw());
577
+ }
578
+ }
579
+
580
+ child.inner.borrow_mut().parent = Rc::downgrade(&self.inner);
581
+ self.inner.borrow_mut().children.push(child.clone());
582
+ self.inner.borrow_mut().children_built = false;
583
+ child.set_inherited_enabled(self.is_enabled_for_routing());
584
+ if self.handle() != NodeHandle::INVALID {
585
+ child.build();
586
+ ui::add_child(self.handle().raw(), child.handle().raw());
587
+ self.inner.borrow_mut().children_built = true;
588
+ crate::frame_scheduler::mark_needs_commit();
589
+ }
590
+ }
591
+
592
+ pub(crate) fn dispose(&self) {
593
+ let children = self.inner.borrow().children.clone();
594
+ for child in children {
595
+ if child.handle() != NodeHandle::INVALID && self.handle() != NodeHandle::INVALID {
596
+ ui::remove_child(self.handle().raw(), child.handle().raw());
597
+ }
598
+ child.dispose();
599
+ }
600
+ let handle = self.handle();
601
+ if handle != NodeHandle::INVALID {
602
+ crate::focus_adorner::handle_owner_destroyed(handle);
603
+ crate::tool_tip_manager::ToolTipManager::handle_owner_destroyed(handle);
604
+ crate::event::unregister_node(handle);
605
+ ui::delete_node(handle.raw());
606
+ }
607
+ {
608
+ let mut core = self.inner.borrow_mut();
609
+ core.handle = NodeHandle::INVALID;
610
+ core.mounted = false;
611
+ core.children_built = false;
612
+ }
613
+ }
614
+
615
+ pub(crate) fn detach_from_parent(&self) {
616
+ let Some(parent) = self.parent() else {
617
+ return;
618
+ };
619
+ let removed = {
620
+ let mut core = parent.inner.borrow_mut();
621
+ let Some(index) = core
622
+ .children
623
+ .iter()
624
+ .position(|candidate| Rc::ptr_eq(&candidate.inner, &self.inner))
625
+ else {
626
+ return;
627
+ };
628
+ core.children.remove(index)
629
+ };
630
+ removed.inner.borrow_mut().parent = Weak::new();
631
+ removed.set_inherited_enabled(true);
632
+ parent.inner.borrow_mut().children_built = false;
633
+ if parent.handle() != NodeHandle::INVALID && self.handle() != NodeHandle::INVALID {
634
+ ui::remove_child(parent.handle().raw(), self.handle().raw());
635
+ parent.inner.borrow_mut().children_built = true;
636
+ crate::frame_scheduler::mark_needs_commit();
637
+ }
638
+ }
639
+
640
+ pub(crate) fn is_visible_for_routing(&self) -> bool {
641
+ !matches!(
642
+ self.inner.borrow().behavior.visibility,
643
+ Some(Visibility::Hidden | Visibility::Collapsed)
644
+ )
645
+ }
646
+
647
+ pub(crate) fn is_effectively_visible_for_routing(&self) -> bool {
648
+ let mut node = Some(self.clone());
649
+ while let Some(current) = node {
650
+ if !current.is_visible_for_routing() {
651
+ return false;
652
+ }
653
+ node = current.parent();
654
+ }
655
+ true
656
+ }
657
+
658
+ pub(crate) fn is_enabled_for_routing(&self) -> bool {
659
+ let behavior = &self.inner.borrow().behavior;
660
+ behavior.enabled && behavior.inherited_enabled
661
+ }
662
+
663
+ pub(crate) fn is_effectively_enabled_for_routing(&self) -> bool {
664
+ let mut node = Some(self.clone());
665
+ while let Some(current) = node {
666
+ if !current.is_enabled_for_routing() {
667
+ return false;
668
+ }
669
+ node = current.parent();
670
+ }
671
+ true
672
+ }
673
+
674
+ pub(crate) fn set_own_enabled(&self, enabled: bool) {
675
+ {
676
+ let mut core = self.inner.borrow_mut();
677
+ if core.behavior.enabled == enabled {
678
+ return;
679
+ }
680
+ core.behavior.enabled = enabled;
681
+ }
682
+ self.apply_enabled_changed();
683
+ }
684
+
685
+ pub(crate) fn set_inherited_enabled(&self, enabled: bool) {
686
+ {
687
+ let mut core = self.inner.borrow_mut();
688
+ if core.behavior.inherited_enabled == enabled {
689
+ return;
690
+ }
691
+ core.behavior.inherited_enabled = enabled;
692
+ }
693
+ self.apply_enabled_changed();
694
+ }
695
+
696
+ pub(crate) fn on_effective_enabled_changed(&self, handler: EffectiveEnabledChangedCallback) {
697
+ self.inner
698
+ .borrow_mut()
699
+ .effective_enabled_changed_callbacks
700
+ .push(handler);
701
+ }
702
+
703
+ fn apply_enabled_changed(&self) {
704
+ let (
705
+ effective,
706
+ handle,
707
+ interactive,
708
+ focusable,
709
+ visible,
710
+ track_semantic_disabled,
711
+ callbacks,
712
+ children,
713
+ ) = {
714
+ let mut core = self.inner.borrow_mut();
715
+ let effective = core.behavior.enabled && core.behavior.inherited_enabled;
716
+ if core.behavior.last_effective_enabled == effective {
717
+ return;
718
+ }
719
+ core.behavior.last_effective_enabled = effective;
720
+ (
721
+ effective,
722
+ core.handle,
723
+ core.behavior.interactive,
724
+ core.behavior.focusable,
725
+ !matches!(
726
+ core.behavior.visibility,
727
+ Some(Visibility::Hidden | Visibility::Collapsed)
728
+ ),
729
+ core.behavior.track_semantic_disabled_from_enabled,
730
+ core.effective_enabled_changed_callbacks.clone(),
731
+ core.children.clone(),
732
+ )
733
+ };
734
+
735
+ if handle != NodeHandle::INVALID {
736
+ ui::set_interactive(handle.raw(), effective && visible && interactive);
737
+ if let Some((focusable, tab_index)) = focusable {
738
+ ui::set_focusable(handle.raw(), effective && visible && focusable, tab_index);
739
+ }
740
+ if track_semantic_disabled {
741
+ ui::set_semantic_disabled(handle.raw(), true, !effective);
742
+ }
743
+ crate::frame_scheduler::mark_needs_commit();
744
+ }
745
+
746
+ for callback in callbacks {
747
+ callback(effective);
748
+ }
749
+ if !effective {
750
+ self.cancel_drag_state();
751
+ }
752
+ for child in children {
753
+ child.set_inherited_enabled(effective);
754
+ }
755
+ }
756
+
757
+ pub(crate) fn semantic_role_for_routing(&self) -> Option<SemanticRole> {
758
+ self.inner.borrow().behavior.semantic_role
759
+ }
760
+
761
+ pub(crate) fn cursor_style_for_routing(&self) -> CursorStyle {
762
+ self.inner
763
+ .borrow()
764
+ .behavior
765
+ .cursor
766
+ .unwrap_or(CursorStyle::Default)
767
+ }
768
+
769
+ pub(crate) fn require_interactive(&self) {
770
+ let (handle, enabled, changed) = {
771
+ let mut inner = self.inner.borrow_mut();
772
+ let changed = !inner.behavior.interactive;
773
+ inner.behavior.interactive = true;
774
+ (inner.handle, inner.behavior.enabled, changed)
775
+ };
776
+ if handle != NodeHandle::INVALID {
777
+ ui::set_interactive(handle.raw(), enabled);
778
+ if changed {
779
+ crate::frame_scheduler::mark_needs_commit();
780
+ }
781
+ }
782
+ }
783
+
784
+ pub(crate) fn is_selectable_text_for_routing(&self) -> bool {
785
+ self.inner.borrow().behavior.selectable_text
786
+ }
787
+
788
+ pub(crate) fn is_editable_text_for_routing(&self) -> bool {
789
+ self.inner.borrow().behavior.editable_text
790
+ }
791
+
792
+ pub(crate) fn preserves_selection_on_pointer_down_for_routing(&self) -> bool {
793
+ self.inner
794
+ .borrow()
795
+ .behavior
796
+ .preserve_selection_on_pointer_down
797
+ }
798
+
799
+ pub(crate) fn link_url_for_routing(&self) -> Option<String> {
800
+ self.inner.borrow().behavior.link_url.clone()
801
+ }
802
+
803
+ pub(crate) fn image_url_for_routing(&self) -> Option<String> {
804
+ self.inner.borrow().behavior.image_url.clone()
805
+ }
806
+
807
+ pub(crate) fn is_image_or_svg_for_routing(&self) -> bool {
808
+ matches!(self.inner.borrow().kind, NodeKind::Image | NodeKind::Svg)
809
+ }
810
+
811
+ pub(crate) fn text_content_for_routing(&self) -> Option<String> {
812
+ self.inner.borrow().behavior.text_content.clone()
813
+ }
814
+
815
+ pub(crate) fn set_link_url_for_routing(&self, value: Option<String>) {
816
+ self.inner.borrow_mut().behavior.link_url = value;
817
+ }
818
+
819
+ pub(crate) fn set_text_content_for_routing(&self, value: Option<String>) {
820
+ self.inner.borrow_mut().behavior.text_content = value;
821
+ }
822
+
823
+ pub(crate) fn set_semantic_label_for_routing(&self, value: Option<String>) {
824
+ self.inner.borrow_mut().behavior.semantic_label = value;
825
+ }
826
+
827
+ pub(crate) fn set_image_url_for_routing(&self, value: Option<String>) {
828
+ self.inner.borrow_mut().behavior.image_url = value;
829
+ }
830
+
831
+ pub(crate) fn set_link_preview_handlers_for_routing(
832
+ &self,
833
+ pin: Option<Rc<dyn Fn()>>,
834
+ release: Option<Rc<dyn Fn()>>,
835
+ ) {
836
+ let mut inner = self.inner.borrow_mut();
837
+ inner.behavior.link_preview_pin = pin;
838
+ inner.behavior.link_preview_release = release;
839
+ }
840
+
841
+ pub(crate) fn pin_link_preview_for_routing(&self) {
842
+ let callback = self.inner.borrow().behavior.link_preview_pin.clone();
843
+ if let Some(callback) = callback {
844
+ callback();
845
+ }
846
+ }
847
+
848
+ pub(crate) fn release_link_preview_for_routing(&self) {
849
+ let callback = self.inner.borrow().behavior.link_preview_release.clone();
850
+ if let Some(callback) = callback {
851
+ callback();
852
+ }
853
+ }
854
+
855
+ pub(crate) fn is_context_menu_disabled_for_routing(&self) -> bool {
856
+ self.inner.borrow().behavior.context_menu_disabled
857
+ }
858
+
859
+ pub(crate) fn context_menu_handler_for_routing(&self) -> Option<ContextMenuCallback> {
860
+ self.inner.borrow().behavior.context_menu_handler.clone()
861
+ }
862
+
863
+ pub(crate) fn tool_tip_for_routing(&self) -> Option<ToolTip> {
864
+ self.inner.borrow().behavior.tool_tip.clone()
865
+ }
866
+
867
+ pub(crate) fn node_id(&self) -> Option<String> {
868
+ self.inner.borrow().behavior.node_id.clone()
869
+ }
870
+
871
+ pub(crate) fn gesture_intent_for_routing(&self) -> crate::event::GestureIntent {
872
+ let handlers = &self.inner.borrow().handlers;
873
+ crate::event::GestureIntent::from_callbacks(
874
+ handlers.pan_gesture.is_some(),
875
+ handlers.pinch_gesture.is_some(),
876
+ )
877
+ }
878
+
879
+ pub(crate) fn is_scroll_view_for_routing(&self) -> bool {
880
+ self.inner.borrow().kind == NodeKind::ScrollView
881
+ }
882
+
883
+ pub(crate) fn has_long_press_for_routing(&self) -> bool {
884
+ self.inner.borrow().handlers.long_press.is_some() || self.has_drag_source()
885
+ }
886
+
887
+ pub(crate) fn scroll_routing_state(&self) -> Option<ScrollRoutingState> {
888
+ self.inner.borrow().scroll_routing
889
+ }
890
+
891
+ pub(crate) fn set_scroll_routing_enabled(&self, enabled_x: bool, enabled_y: bool) {
892
+ let mut inner = self.inner.borrow_mut();
893
+ let state = inner.scroll_routing.get_or_insert(ScrollRoutingState {
894
+ enabled_x,
895
+ enabled_y,
896
+ ..ScrollRoutingState::default()
897
+ });
898
+ state.enabled_x = enabled_x;
899
+ state.enabled_y = enabled_y;
900
+ }
901
+
902
+ pub(crate) fn set_scroll_routing_offsets(&self, offset_x: f32, offset_y: f32) {
903
+ if let Some(state) = self.inner.borrow_mut().scroll_routing.as_mut() {
904
+ state.offset_x = offset_x;
905
+ state.offset_y = offset_y;
906
+ }
907
+ }
908
+
909
+ pub(crate) fn set_scroll_routing_metrics(
910
+ &self,
911
+ offset_x: f32,
912
+ offset_y: f32,
913
+ content_width: f32,
914
+ content_height: f32,
915
+ viewport_width: f32,
916
+ viewport_height: f32,
917
+ ) {
918
+ if let Some(state) = self.inner.borrow_mut().scroll_routing.as_mut() {
919
+ state.offset_x = offset_x;
920
+ state.offset_y = offset_y;
921
+ state.content_width = content_width;
922
+ state.content_height = content_height;
923
+ state.viewport_width = viewport_width;
924
+ state.viewport_height = viewport_height;
925
+ }
926
+ }
927
+
928
+ pub(crate) fn absolute_to_local_position(&self, absolute_x: f32, absolute_y: f32) -> [f32; 2] {
929
+ let bounds = if self.handle() == NodeHandle::INVALID {
930
+ [0.0; 4]
931
+ } else {
932
+ ui::get_bounds(self.handle().raw()).unwrap_or([0.0; 4])
933
+ };
934
+ [absolute_x - bounds[0], absolute_y - bounds[1]]
935
+ }
936
+
937
+ pub(crate) fn retain_attachment<T: Any>(&self, attachment: Rc<T>) {
938
+ let retained: Rc<dyn Any> = attachment;
939
+ self.inner.borrow_mut().retained_attachments.push(retained);
940
+ }
941
+
942
+ pub(crate) fn set_node_id(&self, node_id: impl Into<String>) {
943
+ let node_id = node_id.into();
944
+ self.inner.borrow_mut().behavior.node_id = Some(node_id.clone());
945
+ if self.handle() != NodeHandle::INVALID {
946
+ ui::set_node_id(self.handle().raw(), &node_id);
947
+ }
948
+ }
949
+
950
+ pub(crate) fn bind_scroll_proxy_target_handle(&self, scroll_handle: u64) {
951
+ self.inner.borrow_mut().behavior.scroll_proxy_target = Some(scroll_handle);
952
+ if self.handle() != NodeHandle::INVALID {
953
+ ui::set_scroll_proxy_target(self.handle().raw(), scroll_handle);
954
+ }
955
+ }
956
+
957
+ pub(crate) fn register_persisted_state_adapter(&self, adapter: Rc<dyn PersistedStateAdapter>) {
958
+ let mut core = self.inner.borrow_mut();
959
+ if let Some(index) = core
960
+ .persisted_state_adapters
961
+ .iter()
962
+ .position(|existing| existing.kind() == adapter.kind())
963
+ {
964
+ core.persisted_state_adapters[index] = adapter;
965
+ return;
966
+ }
967
+ core.persisted_state_adapters.push(adapter);
968
+ }
969
+
970
+ pub(crate) fn capture_persisted_state_tree(&self) {
971
+ self.capture_persisted_state();
972
+ let children = self.inner.borrow().children.clone();
973
+ for child in children {
974
+ child.capture_persisted_state_tree();
975
+ }
976
+ }
977
+
978
+ pub(crate) fn restore_persisted_state_tree(&self) {
979
+ let children = self.inner.borrow().children.clone();
980
+ for child in children {
981
+ child.restore_persisted_state_tree();
982
+ }
983
+ self.restore_persisted_state();
984
+ }
985
+
986
+ fn capture_persisted_state(&self) {
987
+ let (node_id, adapters) = {
988
+ let core = self.inner.borrow();
989
+ (
990
+ core.behavior.node_id.clone(),
991
+ core.persisted_state_adapters.clone(),
992
+ )
993
+ };
994
+ let Some(node_id) = node_id else {
995
+ return;
996
+ };
997
+ if node_id.is_empty() {
998
+ return;
999
+ }
1000
+ for adapter in adapters {
1001
+ let Some(payload) = adapter.capture() else {
1002
+ continue;
1003
+ };
1004
+ crate::persisted::store_text_state(
1005
+ &node_id,
1006
+ adapter.kind(),
1007
+ adapter.version(),
1008
+ &payload,
1009
+ );
1010
+ }
1011
+ }
1012
+
1013
+ fn restore_persisted_state(&self) {
1014
+ let (node_id, adapters) = {
1015
+ let core = self.inner.borrow();
1016
+ (
1017
+ core.behavior.node_id.clone(),
1018
+ core.persisted_state_adapters.clone(),
1019
+ )
1020
+ };
1021
+ let Some(node_id) = node_id else {
1022
+ return;
1023
+ };
1024
+ if node_id.is_empty() {
1025
+ return;
1026
+ }
1027
+ for adapter in adapters {
1028
+ let Some(persisted) = crate::persisted::try_load_text_state(&node_id, adapter.kind())
1029
+ else {
1030
+ continue;
1031
+ };
1032
+ adapter.restore(&persisted.payload, persisted.version);
1033
+ }
1034
+ }
1035
+
1036
+ pub(crate) fn long_press_minimum_duration_ms_for_routing(&self) -> i32 {
1037
+ self.inner.borrow().handlers.long_press_minimum_duration_ms
1038
+ }
1039
+
1040
+ pub(crate) fn long_press_movement_tolerance_for_routing(&self) -> f32 {
1041
+ self.inner.borrow().handlers.long_press_movement_tolerance
1042
+ }
1043
+
1044
+ pub(crate) fn handle_pointer_event(&self, event: &mut PointerEventArgs) {
1045
+ if !self.is_enabled_for_routing() {
1046
+ self.cancel_drag_state();
1047
+ return;
1048
+ }
1049
+ [event.x, event.y] = self.absolute_to_local_position(event.scene_x, event.scene_y);
1050
+ let handlers = {
1051
+ let core = self.inner.borrow();
1052
+ core.handlers.clone()
1053
+ };
1054
+ match event.event_type {
1055
+ crate::ffi::PointerEventType::Down => {
1056
+ crate::tool_tip_manager::ToolTipManager::handle_pointer_down(self);
1057
+ if let Some(handler) = handlers.pointer_down {
1058
+ handler(event);
1059
+ }
1060
+ if event.handled {
1061
+ return;
1062
+ }
1063
+ let drag_gesture = if self.has_drag_source() {
1064
+ Some(self.ensure_drag_gesture())
1065
+ } else {
1066
+ None
1067
+ };
1068
+ let is_primary_button = is_primary_activation_pointer(event);
1069
+ if let Some(drag_gesture) = drag_gesture {
1070
+ if is_primary_button {
1071
+ drag_gesture.borrow_mut().handle_pointer_down(
1072
+ event.x,
1073
+ event.y,
1074
+ event.modifiers,
1075
+ matches!(event.pointer_type, PointerType::Touch | PointerType::Pen),
1076
+ );
1077
+ let mut core = self.inner.borrow_mut();
1078
+ core.drag_click_pending = handlers.pointer_click.is_some();
1079
+ core.drag_click_pending_count = event.click_count;
1080
+ core.click_pending = false;
1081
+ core.click_pending_count = 0;
1082
+ return;
1083
+ }
1084
+ }
1085
+ let mut core = self.inner.borrow_mut();
1086
+ core.drag_click_pending = false;
1087
+ core.drag_click_pending_count = 0;
1088
+ core.click_pending =
1089
+ handlers.pointer_click.is_some() && is_primary_activation_pointer(event);
1090
+ core.click_pending_count = event.click_count;
1091
+ }
1092
+ crate::ffi::PointerEventType::Move => {
1093
+ crate::tool_tip_manager::ToolTipManager::handle_pointer_move(
1094
+ self,
1095
+ event.scene_x,
1096
+ event.scene_y,
1097
+ );
1098
+ if let Some(handler) = handlers.pointer_move {
1099
+ handler(event);
1100
+ }
1101
+ if event.handled {
1102
+ return;
1103
+ }
1104
+ let drag_gesture = self.inner.borrow().drag_gesture.clone();
1105
+ if let Some(drag_gesture) = drag_gesture {
1106
+ let has_drag_source = self.has_drag_source();
1107
+ let is_dragging = drag_gesture
1108
+ .try_borrow()
1109
+ .map(|gesture| gesture.is_dragging())
1110
+ .unwrap_or(true);
1111
+ if has_drag_source || is_dragging {
1112
+ if let Ok(mut gesture) = drag_gesture.try_borrow_mut() {
1113
+ gesture.handle_pointer_move(event.x, event.y, event.modifiers);
1114
+ }
1115
+ }
1116
+ }
1117
+ }
1118
+ crate::ffi::PointerEventType::Up => {
1119
+ if let Some(handler) = handlers.pointer_up {
1120
+ handler(event);
1121
+ }
1122
+ if event.handled {
1123
+ self.cancel_drag_state();
1124
+ return;
1125
+ }
1126
+ let drag_gesture = self.inner.borrow().drag_gesture.clone();
1127
+ let has_drag_source = self.has_drag_source();
1128
+ let drag_gesture_is_dragging = drag_gesture
1129
+ .as_ref()
1130
+ .map(|gesture| {
1131
+ gesture
1132
+ .try_borrow()
1133
+ .map(|gesture| gesture.is_dragging())
1134
+ .unwrap_or(true)
1135
+ })
1136
+ .unwrap_or(false);
1137
+ let drag_gesture_active = drag_gesture
1138
+ .as_ref()
1139
+ .map(|_| has_drag_source || drag_gesture_is_dragging)
1140
+ .unwrap_or(false);
1141
+ let (can_fire_pending_click, pending_click_count, can_fire_click, click_count) = {
1142
+ let core = self.inner.borrow();
1143
+ let can_fire_pending_click = core.drag_click_pending
1144
+ && (!drag_gesture_active || !drag_gesture_is_dragging);
1145
+ (
1146
+ can_fire_pending_click,
1147
+ core.drag_click_pending_count,
1148
+ core.click_pending,
1149
+ core.click_pending_count,
1150
+ )
1151
+ };
1152
+ if let Some(drag_gesture) = drag_gesture.as_ref() {
1153
+ if drag_gesture_active {
1154
+ if let Ok(mut gesture) = drag_gesture.try_borrow_mut() {
1155
+ gesture.handle_pointer_up(event.x, event.y, event.modifiers);
1156
+ }
1157
+ }
1158
+ }
1159
+ if can_fire_click {
1160
+ if let Some(handler) = handlers.pointer_click.clone() {
1161
+ event.click_count = if click_count > 0 { click_count } else { 1 };
1162
+ handler(event);
1163
+ }
1164
+ }
1165
+ self.clear_click_pending_state();
1166
+ if can_fire_pending_click {
1167
+ if let Some(handler) = handlers.pointer_click {
1168
+ event.click_count = if pending_click_count > 0 {
1169
+ pending_click_count
1170
+ } else {
1171
+ 1
1172
+ };
1173
+ handler(event);
1174
+ }
1175
+ }
1176
+ self.clear_drag_click_pending_state();
1177
+ }
1178
+ crate::ffi::PointerEventType::Enter => {
1179
+ if let Some(handler) = handlers.pointer_enter {
1180
+ handler(event);
1181
+ }
1182
+ if !event.handled {
1183
+ crate::tool_tip_manager::ToolTipManager::handle_pointer_enter(
1184
+ self,
1185
+ self.tool_tip_for_routing(),
1186
+ event.scene_x,
1187
+ event.scene_y,
1188
+ );
1189
+ }
1190
+ }
1191
+ crate::ffi::PointerEventType::Leave => {
1192
+ self.clear_pending_pointer_state();
1193
+ if let Some(handler) = handlers.pointer_leave {
1194
+ handler(event);
1195
+ }
1196
+ crate::tool_tip_manager::ToolTipManager::handle_pointer_leave(self);
1197
+ }
1198
+ crate::ffi::PointerEventType::Cancel => {
1199
+ self.cancel_drag_state();
1200
+ if let Some(handler) = handlers.pointer_cancel {
1201
+ handler(event);
1202
+ }
1203
+ crate::tool_tip_manager::ToolTipManager::handle_pointer_leave(self);
1204
+ }
1205
+ }
1206
+ }
1207
+
1208
+ fn cancel_drag_state(&self) {
1209
+ let gesture = {
1210
+ let mut core = self.inner.borrow_mut();
1211
+ core.drag_click_pending = false;
1212
+ core.drag_click_pending_count = 0;
1213
+ core.click_pending = false;
1214
+ core.click_pending_count = 0;
1215
+ core.drag_gesture.clone()
1216
+ };
1217
+ if let Some(gesture) = gesture {
1218
+ gesture.borrow_mut().cancel();
1219
+ }
1220
+ }
1221
+
1222
+ fn clear_pending_pointer_state(&self) {
1223
+ let Ok(mut core) = self.inner.try_borrow_mut() else {
1224
+ return;
1225
+ };
1226
+ core.drag_click_pending = false;
1227
+ core.drag_click_pending_count = 0;
1228
+ core.click_pending = false;
1229
+ core.click_pending_count = 0;
1230
+ }
1231
+
1232
+ fn clear_click_pending_state(&self) {
1233
+ let Ok(mut core) = self.inner.try_borrow_mut() else {
1234
+ return;
1235
+ };
1236
+ core.click_pending = false;
1237
+ core.click_pending_count = 0;
1238
+ }
1239
+
1240
+ fn clear_drag_click_pending_state(&self) {
1241
+ let Ok(mut core) = self.inner.try_borrow_mut() else {
1242
+ return;
1243
+ };
1244
+ core.drag_click_pending = false;
1245
+ core.drag_click_pending_count = 0;
1246
+ }
1247
+
1248
+ pub(crate) fn handle_bubbled_pointer_event(&self, event: &mut PointerEventArgs) {
1249
+ self.handle_pointer_event(event);
1250
+ }
1251
+
1252
+ pub(crate) fn handle_wheel_event(&self, event: &mut WheelEventArgs) {
1253
+ if !self.is_enabled_for_routing() || !self.is_visible_for_routing() {
1254
+ return;
1255
+ }
1256
+ [event.x, event.y] = self.absolute_to_local_position(event.scene_x, event.scene_y);
1257
+ if let Some(handler) = self.inner.borrow().handlers.wheel.clone() {
1258
+ handler(event);
1259
+ }
1260
+ }
1261
+
1262
+ pub(crate) fn handle_key_event(&self, event: &mut KeyEventArgs) {
1263
+ if !self.is_enabled_for_routing() {
1264
+ return;
1265
+ }
1266
+ let handlers = self.inner.borrow().handlers.clone();
1267
+ match event.event_type {
1268
+ crate::ffi::KeyEventType::Down => {
1269
+ if let Some(handler) = handlers.key_down {
1270
+ handler(event);
1271
+ }
1272
+ }
1273
+ crate::ffi::KeyEventType::Up => {
1274
+ if let Some(handler) = handlers.key_up {
1275
+ handler(event);
1276
+ }
1277
+ }
1278
+ }
1279
+ }
1280
+
1281
+ pub(crate) fn handle_focus_changed(&self, event: FocusChangedEventArgs) {
1282
+ let handler = self.inner.borrow().handlers.focus_changed.clone();
1283
+ if let Some(handler) = handler {
1284
+ handler(event);
1285
+ }
1286
+ crate::tool_tip_manager::ToolTipManager::handle_focus_changed(
1287
+ self,
1288
+ self.tool_tip_for_routing(),
1289
+ event.focused,
1290
+ );
1291
+ }
1292
+
1293
+ pub(crate) fn handle_scroll_changed(
1294
+ &self,
1295
+ offset_x: f32,
1296
+ offset_y: f32,
1297
+ content_width: f32,
1298
+ content_height: f32,
1299
+ viewport_width: f32,
1300
+ viewport_height: f32,
1301
+ ) {
1302
+ self.set_scroll_routing_metrics(
1303
+ offset_x,
1304
+ offset_y,
1305
+ content_width,
1306
+ content_height,
1307
+ viewport_width,
1308
+ viewport_height,
1309
+ );
1310
+ let handler = self.inner.borrow().handlers.scroll_changed.clone();
1311
+ if let Some(handler) = handler {
1312
+ handler(
1313
+ offset_x,
1314
+ offset_y,
1315
+ content_width,
1316
+ content_height,
1317
+ viewport_width,
1318
+ viewport_height,
1319
+ );
1320
+ }
1321
+ }
1322
+
1323
+ pub(crate) fn handle_selection_changed(&self, start: u32, end: u32) {
1324
+ let handler = self.inner.borrow().handlers.selection_changed.clone();
1325
+ if let Some(handler) = handler {
1326
+ handler(SelectionChangedEventArgs { start, end });
1327
+ }
1328
+ }
1329
+
1330
+ pub(crate) fn handle_text_changed(&self, text: String) {
1331
+ let handler = self.inner.borrow().handlers.text_changed.clone();
1332
+ if let Some(handler) = handler {
1333
+ handler(TextChangedEventArgs { text });
1334
+ }
1335
+ }
1336
+
1337
+ pub(crate) fn handle_text_replaced(&self, start: u32, end: u32, text: String) {
1338
+ let handler = self.inner.borrow().handlers.text_replaced.clone();
1339
+ if let Some(handler) = handler {
1340
+ handler(start, end, text);
1341
+ }
1342
+ }
1343
+
1344
+ pub(crate) fn handle_cross_selection_changed(&self, text: String) {
1345
+ let handler = self.inner.borrow().handlers.cross_selection_changed.clone();
1346
+ if let Some(handler) = handler {
1347
+ handler(text);
1348
+ }
1349
+ }
1350
+
1351
+ pub(crate) fn handle_gesture_event(&self, event: &mut GestureEventArgs) {
1352
+ if !self.is_enabled_for_routing() || !self.is_visible_for_routing() {
1353
+ return;
1354
+ }
1355
+ [event.x, event.y] = self.absolute_to_local_position(event.scene_x, event.scene_y);
1356
+ let handlers = self.inner.borrow().handlers.clone();
1357
+ match event.kind {
1358
+ crate::event::GestureEventKind::Pan => {
1359
+ if let Some(handler) = handlers.pan_gesture {
1360
+ handler(event);
1361
+ }
1362
+ }
1363
+ crate::event::GestureEventKind::Pinch => {
1364
+ if let Some(handler) = handlers.pinch_gesture {
1365
+ handler(event);
1366
+ }
1367
+ }
1368
+ crate::event::GestureEventKind::None => {}
1369
+ }
1370
+ }
1371
+
1372
+ pub(crate) fn handle_bubbled_gesture_event(&self, event: &mut GestureEventArgs) {
1373
+ self.handle_gesture_event(event);
1374
+ }
1375
+
1376
+ pub(crate) fn handle_long_press_event(&self, event: &mut LongPressEventArgs) {
1377
+ if !self.is_enabled_for_routing() || !self.is_visible_for_routing() {
1378
+ return;
1379
+ }
1380
+ [event.x, event.y] = self.absolute_to_local_position(event.scene_x, event.scene_y);
1381
+ if let Some(handler) = self.inner.borrow().handlers.long_press.clone() {
1382
+ handler(event);
1383
+ }
1384
+ if !event.handled
1385
+ && matches!(event.pointer_type, PointerType::Touch | PointerType::Pen)
1386
+ && self.has_drag_source()
1387
+ {
1388
+ event.handled = self.ensure_drag_gesture().borrow_mut().handle_long_press(
1389
+ event.x,
1390
+ event.y,
1391
+ event.modifiers,
1392
+ );
1393
+ }
1394
+ }
1395
+
1396
+ pub(crate) fn handle_bubbled_long_press_event(&self, event: &mut LongPressEventArgs) {
1397
+ self.handle_long_press_event(event);
1398
+ }
1399
+
1400
+ pub(crate) fn handle_custom_draw(&self, canvas_ptr: usize) {
1401
+ if let Some(callback) = self.inner.borrow().draw_callback.clone() {
1402
+ let mut context = DrawContext::new(canvas_ptr);
1403
+ callback(&mut context);
1404
+ }
1405
+ }
1406
+
1407
+ pub(crate) fn build(&self) {
1408
+ if let Some(callback) = self.build_callback.as_ref() {
1409
+ callback();
1410
+ }
1411
+ }
1412
+
1413
+ pub(crate) fn downgrade(&self) -> WeakNodeRef {
1414
+ WeakNodeRef {
1415
+ inner: Rc::downgrade(&self.inner),
1416
+ }
1417
+ }
1418
+
1419
+ pub(crate) fn ensure_drag_gesture(&self) -> Rc<RefCell<DragGesture>> {
1420
+ if let Some(gesture) = self.inner.borrow().drag_gesture.clone() {
1421
+ return gesture;
1422
+ }
1423
+ let weak = self.downgrade();
1424
+ let gesture = Rc::new(RefCell::new(DragGesture::new(self)));
1425
+ gesture.borrow_mut().threshold(4.0);
1426
+ gesture.borrow_mut().set_started({
1427
+ let weak = weak.clone();
1428
+ move |_event: DragStartedEvent| {
1429
+ if let Some(node) = weak.upgrade() {
1430
+ node.handle_drag_gesture_started();
1431
+ }
1432
+ }
1433
+ });
1434
+ gesture
1435
+ .borrow_mut()
1436
+ .set_completed(move |event: DragCompletedEvent| {
1437
+ if let Some(node) = weak.upgrade() {
1438
+ node.handle_drag_gesture_completed(event);
1439
+ }
1440
+ });
1441
+ self.inner.borrow_mut().drag_gesture = Some(gesture.clone());
1442
+ gesture
1443
+ }
1444
+
1445
+ fn handle_drag_gesture_started(&self) {
1446
+ if !crate::event::begin_drag_session(self.clone()) {
1447
+ if let Some(gesture) = self.inner.borrow().drag_gesture.clone() {
1448
+ gesture.borrow_mut().cancel();
1449
+ }
1450
+ }
1451
+ }
1452
+
1453
+ fn handle_drag_gesture_completed(&self, event: DragCompletedEvent) {
1454
+ let mut core = self.inner.borrow_mut();
1455
+ core.drag_click_pending = false;
1456
+ core.drag_click_pending_count = 0;
1457
+ drop(core);
1458
+ if event.cancelled {
1459
+ crate::event::cancel_drag_session_for_source(self);
1460
+ }
1461
+ }
1462
+
1463
+ pub(crate) fn has_drag_source(&self) -> bool {
1464
+ self.inner.borrow().drag_data_callback.is_some()
1465
+ }
1466
+
1467
+ pub(crate) fn create_drag_data_object(&self) -> Option<DragDataObject> {
1468
+ let callback = self.inner.borrow().drag_data_callback.clone();
1469
+ callback.and_then(|callback| callback())
1470
+ }
1471
+
1472
+ pub(crate) fn get_drag_allowed_effects(&self) -> DragDropEffects {
1473
+ self.inner.borrow().drag_allowed_effects
1474
+ }
1475
+
1476
+ pub(crate) fn notify_drag_completed(&self, effect: DragDropEffects) {
1477
+ let callback = self.inner.borrow().drag_completed_callback.clone();
1478
+ if let Some(callback) = callback {
1479
+ callback(DragCompletedEventArgs { effect });
1480
+ }
1481
+ }
1482
+
1483
+ pub(crate) fn allows_drop(&self) -> bool {
1484
+ self.inner.borrow().drop_allowed
1485
+ }
1486
+
1487
+ pub(crate) fn has_drag_enter_handler(&self) -> bool {
1488
+ self.inner.borrow().drag_enter_callback.is_some()
1489
+ }
1490
+
1491
+ pub(crate) fn has_drag_over_handler(&self) -> bool {
1492
+ self.inner.borrow().drag_over_callback.is_some()
1493
+ }
1494
+
1495
+ pub(crate) fn handle_drag_enter(&self, args: DragEventArgs) -> DropProposal {
1496
+ let callback = self.inner.borrow().drag_enter_callback.clone();
1497
+ callback
1498
+ .map(|callback| callback(args))
1499
+ .unwrap_or_else(DropProposal::none)
1500
+ }
1501
+
1502
+ pub(crate) fn handle_drag_over(&self, args: DragEventArgs) -> DropProposal {
1503
+ let callback = self.inner.borrow().drag_over_callback.clone();
1504
+ callback
1505
+ .map(|callback| callback(args))
1506
+ .unwrap_or_else(DropProposal::none)
1507
+ }
1508
+
1509
+ pub(crate) fn handle_drag_leave(&self, args: DragEventArgs) {
1510
+ let callback = self.inner.borrow().drag_leave_callback.clone();
1511
+ if let Some(callback) = callback {
1512
+ callback(args);
1513
+ }
1514
+ }
1515
+
1516
+ pub(crate) fn handle_drop_event(&self, args: DragEventArgs) {
1517
+ let callback = self.inner.borrow().drop_callback.clone();
1518
+ if let Some(callback) = callback {
1519
+ callback(args);
1520
+ }
1521
+ }
1522
+
1523
+ pub(crate) fn allows_external_drop(&self) -> bool {
1524
+ self.inner.borrow().behavior.external_drop_allowed
1525
+ }
1526
+
1527
+ pub(crate) fn has_external_drag_enter_handler(&self) -> bool {
1528
+ self.inner.borrow().external_drag_enter_callback.is_some()
1529
+ }
1530
+
1531
+ pub(crate) fn has_external_drag_over_handler(&self) -> bool {
1532
+ self.inner.borrow().external_drag_over_callback.is_some()
1533
+ }
1534
+
1535
+ pub(crate) fn handle_external_drag_enter(&self, args: ExternalDropEventArgs) -> DropProposal {
1536
+ let callback = self.inner.borrow().external_drag_enter_callback.clone();
1537
+ callback
1538
+ .map(|callback| callback(args))
1539
+ .unwrap_or_else(DropProposal::none)
1540
+ }
1541
+
1542
+ pub(crate) fn handle_external_drag_over(&self, args: ExternalDropEventArgs) -> DropProposal {
1543
+ let callback = self.inner.borrow().external_drag_over_callback.clone();
1544
+ callback
1545
+ .map(|callback| callback(args))
1546
+ .unwrap_or_else(DropProposal::none)
1547
+ }
1548
+
1549
+ pub(crate) fn handle_external_drag_leave(&self, args: ExternalDropEventArgs) {
1550
+ let callback = self.inner.borrow().external_drag_leave_callback.clone();
1551
+ if let Some(callback) = callback {
1552
+ callback(args);
1553
+ }
1554
+ }
1555
+
1556
+ pub(crate) fn handle_external_drop_event(&self, args: ExternalDropEventArgs) {
1557
+ let callback = self.inner.borrow().external_drop_callback.clone();
1558
+ if let Some(callback) = callback {
1559
+ callback(args);
1560
+ }
1561
+ }
1562
+ }
1563
+
1564
+ pub trait Node: Clone + 'static {
1565
+ #[doc(hidden)]
1566
+ fn node_ref(&self) -> NodeRef {
1567
+ self.retained_node_ref()
1568
+ }
1569
+ #[doc(hidden)]
1570
+ fn retained_node_ref(&self) -> NodeRef;
1571
+ #[doc(hidden)]
1572
+ fn retained_owner_attachment(&self) -> Option<Rc<dyn Any>> {
1573
+ None
1574
+ }
1575
+ #[doc(hidden)]
1576
+ fn build_self(&self);
1577
+
1578
+ fn node_id(&self, node_id: impl Into<String>) -> &Self
1579
+ where
1580
+ Self: Sized,
1581
+ {
1582
+ let node_ref = self.node_ref();
1583
+ node_ref.set_node_id(node_id);
1584
+ if self.has_built_handle() {
1585
+ self.notify_retained_mutation();
1586
+ }
1587
+ self
1588
+ }
1589
+
1590
+ fn semantic_role(&self, role: SemanticRole) -> &Self
1591
+ where
1592
+ Self: Sized,
1593
+ {
1594
+ let node_ref = self.node_ref();
1595
+ node_ref.inner.borrow_mut().behavior.semantic_role = Some(role);
1596
+ if self.has_built_handle() {
1597
+ ui::set_semantic_role(self.handle().raw(), role as u32);
1598
+ self.notify_retained_mutation();
1599
+ }
1600
+ self
1601
+ }
1602
+
1603
+ fn semantic_label(&self, label: impl Into<String>) -> &Self
1604
+ where
1605
+ Self: Sized,
1606
+ {
1607
+ let label = label.into();
1608
+ let node_ref = self.node_ref();
1609
+ node_ref.inner.borrow_mut().behavior.semantic_label = Some(label.clone());
1610
+ if self.has_built_handle() {
1611
+ ui::set_semantic_label(self.handle().raw(), &label);
1612
+ self.notify_retained_mutation();
1613
+ }
1614
+ self
1615
+ }
1616
+
1617
+ fn persist_state(&self, adapter: Rc<dyn PersistedStateAdapter>) -> &Self
1618
+ where
1619
+ Self: Sized,
1620
+ {
1621
+ self.node_ref().register_persisted_state_adapter(adapter);
1622
+ self
1623
+ }
1624
+
1625
+ fn handle(&self) -> NodeHandle {
1626
+ self.node_ref().inner.borrow().handle
1627
+ }
1628
+
1629
+ fn has_built_handle(&self) -> bool {
1630
+ self.handle() != NodeHandle::INVALID
1631
+ }
1632
+
1633
+ fn on_context_menu(&self, handler: impl Fn(ContextMenuEventArgs) + 'static) -> &Self
1634
+ where
1635
+ Self: Sized,
1636
+ {
1637
+ self.node_ref()
1638
+ .inner
1639
+ .borrow_mut()
1640
+ .behavior
1641
+ .context_menu_handler = Some(Rc::new(handler));
1642
+ self
1643
+ }
1644
+
1645
+ fn clear_context_menu(&self) -> &Self
1646
+ where
1647
+ Self: Sized,
1648
+ {
1649
+ self.node_ref()
1650
+ .inner
1651
+ .borrow_mut()
1652
+ .behavior
1653
+ .context_menu_handler = None;
1654
+ self
1655
+ }
1656
+
1657
+ fn disable_context_menu(&self, flag: bool) -> &Self
1658
+ where
1659
+ Self: Sized,
1660
+ {
1661
+ self.node_ref()
1662
+ .inner
1663
+ .borrow_mut()
1664
+ .behavior
1665
+ .context_menu_disabled = flag;
1666
+ self
1667
+ }
1668
+
1669
+ fn on_click(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self
1670
+ where
1671
+ Self: Sized,
1672
+ {
1673
+ let node_ref = self.node_ref();
1674
+ node_ref.inner.borrow_mut().handlers.pointer_click = Some(Rc::new(handler));
1675
+ node_ref.require_interactive();
1676
+ self
1677
+ }
1678
+
1679
+ fn on_pointer_down(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self
1680
+ where
1681
+ Self: Sized,
1682
+ {
1683
+ let node_ref = self.node_ref();
1684
+ node_ref.inner.borrow_mut().handlers.pointer_down = Some(Rc::new(handler));
1685
+ node_ref.require_interactive();
1686
+ self
1687
+ }
1688
+
1689
+ fn on_pointer_move(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self
1690
+ where
1691
+ Self: Sized,
1692
+ {
1693
+ let node_ref = self.node_ref();
1694
+ node_ref.inner.borrow_mut().handlers.pointer_move = Some(Rc::new(handler));
1695
+ node_ref.require_interactive();
1696
+ self
1697
+ }
1698
+
1699
+ fn on_pointer_up(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self
1700
+ where
1701
+ Self: Sized,
1702
+ {
1703
+ let node_ref = self.node_ref();
1704
+ node_ref.inner.borrow_mut().handlers.pointer_up = Some(Rc::new(handler));
1705
+ node_ref.require_interactive();
1706
+ self
1707
+ }
1708
+
1709
+ fn on_pointer_enter(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self
1710
+ where
1711
+ Self: Sized,
1712
+ {
1713
+ let node_ref = self.node_ref();
1714
+ node_ref.inner.borrow_mut().handlers.pointer_enter = Some(Rc::new(handler));
1715
+ node_ref.require_interactive();
1716
+ self
1717
+ }
1718
+
1719
+ fn on_pointer_leave(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self
1720
+ where
1721
+ Self: Sized,
1722
+ {
1723
+ let node_ref = self.node_ref();
1724
+ node_ref.inner.borrow_mut().handlers.pointer_leave = Some(Rc::new(handler));
1725
+ node_ref.require_interactive();
1726
+ self
1727
+ }
1728
+
1729
+ fn on_pointer_cancel(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self
1730
+ where
1731
+ Self: Sized,
1732
+ {
1733
+ let node_ref = self.node_ref();
1734
+ node_ref.inner.borrow_mut().handlers.pointer_cancel = Some(Rc::new(handler));
1735
+ node_ref.require_interactive();
1736
+ self
1737
+ }
1738
+
1739
+ fn on_wheel(&self, handler: impl Fn(&mut WheelEventArgs) + 'static) -> &Self
1740
+ where
1741
+ Self: Sized,
1742
+ {
1743
+ let node_ref = self.node_ref();
1744
+ node_ref.inner.borrow_mut().handlers.wheel = Some(Rc::new(handler));
1745
+ node_ref.require_interactive();
1746
+ self
1747
+ }
1748
+
1749
+ fn on_pan_gesture(&self, handler: impl Fn(&mut GestureEventArgs) + 'static) -> &Self
1750
+ where
1751
+ Self: Sized,
1752
+ {
1753
+ self.node_ref().inner.borrow_mut().handlers.pan_gesture = Some(Rc::new(handler));
1754
+ self
1755
+ }
1756
+
1757
+ fn on_pinch_gesture(&self, handler: impl Fn(&mut GestureEventArgs) + 'static) -> &Self
1758
+ where
1759
+ Self: Sized,
1760
+ {
1761
+ self.node_ref().inner.borrow_mut().handlers.pinch_gesture = Some(Rc::new(handler));
1762
+ self
1763
+ }
1764
+
1765
+ fn long_press_options(&self, minimum_duration_ms: i32, movement_tolerance: f32) -> &Self
1766
+ where
1767
+ Self: Sized,
1768
+ {
1769
+ let node_ref = self.node_ref();
1770
+ let mut core = node_ref.inner.borrow_mut();
1771
+ let handlers = &mut core.handlers;
1772
+ handlers.long_press_minimum_duration_ms = minimum_duration_ms.max(0);
1773
+ handlers.long_press_movement_tolerance = movement_tolerance.max(0.0);
1774
+ self
1775
+ }
1776
+
1777
+ fn on_long_press(&self, handler: impl Fn(&mut LongPressEventArgs) + 'static) -> &Self
1778
+ where
1779
+ Self: Sized,
1780
+ {
1781
+ let node_ref = self.node_ref();
1782
+ node_ref.inner.borrow_mut().handlers.long_press = Some(Rc::new(handler));
1783
+ node_ref.require_interactive();
1784
+ self
1785
+ }
1786
+
1787
+ fn focusable(&self, enabled: bool, tab_index: i32) -> &Self
1788
+ where
1789
+ Self: Sized,
1790
+ {
1791
+ let node_ref = self.node_ref();
1792
+ let mut core = node_ref.inner.borrow_mut();
1793
+ core.behavior.focusable = Some((enabled, tab_index));
1794
+ let interactive = core.behavior.enabled && core.behavior.inherited_enabled;
1795
+ let handle = core.handle;
1796
+ drop(core);
1797
+ if handle != NodeHandle::INVALID {
1798
+ ui::set_focusable(handle.raw(), interactive && enabled, tab_index);
1799
+ self.notify_retained_mutation();
1800
+ }
1801
+ self
1802
+ }
1803
+
1804
+ fn on_key_down(&self, handler: impl Fn(&mut KeyEventArgs) + 'static) -> &Self
1805
+ where
1806
+ Self: Sized,
1807
+ {
1808
+ self.node_ref().inner.borrow_mut().handlers.key_down = Some(Rc::new(handler));
1809
+ self
1810
+ }
1811
+
1812
+ fn on_key_up(&self, handler: impl Fn(&mut KeyEventArgs) + 'static) -> &Self
1813
+ where
1814
+ Self: Sized,
1815
+ {
1816
+ self.node_ref().inner.borrow_mut().handlers.key_up = Some(Rc::new(handler));
1817
+ self
1818
+ }
1819
+
1820
+ fn on_focus_changed(&self, handler: impl Fn(FocusChangedEventArgs) + 'static) -> &Self
1821
+ where
1822
+ Self: Sized,
1823
+ {
1824
+ self.node_ref().inner.borrow_mut().handlers.focus_changed = Some(Rc::new(handler));
1825
+ self
1826
+ }
1827
+
1828
+ fn drag_allowed_effects(&self, effects: DragDropEffects) -> &Self
1829
+ where
1830
+ Self: Sized,
1831
+ {
1832
+ self.node_ref().inner.borrow_mut().drag_allowed_effects = effects;
1833
+ self
1834
+ }
1835
+
1836
+ fn drag_data(&self, handler: impl Fn() -> Option<DragDataObject> + 'static) -> &Self
1837
+ where
1838
+ Self: Sized,
1839
+ {
1840
+ let node_ref = self.node_ref();
1841
+ node_ref.inner.borrow_mut().drag_data_callback = Some(Rc::new(handler));
1842
+ node_ref.require_interactive();
1843
+ node_ref.ensure_drag_gesture();
1844
+ self
1845
+ }
1846
+
1847
+ fn clear_drag_data(&self) -> &Self
1848
+ where
1849
+ Self: Sized,
1850
+ {
1851
+ self.node_ref().inner.borrow_mut().drag_data_callback = None;
1852
+ self
1853
+ }
1854
+
1855
+ fn allow_drop(&self, flag: bool) -> &Self
1856
+ where
1857
+ Self: Sized,
1858
+ {
1859
+ let node_ref = self.node_ref();
1860
+ node_ref.inner.borrow_mut().drop_allowed = flag;
1861
+ if flag {
1862
+ node_ref.require_interactive();
1863
+ }
1864
+ self
1865
+ }
1866
+
1867
+ fn on_drag_completed(&self, handler: impl Fn(DragCompletedEventArgs) + 'static) -> &Self
1868
+ where
1869
+ Self: Sized,
1870
+ {
1871
+ self.node_ref().inner.borrow_mut().drag_completed_callback = Some(Rc::new(handler));
1872
+ self
1873
+ }
1874
+
1875
+ fn on_drag_enter(&self, handler: impl Fn(DragEventArgs) -> DropProposal + 'static) -> &Self
1876
+ where
1877
+ Self: Sized,
1878
+ {
1879
+ let node_ref = self.node_ref();
1880
+ node_ref.inner.borrow_mut().drag_enter_callback = Some(Rc::new(handler));
1881
+ self.allow_drop(true);
1882
+ node_ref.require_interactive();
1883
+ self
1884
+ }
1885
+
1886
+ fn on_drag_over(&self, handler: impl Fn(DragEventArgs) -> DropProposal + 'static) -> &Self
1887
+ where
1888
+ Self: Sized,
1889
+ {
1890
+ let node_ref = self.node_ref();
1891
+ node_ref.inner.borrow_mut().drag_over_callback = Some(Rc::new(handler));
1892
+ self.allow_drop(true);
1893
+ node_ref.require_interactive();
1894
+ self
1895
+ }
1896
+
1897
+ fn on_drag_leave(&self, handler: impl Fn(DragEventArgs) + 'static) -> &Self
1898
+ where
1899
+ Self: Sized,
1900
+ {
1901
+ let node_ref = self.node_ref();
1902
+ node_ref.inner.borrow_mut().drag_leave_callback = Some(Rc::new(handler));
1903
+ self.allow_drop(true);
1904
+ node_ref.require_interactive();
1905
+ self
1906
+ }
1907
+
1908
+ fn on_drop(&self, handler: impl Fn(DragEventArgs) + 'static) -> &Self
1909
+ where
1910
+ Self: Sized,
1911
+ {
1912
+ let node_ref = self.node_ref();
1913
+ node_ref.inner.borrow_mut().drop_callback = Some(Rc::new(handler));
1914
+ self.allow_drop(true);
1915
+ node_ref.require_interactive();
1916
+ self
1917
+ }
1918
+
1919
+ fn allow_external_drop(&self, flag: bool) -> &Self
1920
+ where
1921
+ Self: Sized,
1922
+ {
1923
+ let node_ref = self.node_ref();
1924
+ node_ref.inner.borrow_mut().behavior.external_drop_allowed = flag;
1925
+ if flag {
1926
+ node_ref.require_interactive();
1927
+ }
1928
+ self
1929
+ }
1930
+
1931
+ fn on_external_drag_enter(
1932
+ &self,
1933
+ handler: impl Fn(ExternalDropEventArgs) -> DropProposal + 'static,
1934
+ ) -> &Self
1935
+ where
1936
+ Self: Sized,
1937
+ {
1938
+ let node_ref = self.node_ref();
1939
+ node_ref.inner.borrow_mut().external_drag_enter_callback = Some(Rc::new(handler));
1940
+ self.allow_external_drop(true);
1941
+ node_ref.require_interactive();
1942
+ self
1943
+ }
1944
+
1945
+ fn on_external_drag_over(
1946
+ &self,
1947
+ handler: impl Fn(ExternalDropEventArgs) -> DropProposal + 'static,
1948
+ ) -> &Self
1949
+ where
1950
+ Self: Sized,
1951
+ {
1952
+ let node_ref = self.node_ref();
1953
+ node_ref.inner.borrow_mut().external_drag_over_callback = Some(Rc::new(handler));
1954
+ self.allow_external_drop(true);
1955
+ node_ref.require_interactive();
1956
+ self
1957
+ }
1958
+
1959
+ fn on_external_drag_leave(&self, handler: impl Fn(ExternalDropEventArgs) + 'static) -> &Self
1960
+ where
1961
+ Self: Sized,
1962
+ {
1963
+ let node_ref = self.node_ref();
1964
+ node_ref.inner.borrow_mut().external_drag_leave_callback = Some(Rc::new(handler));
1965
+ self.allow_external_drop(true);
1966
+ node_ref.require_interactive();
1967
+ self
1968
+ }
1969
+
1970
+ fn on_external_drop(&self, handler: impl Fn(ExternalDropEventArgs) + 'static) -> &Self
1971
+ where
1972
+ Self: Sized,
1973
+ {
1974
+ let node_ref = self.node_ref();
1975
+ node_ref.inner.borrow_mut().external_drop_callback = Some(Rc::new(handler));
1976
+ self.allow_external_drop(true);
1977
+ node_ref.require_interactive();
1978
+ self
1979
+ }
1980
+
1981
+ fn get_bounds(&self) -> [f32; 4] {
1982
+ if !self.has_built_handle() {
1983
+ return [0.0; 4];
1984
+ }
1985
+ ui::get_bounds(self.handle().raw()).unwrap_or([0.0; 4])
1986
+ }
1987
+
1988
+ fn absolute_to_local_position(&self, absolute_x: f32, absolute_y: f32) -> [f32; 2] {
1989
+ let bounds = self.get_bounds();
1990
+ [absolute_x - bounds[0], absolute_y - bounds[1]]
1991
+ }
1992
+
1993
+ fn local_to_absolute_position(&self, local_x: f32, local_y: f32) -> [f32; 2] {
1994
+ let bounds = self.get_bounds();
1995
+ [bounds[0] + local_x, bounds[1] + local_y]
1996
+ }
1997
+
1998
+ fn ensure_handle(&self) {
1999
+ if self.has_built_handle() {
2000
+ return;
2001
+ }
2002
+ let node_ref = self.node_ref();
2003
+ let node_type = node_ref.inner.borrow().kind.node_type();
2004
+ let handle = NodeHandle(ui::create_node(node_type as u32));
2005
+ {
2006
+ let mut core = node_ref.inner.borrow_mut();
2007
+ core.handle = handle;
2008
+ core.mounted = true;
2009
+ }
2010
+ crate::event::register_node(&node_ref);
2011
+ }
2012
+
2013
+ fn build(&self) {
2014
+ self.ensure_handle();
2015
+ self.build_self();
2016
+ self.build_children();
2017
+ }
2018
+
2019
+ fn dispose(&self) {
2020
+ self.node_ref().dispose();
2021
+ }
2022
+
2023
+ fn build_children(&self) {
2024
+ let node_ref = self.node_ref();
2025
+ {
2026
+ let mut core = node_ref.inner.borrow_mut();
2027
+ if core.children_built {
2028
+ return;
2029
+ }
2030
+ core.children_built = true;
2031
+ }
2032
+ let children = node_ref.inner.borrow().children.clone();
2033
+ for child in children {
2034
+ child.build();
2035
+ ui::add_child(self.handle().raw(), child.handle().raw());
2036
+ }
2037
+ }
2038
+
2039
+ fn append_child<T: Node>(&self, child: &T) {
2040
+ let self_node_ref = self.node_ref();
2041
+ let child_node_ref = child.node_ref();
2042
+ if Rc::ptr_eq(&self_node_ref.inner, &child_node_ref.inner) {
2043
+ return;
2044
+ }
2045
+ if self_node_ref
2046
+ .inner
2047
+ .borrow()
2048
+ .children
2049
+ .iter()
2050
+ .any(|candidate| Rc::ptr_eq(&candidate.inner, &child_node_ref.inner))
2051
+ {
2052
+ return;
2053
+ }
2054
+ if let Some(previous_parent) = child_node_ref.inner.borrow().parent.upgrade() {
2055
+ if Rc::ptr_eq(&previous_parent, &self_node_ref.inner) {
2056
+ return;
2057
+ }
2058
+ let child_handle = child.handle();
2059
+ {
2060
+ let mut previous_parent_core = previous_parent.borrow_mut();
2061
+ previous_parent_core
2062
+ .children
2063
+ .retain(|candidate| !Rc::ptr_eq(&candidate.inner, &child_node_ref.inner));
2064
+ }
2065
+ if previous_parent.borrow().handle != NodeHandle::INVALID
2066
+ && child_handle != NodeHandle::INVALID
2067
+ {
2068
+ ui::remove_child(previous_parent.borrow().handle.raw(), child_handle.raw());
2069
+ }
2070
+ }
2071
+
2072
+ {
2073
+ let mut child_core = child_node_ref.inner.borrow_mut();
2074
+ child_core.parent = Rc::downgrade(&self_node_ref.inner);
2075
+ }
2076
+ child_node_ref.set_inherited_enabled(self_node_ref.is_enabled_for_routing());
2077
+ self_node_ref
2078
+ .inner
2079
+ .borrow_mut()
2080
+ .children
2081
+ .push(child_node_ref.clone());
2082
+ if let Some(owner) = child.retained_owner_attachment() {
2083
+ self_node_ref
2084
+ .inner
2085
+ .borrow_mut()
2086
+ .retained_attachments
2087
+ .push(owner);
2088
+ }
2089
+ self_node_ref.inner.borrow_mut().children_built = false;
2090
+ if self.has_built_handle() {
2091
+ child.build();
2092
+ ui::add_child(self.handle().raw(), child.handle().raw());
2093
+ self_node_ref.inner.borrow_mut().children_built = true;
2094
+ self.notify_retained_mutation();
2095
+ self.notify_retained_child_layout_changed();
2096
+ }
2097
+ }
2098
+
2099
+ fn remove_child<T: Node>(&self, child: &T) -> bool {
2100
+ let child_handle = child.handle();
2101
+ let child_node_ref = child.node_ref();
2102
+ let removed = {
2103
+ let self_node_ref = self.node_ref();
2104
+ let mut core = self_node_ref.inner.borrow_mut();
2105
+ let Some(index) = core
2106
+ .children
2107
+ .iter()
2108
+ .position(|candidate| Rc::ptr_eq(&candidate.inner, &child_node_ref.inner))
2109
+ else {
2110
+ return false;
2111
+ };
2112
+ core.children.remove(index)
2113
+ };
2114
+ removed.inner.borrow_mut().parent = Weak::new();
2115
+ removed.set_inherited_enabled(true);
2116
+ self.node_ref().inner.borrow_mut().children_built = false;
2117
+ if self.has_built_handle() && child.has_built_handle() {
2118
+ ui::remove_child(self.handle().raw(), child_handle.raw());
2119
+ self.node_ref().inner.borrow_mut().children_built = true;
2120
+ self.notify_retained_mutation();
2121
+ self.notify_retained_child_layout_changed();
2122
+ }
2123
+ true
2124
+ }
2125
+
2126
+ fn parent_handle(&self) -> Option<NodeHandle> {
2127
+ self.node_ref()
2128
+ .inner
2129
+ .borrow()
2130
+ .parent
2131
+ .upgrade()
2132
+ .map(|parent| parent.borrow().handle)
2133
+ }
2134
+
2135
+ fn notify_retained_layout_mutation(&self) {
2136
+ self.notify_retained_mutation();
2137
+ }
2138
+
2139
+ fn notify_retained_mutation(&self) {
2140
+ crate::frame_scheduler::mark_needs_commit();
2141
+ }
2142
+
2143
+ fn notify_retained_child_layout_changed(&self) {}
2144
+
2145
+ #[doc(hidden)]
2146
+ fn bind_scroll_proxy_target_handle(&self, scroll_handle: u64) -> &Self
2147
+ where
2148
+ Self: Sized,
2149
+ {
2150
+ let node_ref = self.node_ref();
2151
+ node_ref.inner.borrow_mut().behavior.scroll_proxy_target = Some(scroll_handle);
2152
+ if self.has_built_handle() {
2153
+ ui::set_scroll_proxy_target(self.handle().raw(), scroll_handle);
2154
+ self.notify_retained_mutation();
2155
+ }
2156
+ self
2157
+ }
2158
+
2159
+ fn preserve_selection_on_pointer_down(&self, preserve: bool) -> &Self
2160
+ where
2161
+ Self: Sized,
2162
+ {
2163
+ let node_ref = self.node_ref();
2164
+ node_ref
2165
+ .inner
2166
+ .borrow_mut()
2167
+ .behavior
2168
+ .preserve_selection_on_pointer_down = preserve;
2169
+ if self.has_built_handle() {
2170
+ ui::set_preserve_selection_on_pointer_down(self.handle().raw(), preserve);
2171
+ self.notify_retained_mutation();
2172
+ }
2173
+ self
2174
+ }
2175
+
2176
+ fn tool_tip(&self, tool_tip: ToolTip) -> &Self
2177
+ where
2178
+ Self: Sized,
2179
+ {
2180
+ let node_ref = self.node_ref();
2181
+ node_ref.inner.borrow_mut().behavior.tool_tip = Some(tool_tip.clone());
2182
+ node_ref.require_interactive();
2183
+ if self.has_built_handle()
2184
+ && node_ref.is_enabled_for_routing()
2185
+ && node_ref.is_visible_for_routing()
2186
+ {
2187
+ ui::set_interactive(self.handle().raw(), true);
2188
+ self.notify_retained_mutation();
2189
+ }
2190
+ crate::tool_tip_manager::ToolTipManager::handle_tool_tip_changed(&node_ref, Some(tool_tip));
2191
+ self
2192
+ }
2193
+
2194
+ fn tool_tip_text(&self, text: impl Into<String>) -> &Self
2195
+ where
2196
+ Self: Sized,
2197
+ {
2198
+ self.tool_tip(ToolTip::text(text))
2199
+ }
2200
+
2201
+ fn clear_tool_tip(&self) -> &Self
2202
+ where
2203
+ Self: Sized,
2204
+ {
2205
+ let node_ref = self.node_ref();
2206
+ node_ref.inner.borrow_mut().behavior.tool_tip = None;
2207
+ crate::tool_tip_manager::ToolTipManager::handle_tool_tip_changed(&node_ref, None);
2208
+ self
2209
+ }
2210
+ }