@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,874 @@
1
+ use super::core::*;
2
+ use super::*;
3
+ use crate::animation::{animate_color, animate_float, Animation};
4
+ use crate::transitions::NodeTransitions;
5
+
6
+ #[derive(Default)]
7
+ pub(crate) struct FlexBoxAnimations {
8
+ pub(crate) opacity: Option<Animation>,
9
+ pub(crate) background_color: Option<Animation>,
10
+ }
11
+
12
+ #[derive(Clone)]
13
+ pub struct FlexBox {
14
+ pub(crate) core: Rc<RefCell<NodeCore>>,
15
+ pub(crate) props: Rc<RefCell<FlexBoxProps>>,
16
+ pub(crate) active_animations: Rc<RefCell<FlexBoxAnimations>>,
17
+ }
18
+
19
+ impl Default for FlexBox {
20
+ fn default() -> Self {
21
+ let mut core = NodeCore::new(NodeKind::FlexBox);
22
+ core.behavior.clip_to_bounds = Some(true);
23
+ Self {
24
+ core: Rc::new(RefCell::new(core)),
25
+ props: Rc::new(RefCell::new(FlexBoxProps::default())),
26
+ active_animations: Rc::new(RefCell::new(FlexBoxAnimations::default())),
27
+ }
28
+ }
29
+ }
30
+
31
+ impl Node for FlexBox {
32
+ fn retained_node_ref(&self) -> NodeRef {
33
+ NodeRef::from_node(self.core.clone(), self.clone())
34
+ }
35
+
36
+ fn build_self(&self) {
37
+ let props = self.props.borrow().clone();
38
+ let behavior = self.core.borrow().behavior.clone();
39
+ apply_flex_box_props(self.handle(), &props, behavior);
40
+ }
41
+ }
42
+
43
+ #[derive(Clone, Copy, Debug, PartialEq)]
44
+ pub struct Border {
45
+ pub width: f32,
46
+ pub color: u32,
47
+ pub style: BorderStyle,
48
+ pub dash_on: f32,
49
+ pub dash_off: f32,
50
+ }
51
+
52
+ impl Border {
53
+ pub fn solid(width: f32, color: u32) -> Self {
54
+ Self {
55
+ width,
56
+ color,
57
+ style: BorderStyle::Solid,
58
+ dash_on: 0.0,
59
+ dash_off: 0.0,
60
+ }
61
+ }
62
+
63
+ pub fn dashed(width: f32, color: u32, dash_on: f32, dash_off: f32) -> Self {
64
+ Self {
65
+ width,
66
+ color,
67
+ style: BorderStyle::Dashed,
68
+ dash_on,
69
+ dash_off,
70
+ }
71
+ }
72
+
73
+ pub fn dotted(width: f32, color: u32, dash_on: f32, dash_off: f32) -> Self {
74
+ Self {
75
+ width,
76
+ color,
77
+ style: BorderStyle::Dotted,
78
+ dash_on,
79
+ dash_off,
80
+ }
81
+ }
82
+ }
83
+
84
+ #[derive(Clone, Copy, Debug, PartialEq)]
85
+ pub struct GradientStop {
86
+ pub offset: f32,
87
+ pub color: u32,
88
+ }
89
+
90
+ impl GradientStop {
91
+ pub fn new(offset: f32, color: u32) -> Self {
92
+ Self { offset, color }
93
+ }
94
+ }
95
+
96
+ impl FlexBox {
97
+ pub(crate) fn downgrade(&self) -> WeakFlexBox {
98
+ WeakFlexBox {
99
+ core: Rc::downgrade(&self.core),
100
+ props: Rc::downgrade(&self.props),
101
+ active_animations: Rc::downgrade(&self.active_animations),
102
+ }
103
+ }
104
+
105
+ pub fn key(&self, _key: u64) -> &Self {
106
+ self
107
+ }
108
+
109
+ pub fn width(&self, width: f32, unit: Unit) -> &Self {
110
+ self.props.borrow_mut().width = Some((width, unit));
111
+ {
112
+ let mut core = self.core.borrow_mut();
113
+ core.behavior.fill_width = false;
114
+ core.behavior.fill_width_percent = None;
115
+ }
116
+ if self.has_built_handle() {
117
+ ui::set_width(self.handle().raw(), width, unit as u32);
118
+ self.notify_retained_layout_mutation();
119
+ }
120
+ self
121
+ }
122
+
123
+ pub fn width_len(&self, length: Length) -> &Self {
124
+ let (width, unit) = length;
125
+ self.width(width, unit)
126
+ }
127
+
128
+ pub fn height(&self, height: f32, unit: Unit) -> &Self {
129
+ self.props.borrow_mut().height = Some((height, unit));
130
+ {
131
+ let mut core = self.core.borrow_mut();
132
+ core.behavior.fill_height = false;
133
+ core.behavior.fill_height_percent = None;
134
+ }
135
+ if self.has_built_handle() {
136
+ ui::set_height(self.handle().raw(), height, unit as u32);
137
+ self.notify_retained_layout_mutation();
138
+ }
139
+ self
140
+ }
141
+
142
+ pub fn height_len(&self, length: Length) -> &Self {
143
+ let (height, unit) = length;
144
+ self.height(height, unit)
145
+ }
146
+
147
+ pub fn fill_width(&self) -> &Self {
148
+ self.props.borrow_mut().width = None;
149
+ {
150
+ let mut core = self.core.borrow_mut();
151
+ core.behavior.fill_width = true;
152
+ core.behavior.fill_width_percent = None;
153
+ }
154
+ if self.has_built_handle() {
155
+ ui::set_fill_width(self.handle().raw(), true);
156
+ self.notify_retained_layout_mutation();
157
+ }
158
+ self
159
+ }
160
+
161
+ pub fn fill_height(&self) -> &Self {
162
+ self.props.borrow_mut().height = None;
163
+ {
164
+ let mut core = self.core.borrow_mut();
165
+ core.behavior.fill_height = true;
166
+ core.behavior.fill_height_percent = None;
167
+ }
168
+ if self.has_built_handle() {
169
+ ui::set_fill_height(self.handle().raw(), true);
170
+ self.notify_retained_layout_mutation();
171
+ }
172
+ self
173
+ }
174
+
175
+ pub fn fill_size(&self) -> &Self {
176
+ self.fill_width();
177
+ self.fill_height();
178
+ self
179
+ }
180
+
181
+ pub fn fill_width_percent(&self, percent: f32) -> &Self {
182
+ self.props.borrow_mut().width = None;
183
+ {
184
+ let mut core = self.core.borrow_mut();
185
+ core.behavior.fill_width = false;
186
+ core.behavior.fill_width_percent = Some(percent);
187
+ }
188
+ if self.has_built_handle() {
189
+ ui::set_fill_width_percent(self.handle().raw(), percent);
190
+ self.notify_retained_layout_mutation();
191
+ }
192
+ self
193
+ }
194
+
195
+ pub fn fill_height_percent(&self, percent: f32) -> &Self {
196
+ self.props.borrow_mut().height = None;
197
+ {
198
+ let mut core = self.core.borrow_mut();
199
+ core.behavior.fill_height = false;
200
+ core.behavior.fill_height_percent = Some(percent);
201
+ }
202
+ if self.has_built_handle() {
203
+ ui::set_fill_height_percent(self.handle().raw(), percent);
204
+ self.notify_retained_layout_mutation();
205
+ }
206
+ self
207
+ }
208
+
209
+ pub fn bg_color(&self, color: u32) -> &Self {
210
+ self.cancel_background_color_transition();
211
+ if self.should_animate_background_color(color) {
212
+ let timing = {
213
+ self.props
214
+ .borrow()
215
+ .transitions
216
+ .as_ref()
217
+ .and_then(NodeTransitions::background_color_timing)
218
+ };
219
+ if let Some(timing) = timing {
220
+ let weak = self.downgrade();
221
+ let from = self.current_background_color();
222
+ let animation = animate_color(from, color, timing, move |value| {
223
+ if let Some(node) = weak.upgrade() {
224
+ node.apply_animated_background_color(value);
225
+ }
226
+ });
227
+ self.active_animations.borrow_mut().background_color = Some(animation);
228
+ return self;
229
+ }
230
+ }
231
+ self.apply_animated_background_color(color);
232
+ self
233
+ }
234
+
235
+ pub fn padding(&self, left: f32, top: f32, right: f32, bottom: f32) -> &Self {
236
+ self.props.borrow_mut().padding = Some((left, top, right, bottom));
237
+ if self.has_built_handle() {
238
+ ui::set_padding(self.handle().raw(), left, top, right, bottom);
239
+ self.notify_retained_layout_mutation();
240
+ }
241
+ self
242
+ }
243
+
244
+ pub fn flex_direction(&self, direction: FlexDirection) -> &Self {
245
+ self.props.borrow_mut().flex_direction = Some(direction);
246
+ if self.has_built_handle() {
247
+ ui::set_flex_direction(self.handle().raw(), direction as u32);
248
+ self.notify_retained_layout_mutation();
249
+ }
250
+ self
251
+ }
252
+
253
+ pub fn corner_radius(&self, radius: f32) -> &Self {
254
+ self.corners(radius, radius, radius, radius)
255
+ }
256
+
257
+ pub fn corners(&self, tl: f32, tr: f32, br: f32, bl: f32) -> &Self {
258
+ let existing = self.props.borrow().box_style.unwrap_or(BoxStyle {
259
+ radius_tl: 0.0,
260
+ radius_tr: 0.0,
261
+ radius_br: 0.0,
262
+ radius_bl: 0.0,
263
+ border_width: 0.0,
264
+ border_color: 0,
265
+ border_style: BorderStyle::Solid,
266
+ border_dash_on: 0.0,
267
+ border_dash_off: 0.0,
268
+ });
269
+ self.props.borrow_mut().box_style = Some(BoxStyle {
270
+ radius_tl: tl,
271
+ radius_tr: tr,
272
+ radius_br: br,
273
+ radius_bl: bl,
274
+ ..existing
275
+ });
276
+ if self.has_built_handle() {
277
+ self.build_self();
278
+ self.notify_retained_mutation();
279
+ }
280
+ self
281
+ }
282
+
283
+ pub fn border(&self, width: f32, color: u32) -> &Self {
284
+ self.border_config(Border::solid(width, color))
285
+ }
286
+
287
+ pub fn border_config(&self, border: Border) -> &Self {
288
+ let existing = self.props.borrow().box_style.unwrap_or(BoxStyle {
289
+ radius_tl: 0.0,
290
+ radius_tr: 0.0,
291
+ radius_br: 0.0,
292
+ radius_bl: 0.0,
293
+ border_width: 0.0,
294
+ border_color: 0,
295
+ border_style: BorderStyle::Solid,
296
+ border_dash_on: 0.0,
297
+ border_dash_off: 0.0,
298
+ });
299
+ self.props.borrow_mut().box_style = Some(BoxStyle {
300
+ border_width: border.width,
301
+ border_color: border.color,
302
+ border_style: border.style,
303
+ border_dash_on: border.dash_on,
304
+ border_dash_off: border.dash_off,
305
+ ..existing
306
+ });
307
+ if self.has_built_handle() {
308
+ self.build_self();
309
+ self.notify_retained_mutation();
310
+ }
311
+ self
312
+ }
313
+
314
+ pub fn opacity(&self, value: f32) -> &Self {
315
+ let value = value.clamp(0.0, 1.0);
316
+ self.cancel_opacity_transition();
317
+ if self.should_animate_opacity(value) {
318
+ let timing = {
319
+ self.props
320
+ .borrow()
321
+ .transitions
322
+ .as_ref()
323
+ .and_then(NodeTransitions::opacity_timing)
324
+ };
325
+ if let Some(timing) = timing {
326
+ let weak = self.downgrade();
327
+ let from = self.current_opacity();
328
+ let animation = animate_float(from, value, timing, move |next| {
329
+ if let Some(node) = weak.upgrade() {
330
+ node.apply_animated_opacity(next);
331
+ }
332
+ });
333
+ self.active_animations.borrow_mut().opacity = Some(animation);
334
+ return self;
335
+ }
336
+ }
337
+ self.apply_animated_opacity(value);
338
+ self
339
+ }
340
+
341
+ pub fn transitions(&self, transitions: Option<NodeTransitions>) -> &Self {
342
+ self.props.borrow_mut().transitions = transitions;
343
+ self
344
+ }
345
+
346
+ pub fn blur(&self, sigma: f32) -> &Self {
347
+ self.props.borrow_mut().blur_sigma = Some(sigma.max(0.0));
348
+ if self.has_built_handle() {
349
+ self.build_self();
350
+ self.notify_retained_mutation();
351
+ }
352
+ self
353
+ }
354
+
355
+ pub fn drop_shadow(
356
+ &self,
357
+ color: u32,
358
+ offset_x: f32,
359
+ offset_y: f32,
360
+ blur_sigma: f32,
361
+ spread: f32,
362
+ ) -> &Self {
363
+ self.props.borrow_mut().drop_shadow = Some(DropShadow {
364
+ color,
365
+ offset_x,
366
+ offset_y,
367
+ blur_sigma: blur_sigma.max(0.0),
368
+ spread,
369
+ });
370
+ if self.has_built_handle() {
371
+ self.build_self();
372
+ self.notify_retained_mutation();
373
+ }
374
+ self
375
+ }
376
+
377
+ pub fn background_blur(&self, sigma: f32) -> &Self {
378
+ self.props.borrow_mut().background_blur_sigma = Some(sigma.max(0.0));
379
+ if self.has_built_handle() {
380
+ self.build_self();
381
+ self.notify_retained_mutation();
382
+ }
383
+ self
384
+ }
385
+
386
+ pub fn linear_gradient(
387
+ &self,
388
+ sx: f32,
389
+ sy: f32,
390
+ ex: f32,
391
+ ey: f32,
392
+ offsets: Vec<f32>,
393
+ colors: Vec<u32>,
394
+ ) -> &Self {
395
+ self.props.borrow_mut().linear_gradient = Some(LinearGradient {
396
+ sx,
397
+ sy,
398
+ ex,
399
+ ey,
400
+ offsets,
401
+ colors,
402
+ });
403
+ if self.has_built_handle() {
404
+ self.build_self();
405
+ self.notify_retained_mutation();
406
+ }
407
+ self
408
+ }
409
+
410
+ pub fn linear_gradient_stops(
411
+ &self,
412
+ sx: f32,
413
+ sy: f32,
414
+ ex: f32,
415
+ ey: f32,
416
+ stops: Vec<GradientStop>,
417
+ ) -> &Self {
418
+ let mut offsets = Vec::with_capacity(stops.len());
419
+ let mut colors = Vec::with_capacity(stops.len());
420
+ for stop in stops {
421
+ offsets.push(stop.offset);
422
+ colors.push(stop.color);
423
+ }
424
+ self.linear_gradient(sx, sy, ex, ey, offsets, colors)
425
+ }
426
+
427
+ pub fn interactive(&self, interactive: bool) -> &Self {
428
+ let mut core = self.core.borrow_mut();
429
+ core.behavior.interactive = interactive;
430
+ let enabled = core.behavior.enabled && core.behavior.inherited_enabled;
431
+ let has_built_handle = core.handle != NodeHandle::INVALID;
432
+ drop(core);
433
+ if has_built_handle {
434
+ ui::set_interactive(self.handle().raw(), enabled && interactive);
435
+ self.notify_retained_mutation();
436
+ }
437
+ self
438
+ }
439
+
440
+ pub fn enabled(&self, enabled: bool) -> &Self {
441
+ self.retained_node_ref().set_own_enabled(enabled);
442
+ self
443
+ }
444
+
445
+ pub(crate) fn reflect_semantic_disabled_from_enabled(&self) -> &Self {
446
+ let mut core = self.core.borrow_mut();
447
+ core.behavior.track_semantic_disabled_from_enabled = true;
448
+ let enabled = core.behavior.enabled && core.behavior.inherited_enabled;
449
+ let has_built_handle = core.handle != NodeHandle::INVALID;
450
+ drop(core);
451
+ if has_built_handle {
452
+ ui::set_semantic_disabled(self.handle().raw(), true, !enabled);
453
+ self.notify_retained_mutation();
454
+ }
455
+ self
456
+ }
457
+
458
+ pub fn focusable(&self, enabled: bool, tab_index: i32) -> &Self {
459
+ let mut core = self.core.borrow_mut();
460
+ core.behavior.focusable = Some((enabled, tab_index));
461
+ let interactive = core.behavior.enabled && core.behavior.inherited_enabled;
462
+ let has_built_handle = core.handle != NodeHandle::INVALID;
463
+ drop(core);
464
+ if has_built_handle {
465
+ ui::set_focusable(self.handle().raw(), interactive && enabled, tab_index);
466
+ self.notify_retained_mutation();
467
+ }
468
+ self
469
+ }
470
+
471
+ pub fn cursor(&self, style: CursorStyle) -> &Self {
472
+ self.core.borrow_mut().behavior.cursor = Some(style);
473
+ crate::event::handle_cursor_style_changed(self.handle());
474
+ self
475
+ }
476
+
477
+ fn current_background_color(&self) -> u32 {
478
+ self.props.borrow().bg_color.unwrap_or(0)
479
+ }
480
+
481
+ fn current_opacity(&self) -> f32 {
482
+ self.props.borrow().opacity.unwrap_or(1.0)
483
+ }
484
+
485
+ fn apply_animated_background_color(&self, color: u32) {
486
+ self.props.borrow_mut().bg_color = Some(color);
487
+ if self.has_built_handle() {
488
+ ui::set_bg_color(self.handle().raw(), color);
489
+ self.notify_retained_mutation();
490
+ }
491
+ }
492
+
493
+ fn apply_animated_opacity(&self, value: f32) {
494
+ self.props.borrow_mut().opacity = Some(value.clamp(0.0, 1.0));
495
+ if self.has_built_handle() {
496
+ self.build_self();
497
+ self.notify_retained_mutation();
498
+ }
499
+ }
500
+
501
+ fn should_animate_opacity(&self, next: f32) -> bool {
502
+ self.has_built_handle()
503
+ && self
504
+ .props
505
+ .borrow()
506
+ .transitions
507
+ .as_ref()
508
+ .and_then(NodeTransitions::opacity_timing)
509
+ .is_some()
510
+ && (self.current_opacity() - next).abs() > f32::EPSILON
511
+ }
512
+
513
+ fn should_animate_background_color(&self, next: u32) -> bool {
514
+ self.has_built_handle()
515
+ && self
516
+ .props
517
+ .borrow()
518
+ .transitions
519
+ .as_ref()
520
+ .and_then(NodeTransitions::background_color_timing)
521
+ .is_some()
522
+ && self.current_background_color() != next
523
+ }
524
+
525
+ fn cancel_opacity_transition(&self) {
526
+ if let Some(animation) = self.active_animations.borrow_mut().opacity.take() {
527
+ animation.cancel();
528
+ }
529
+ }
530
+
531
+ fn cancel_background_color_transition(&self) {
532
+ if let Some(animation) = self.active_animations.borrow_mut().background_color.take() {
533
+ animation.cancel();
534
+ }
535
+ }
536
+
537
+ pub fn node_id(&self, node_id: impl Into<String>) -> &Self {
538
+ let node_id = node_id.into();
539
+ self.core.borrow_mut().behavior.node_id = Some(node_id.clone());
540
+ if self.has_built_handle() {
541
+ ui::set_node_id(self.handle().raw(), &node_id);
542
+ self.notify_retained_mutation();
543
+ }
544
+ self
545
+ }
546
+
547
+ pub fn semantic_role(&self, role: SemanticRole) -> &Self {
548
+ self.core.borrow_mut().behavior.semantic_role = Some(role);
549
+ if self.has_built_handle() {
550
+ ui::set_semantic_role(self.handle().raw(), role as u32);
551
+ self.notify_retained_mutation();
552
+ }
553
+ self
554
+ }
555
+
556
+ pub fn semantic_label(&self, label: impl Into<String>) -> &Self {
557
+ let label = label.into();
558
+ self.core.borrow_mut().behavior.semantic_label = Some(label.clone());
559
+ if self.has_built_handle() {
560
+ ui::set_semantic_label(self.handle().raw(), &label);
561
+ self.notify_retained_mutation();
562
+ }
563
+ self
564
+ }
565
+
566
+ pub(crate) fn default_semantic_label(&self, label: impl Into<String>) -> &Self {
567
+ let label = label.into();
568
+ let should_emit = {
569
+ let mut core = self.core.borrow_mut();
570
+ core.behavior.default_semantic_label = Some(label.clone());
571
+ core.behavior.semantic_label.is_none()
572
+ };
573
+ if should_emit && self.has_built_handle() {
574
+ ui::set_semantic_label(self.handle().raw(), &label);
575
+ self.notify_retained_mutation();
576
+ }
577
+ self
578
+ }
579
+
580
+ pub(crate) fn semantic_disabled(&self, disabled: bool) -> &Self {
581
+ self.core.borrow_mut().behavior.semantic_disabled = Some(disabled);
582
+ if self.has_built_handle() {
583
+ ui::set_semantic_disabled(self.handle().raw(), true, disabled);
584
+ self.notify_retained_mutation();
585
+ }
586
+ self
587
+ }
588
+
589
+ pub fn semantic_checked(&self, state: SemanticCheckedState) -> &Self {
590
+ self.core.borrow_mut().behavior.semantic_checked = Some(state);
591
+ self
592
+ }
593
+
594
+ pub(crate) fn semantic_selected(&self, selected: bool) -> &Self {
595
+ self.core.borrow_mut().behavior.semantic_selected = Some(selected);
596
+ if self.has_built_handle() {
597
+ ui::set_semantic_selected(self.handle().raw(), true, selected);
598
+ self.notify_retained_mutation();
599
+ }
600
+ self
601
+ }
602
+
603
+ pub fn semantic_value_range(&self, value_now: f32, value_min: f32, value_max: f32) -> &Self {
604
+ self.core.borrow_mut().behavior.semantic_value_range =
605
+ Some((value_now, value_min, value_max));
606
+ self
607
+ }
608
+
609
+ pub fn semantic_orientation(&self, orientation: Orientation) -> &Self {
610
+ self.core.borrow_mut().behavior.semantic_orientation = Some(orientation);
611
+ self
612
+ }
613
+
614
+ pub fn request_semantic_announcement(&self) -> &Self {
615
+ self.core
616
+ .borrow_mut()
617
+ .behavior
618
+ .request_semantic_announcement = true;
619
+ self
620
+ }
621
+
622
+ pub fn visibility(&self, visibility: Visibility) -> &Self {
623
+ self.core.borrow_mut().behavior.visibility = Some(visibility);
624
+ if self.has_built_handle() {
625
+ ui::set_visibility(self.handle().raw(), visibility as u32);
626
+ self.notify_retained_layout_mutation();
627
+ }
628
+ self
629
+ }
630
+
631
+ pub fn portal(&self, is_portal: bool) -> &Self {
632
+ self.core.borrow_mut().behavior.is_portal = is_portal;
633
+ if self.has_built_handle() {
634
+ ui::set_is_portal(self.handle().raw(), is_portal);
635
+ self.notify_retained_mutation();
636
+ }
637
+ self
638
+ }
639
+
640
+ pub fn min_width(&self, value: f32, unit: Unit) -> &Self {
641
+ self.core.borrow_mut().behavior.min_width = Some((value, unit));
642
+ if self.has_built_handle() {
643
+ ui::set_min_width(self.handle().raw(), value, unit as u32);
644
+ self.notify_retained_layout_mutation();
645
+ }
646
+ self
647
+ }
648
+
649
+ pub fn min_width_len(&self, length: Length) -> &Self {
650
+ let (value, unit) = length;
651
+ self.min_width(value, unit)
652
+ }
653
+
654
+ pub fn max_width(&self, value: f32, unit: Unit) -> &Self {
655
+ self.core.borrow_mut().behavior.max_width = Some((value, unit));
656
+ if self.has_built_handle() {
657
+ ui::set_max_width(self.handle().raw(), value, unit as u32);
658
+ self.notify_retained_layout_mutation();
659
+ }
660
+ self
661
+ }
662
+
663
+ pub fn max_width_len(&self, length: Length) -> &Self {
664
+ let (value, unit) = length;
665
+ self.max_width(value, unit)
666
+ }
667
+
668
+ pub fn min_height(&self, value: f32, unit: Unit) -> &Self {
669
+ self.core.borrow_mut().behavior.min_height = Some((value, unit));
670
+ if self.has_built_handle() {
671
+ ui::set_min_height(self.handle().raw(), value, unit as u32);
672
+ self.notify_retained_layout_mutation();
673
+ }
674
+ self
675
+ }
676
+
677
+ pub fn min_height_len(&self, length: Length) -> &Self {
678
+ let (value, unit) = length;
679
+ self.min_height(value, unit)
680
+ }
681
+
682
+ pub fn max_height(&self, value: f32, unit: Unit) -> &Self {
683
+ self.core.borrow_mut().behavior.max_height = Some((value, unit));
684
+ if self.has_built_handle() {
685
+ ui::set_max_height(self.handle().raw(), value, unit as u32);
686
+ self.notify_retained_layout_mutation();
687
+ }
688
+ self
689
+ }
690
+
691
+ pub fn max_height_len(&self, length: Length) -> &Self {
692
+ let (value, unit) = length;
693
+ self.max_height(value, unit)
694
+ }
695
+
696
+ pub fn flex_basis(&self, basis: f32) -> &Self {
697
+ self.core.borrow_mut().behavior.flex_basis = Some(basis);
698
+ self
699
+ }
700
+
701
+ pub fn justify_content(&self, justify: JustifyContent) -> &Self {
702
+ self.core.borrow_mut().behavior.justify_content = Some(justify);
703
+ self
704
+ }
705
+
706
+ pub fn align_items(&self, align: AlignItems) -> &Self {
707
+ self.core.borrow_mut().behavior.align_items = Some(align);
708
+ self
709
+ }
710
+
711
+ pub fn align_self(&self, align: AlignSelf) -> &Self {
712
+ self.core.borrow_mut().behavior.align_self = Some(align);
713
+ self
714
+ }
715
+
716
+ pub fn margin(&self, left: f32, top: f32, right: f32, bottom: f32) -> &Self {
717
+ self.core.borrow_mut().behavior.margin = Some((left, top, right, bottom));
718
+ self
719
+ }
720
+
721
+ pub fn position_type(&self, position_type: PositionType) -> &Self {
722
+ self.core.borrow_mut().behavior.position_type = Some(position_type);
723
+ if self.has_built_handle() {
724
+ ui::set_position_type(self.handle().raw(), position_type as u32);
725
+ self.notify_retained_layout_mutation();
726
+ }
727
+ self
728
+ }
729
+
730
+ pub fn position(&self, left: f32, top: f32) -> &Self {
731
+ self.core.borrow_mut().behavior.position = Some((left, top, f32::NAN, f32::NAN));
732
+ if self.has_built_handle() {
733
+ ui::set_position(self.handle().raw(), left, top, f32::NAN, f32::NAN);
734
+ self.notify_retained_layout_mutation();
735
+ }
736
+ self
737
+ }
738
+
739
+ pub fn custom_drawable(&self, enabled: bool) -> &Self {
740
+ self.core.borrow_mut().behavior.custom_drawable = enabled;
741
+ self
742
+ }
743
+
744
+ pub fn flex_wrap(&self, wrap: FlexWrap) -> &Self {
745
+ self.core.borrow_mut().behavior.flex_wrap = Some(wrap);
746
+ self
747
+ }
748
+
749
+ pub fn clip_to_bounds(&self, clip: bool) -> &Self {
750
+ self.core.borrow_mut().behavior.clip_to_bounds = Some(clip);
751
+ self
752
+ }
753
+
754
+ pub fn selection_area(&self, enabled: bool) -> &Self {
755
+ self.core.borrow_mut().behavior.selection_area = enabled;
756
+ self
757
+ }
758
+
759
+ pub fn selection_area_barrier(&self, enabled: bool) -> &Self {
760
+ self.core.borrow_mut().behavior.selection_area_barrier = enabled;
761
+ self
762
+ }
763
+
764
+ pub fn shared_size_scope(&self, enabled: bool) -> &Self {
765
+ self.core.borrow_mut().behavior.is_shared_size_scope = enabled;
766
+ if self.has_built_handle() {
767
+ ui::set_is_shared_size_scope(self.handle().raw(), enabled);
768
+ self.notify_retained_layout_mutation();
769
+ }
770
+ self
771
+ }
772
+
773
+ pub fn on_click(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
774
+ self.core.borrow_mut().handlers.pointer_click = Some(Rc::new(handler));
775
+ self.retained_node_ref().require_interactive();
776
+ self
777
+ }
778
+
779
+ pub fn on_pointer_down(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
780
+ self.core.borrow_mut().handlers.pointer_down = Some(Rc::new(handler));
781
+ self.retained_node_ref().require_interactive();
782
+ self
783
+ }
784
+
785
+ pub fn on_pointer_move(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
786
+ self.core.borrow_mut().handlers.pointer_move = Some(Rc::new(handler));
787
+ self.retained_node_ref().require_interactive();
788
+ self
789
+ }
790
+
791
+ pub fn on_pointer_up(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
792
+ self.core.borrow_mut().handlers.pointer_up = Some(Rc::new(handler));
793
+ self.retained_node_ref().require_interactive();
794
+ self
795
+ }
796
+
797
+ pub fn on_pointer_enter(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
798
+ self.core.borrow_mut().handlers.pointer_enter = Some(Rc::new(handler));
799
+ self.retained_node_ref().require_interactive();
800
+ self
801
+ }
802
+
803
+ pub fn on_pointer_leave(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
804
+ self.core.borrow_mut().handlers.pointer_leave = Some(Rc::new(handler));
805
+ self.retained_node_ref().require_interactive();
806
+ self
807
+ }
808
+
809
+ pub fn on_pointer_cancel(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
810
+ self.core.borrow_mut().handlers.pointer_cancel = Some(Rc::new(handler));
811
+ self.retained_node_ref().require_interactive();
812
+ self
813
+ }
814
+
815
+ pub fn on_wheel(&self, handler: impl Fn(&mut WheelEventArgs) + 'static) -> &Self {
816
+ self.core.borrow_mut().handlers.wheel = Some(Rc::new(handler));
817
+ self.retained_node_ref().require_interactive();
818
+ self
819
+ }
820
+
821
+ pub fn on_pan_gesture(&self, handler: impl Fn(&mut GestureEventArgs) + 'static) -> &Self {
822
+ self.core.borrow_mut().handlers.pan_gesture = Some(Rc::new(handler));
823
+ self
824
+ }
825
+
826
+ pub fn on_pinch_gesture(&self, handler: impl Fn(&mut GestureEventArgs) + 'static) -> &Self {
827
+ self.core.borrow_mut().handlers.pinch_gesture = Some(Rc::new(handler));
828
+ self
829
+ }
830
+
831
+ pub fn long_press_options(&self, minimum_duration_ms: i32, movement_tolerance: f32) -> &Self {
832
+ let mut core = self.core.borrow_mut();
833
+ core.handlers.long_press_minimum_duration_ms = minimum_duration_ms.max(0);
834
+ core.handlers.long_press_movement_tolerance = movement_tolerance.max(0.0);
835
+ self
836
+ }
837
+
838
+ pub fn on_long_press(&self, handler: impl Fn(&mut LongPressEventArgs) + 'static) -> &Self {
839
+ self.core.borrow_mut().handlers.long_press = Some(Rc::new(handler));
840
+ self
841
+ }
842
+
843
+ pub fn on_key_down(&self, handler: impl Fn(&mut KeyEventArgs) + 'static) -> &Self {
844
+ self.core.borrow_mut().handlers.key_down = Some(Rc::new(handler));
845
+ self
846
+ }
847
+
848
+ pub fn on_key_up(&self, handler: impl Fn(&mut KeyEventArgs) + 'static) -> &Self {
849
+ self.core.borrow_mut().handlers.key_up = Some(Rc::new(handler));
850
+ self
851
+ }
852
+
853
+ pub fn on_focus_changed(&self, handler: impl Fn(FocusChangedEventArgs) + 'static) -> &Self {
854
+ self.core.borrow_mut().handlers.focus_changed = Some(Rc::new(handler));
855
+ self
856
+ }
857
+
858
+ pub fn child<T: Node>(&self, child: &T) -> &Self {
859
+ self.append_child(child);
860
+ self
861
+ }
862
+
863
+ pub fn children<I, C>(&self, children: I) -> &Self
864
+ where
865
+ I: IntoIterator<Item = C>,
866
+ C: Into<Child>,
867
+ {
868
+ for child in children {
869
+ self.retained_node_ref()
870
+ .append_child_ref(&child.into().node_ref);
871
+ }
872
+ self
873
+ }
874
+ }