@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,542 @@
1
+ use super::internal::button_presenter::{
2
+ ButtonPresenter, ButtonTemplate, ButtonVisualState, DEFAULT_BUTTON_TEMPLATE,
3
+ };
4
+ use super::*;
5
+ use crate::ffi::CursorStyle;
6
+ use crate::node::{TextCore, WeakFlexBox};
7
+ use crate::signal::SubscriptionGuard;
8
+ use crate::{focus_adorner, focus_visibility};
9
+ use std::rc::Rc;
10
+
11
+ #[derive(Clone)]
12
+ pub struct Button {
13
+ root: FlexBox,
14
+ presenter: Rc<RefCell<Rc<dyn ButtonPresenter>>>,
15
+ label: Rc<RefCell<TextCore>>,
16
+ template: Rc<RefCell<Option<Rc<dyn ButtonTemplate>>>>,
17
+ label_value: Rc<RefCell<String>>,
18
+ click: Rc<RefCell<Option<ClickCallback>>>,
19
+ double_click: Rc<RefCell<Option<ClickCallback>>>,
20
+ triple_click: Rc<RefCell<Option<ClickCallback>>>,
21
+ hovered_state: Rc<Cell<bool>>,
22
+ pressed_state: Rc<Cell<bool>>,
23
+ focused_state: Rc<Cell<bool>>,
24
+ keyboard_armed_key: Rc<RefCell<Option<String>>>,
25
+ background_override: Rc<Cell<Option<u32>>>,
26
+ hover_background_override: Rc<Cell<Option<u32>>>,
27
+ pressed_background_override: Rc<Cell<Option<u32>>>,
28
+ border_override: Rc<Cell<Option<Border>>>,
29
+ text_color_override: Rc<Cell<Option<u32>>>,
30
+ colors_value: Rc<Cell<Option<ButtonColors>>>,
31
+ theme_guard: Rc<RefCell<Option<SubscriptionGuard>>>,
32
+ focus_visibility_guard: Rc<RefCell<Option<SubscriptionGuard>>>,
33
+ }
34
+
35
+ impl Button {
36
+ pub fn new(label: impl Into<String>) -> Self {
37
+ let label = label.into();
38
+ let root = row();
39
+ let presenter = create_button_presenter(None);
40
+ let label_node = presenter.label_node();
41
+ label_node.text(label.clone());
42
+ root.flex_direction(crate::FlexDirection::Row)
43
+ .justify_content(JustifyContent::Center)
44
+ .align_items(AlignItems::Center)
45
+ .interactive(true)
46
+ .focusable(true, 0)
47
+ .semantic_role(SemanticRole::Button)
48
+ .semantic_label(label.clone())
49
+ .reflect_semantic_disabled_from_enabled()
50
+ .child(&presenter.content_root());
51
+
52
+ let control = Self {
53
+ root,
54
+ presenter: Rc::new(RefCell::new(presenter)),
55
+ label: Rc::new(RefCell::new(label_node)),
56
+ template: Rc::new(RefCell::new(None)),
57
+ label_value: Rc::new(RefCell::new(label.clone())),
58
+ click: Rc::new(RefCell::new(None)),
59
+ double_click: Rc::new(RefCell::new(None)),
60
+ triple_click: Rc::new(RefCell::new(None)),
61
+ hovered_state: Rc::new(Cell::new(false)),
62
+ pressed_state: Rc::new(Cell::new(false)),
63
+ focused_state: Rc::new(Cell::new(false)),
64
+ keyboard_armed_key: Rc::new(RefCell::new(None)),
65
+ background_override: Rc::new(Cell::new(None)),
66
+ hover_background_override: Rc::new(Cell::new(None)),
67
+ pressed_background_override: Rc::new(Cell::new(None)),
68
+ border_override: Rc::new(Cell::new(None)),
69
+ text_color_override: Rc::new(Cell::new(None)),
70
+ colors_value: Rc::new(Cell::new(None)),
71
+ theme_guard: Rc::new(RefCell::new(None)),
72
+ focus_visibility_guard: Rc::new(RefCell::new(None)),
73
+ };
74
+ control.install_visual_subscriptions();
75
+ control.sync_visual_state();
76
+ control.sync_focus_chrome();
77
+ control.bind_events();
78
+ control
79
+ }
80
+
81
+ fn bind_events(&self) {
82
+ let event_target = self.event_target();
83
+ self.root.on_pointer_enter(move |_event| {
84
+ event_target.set_hovered(true);
85
+ });
86
+ let event_target = self.event_target();
87
+ self.root.on_pointer_leave(move |_event| {
88
+ event_target.set_hovered(false);
89
+ if event_target.keyboard_armed_key.borrow().is_none() {
90
+ event_target.cancel_press();
91
+ }
92
+ });
93
+ let event_target = self.event_target();
94
+ self.root.on_pointer_down(move |_event| {
95
+ event_target.set_hovered(true);
96
+ event_target.begin_press();
97
+ });
98
+ let event_target = self.event_target();
99
+ self.root.on_pointer_up(move |_event| {
100
+ if event_target.pressed_state.get()
101
+ && event_target.keyboard_armed_key.borrow().is_none()
102
+ {
103
+ event_target.end_press();
104
+ }
105
+ });
106
+
107
+ let event_target = self.event_target();
108
+ self.root.on_click(move |event| {
109
+ fire_click_callbacks(
110
+ &event_target.click,
111
+ &event_target.double_click,
112
+ &event_target.triple_click,
113
+ event.click_count.max(1),
114
+ );
115
+ event.handled = true;
116
+ });
117
+ let event_target = self.event_target();
118
+ self.root.on_key_down(move |event| {
119
+ event_target.sync_focus_chrome();
120
+ if !event_target.is_enabled() || event.modifiers != 0 || !is_activation_key(event) {
121
+ return;
122
+ }
123
+ if event_target.keyboard_armed_key.borrow().is_some() {
124
+ event.handled = true;
125
+ return;
126
+ }
127
+ *event_target.keyboard_armed_key.borrow_mut() = Some(event.key.clone());
128
+ event_target.begin_press();
129
+ event.handled = true;
130
+ });
131
+ let event_target = self.event_target();
132
+ self.root.on_key_up(move |event| {
133
+ if !event_target.is_enabled() || event.modifiers != 0 || !is_activation_key(event) {
134
+ return;
135
+ }
136
+ let armed = event_target.keyboard_armed_key.borrow().clone();
137
+ if armed.as_deref() == Some(event.key.as_str()) {
138
+ *event_target.keyboard_armed_key.borrow_mut() = None;
139
+ event_target.end_press();
140
+ fire_click_callbacks(
141
+ &event_target.click,
142
+ &event_target.double_click,
143
+ &event_target.triple_click,
144
+ 1,
145
+ );
146
+ event.handled = true;
147
+ }
148
+ });
149
+ let event_target = self.event_target();
150
+ self.root.on_focus_changed(move |event| {
151
+ if !event.focused && event_target.keyboard_armed_key.borrow().is_some() {
152
+ *event_target.keyboard_armed_key.borrow_mut() = None;
153
+ event_target.cancel_press();
154
+ }
155
+ if event_target.focused_state.get() != event.focused {
156
+ event_target.focused_state.set(event.focused);
157
+ event_target.sync_visual_state();
158
+ event_target.sync_focus_chrome();
159
+ }
160
+ });
161
+ }
162
+
163
+ pub fn text(&self, value: impl Into<String>) -> &Self {
164
+ let value = value.into();
165
+ self.label_value.replace(value.clone());
166
+ self.label.borrow().text(value.clone());
167
+ self.root.semantic_label(value);
168
+ self
169
+ }
170
+
171
+ pub fn template(&self, template: Option<Rc<dyn ButtonTemplate>>) -> &Self {
172
+ self.template.replace(template.clone());
173
+ self.replace_presenter(create_button_presenter(template));
174
+ self
175
+ }
176
+
177
+ pub fn colors(&self, colors: Option<ButtonColors>) -> &Self {
178
+ self.colors_value.set(colors);
179
+ self.sync_visual_state();
180
+ self
181
+ }
182
+
183
+ pub fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
184
+ *self.click.borrow_mut() = Some(Rc::new(handler));
185
+ self
186
+ }
187
+
188
+ pub fn on_double_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
189
+ *self.double_click.borrow_mut() = Some(Rc::new(handler));
190
+ self
191
+ }
192
+
193
+ pub fn on_triple_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
194
+ *self.triple_click.borrow_mut() = Some(Rc::new(handler));
195
+ self
196
+ }
197
+
198
+ pub fn enabled(&self, enabled: bool) -> &Self {
199
+ self.root.enabled(enabled);
200
+ if !enabled {
201
+ self.hovered_state.set(false);
202
+ self.focused_state.set(false);
203
+ *self.keyboard_armed_key.borrow_mut() = None;
204
+ self.cancel_press();
205
+ }
206
+ self.sync_visual_state();
207
+ self.sync_focus_chrome();
208
+ self
209
+ }
210
+
211
+ pub fn corner_radius(&self, radius: f32) -> &Self {
212
+ self.root.corner_radius(radius);
213
+ self.sync_focus_chrome();
214
+ self
215
+ }
216
+
217
+ pub fn corners(&self, tl: f32, tr: f32, br: f32, bl: f32) -> &Self {
218
+ self.root.corners(tl, tr, br, bl);
219
+ self.sync_focus_chrome();
220
+ self
221
+ }
222
+
223
+ pub fn hover_bg_color(&self, color: u32) -> &Self {
224
+ self.hover_background_override.set(Some(color));
225
+ self.sync_visual_state();
226
+ self
227
+ }
228
+
229
+ pub fn pressed_bg_color(&self, color: u32) -> &Self {
230
+ self.pressed_background_override.set(Some(color));
231
+ self.sync_visual_state();
232
+ self
233
+ }
234
+
235
+ pub fn bg_color(&self, color: u32) -> &Self {
236
+ self.background_override.set(Some(color));
237
+ self.sync_visual_state();
238
+ self
239
+ }
240
+
241
+ pub fn border(&self, width: f32, color: u32) -> &Self {
242
+ self.border_override.set(Some(Border::solid(width, color)));
243
+ self.sync_visual_state();
244
+ self
245
+ }
246
+
247
+ pub fn border_config(&self, border: Border) -> &Self {
248
+ self.border_override.set(Some(border));
249
+ self.sync_visual_state();
250
+ self
251
+ }
252
+
253
+ pub fn text_color(&self, color: u32) -> &Self {
254
+ self.text_color_override.set(Some(color));
255
+ self.sync_visual_state();
256
+ self
257
+ }
258
+
259
+ fn install_visual_subscriptions(&self) {
260
+ let event_target = self.event_target();
261
+ *self.theme_guard.borrow_mut() = Some(subscribe(move |_theme| {
262
+ event_target.sync_visual_state();
263
+ event_target.sync_focus_chrome();
264
+ }));
265
+
266
+ let event_target = self.event_target();
267
+ *self.focus_visibility_guard.borrow_mut() =
268
+ Some(focus_visibility::subscribe(move |_visible| {
269
+ event_target.sync_focus_chrome();
270
+ }));
271
+ }
272
+
273
+ fn event_target(&self) -> ButtonEventTarget {
274
+ ButtonEventTarget {
275
+ weak_root: self.root.downgrade(),
276
+ presenter: self.presenter.clone(),
277
+ click: self.click.clone(),
278
+ double_click: self.double_click.clone(),
279
+ triple_click: self.triple_click.clone(),
280
+ hovered_state: self.hovered_state.clone(),
281
+ pressed_state: self.pressed_state.clone(),
282
+ focused_state: self.focused_state.clone(),
283
+ keyboard_armed_key: self.keyboard_armed_key.clone(),
284
+ background_override: self.background_override.clone(),
285
+ hover_background_override: self.hover_background_override.clone(),
286
+ pressed_background_override: self.pressed_background_override.clone(),
287
+ border_override: self.border_override.clone(),
288
+ text_color_override: self.text_color_override.clone(),
289
+ colors_value: self.colors_value.clone(),
290
+ }
291
+ }
292
+
293
+ pub(crate) fn is_enabled(&self) -> bool {
294
+ self.root.retained_node_ref().is_enabled_for_routing()
295
+ }
296
+
297
+ pub(crate) fn begin_press(&self) {
298
+ self.pressed_state.set(true);
299
+ self.sync_visual_state();
300
+ self.sync_focus_chrome();
301
+ }
302
+
303
+ pub(crate) fn end_press(&self, activate: bool) {
304
+ self.pressed_state.set(false);
305
+ self.sync_visual_state();
306
+ self.sync_focus_chrome();
307
+ if activate {
308
+ fire_click_callbacks(&self.click, &self.double_click, &self.triple_click, 1);
309
+ }
310
+ }
311
+
312
+ pub(crate) fn cancel_press(&self) {
313
+ if self.pressed_state.replace(false) {
314
+ self.sync_visual_state();
315
+ }
316
+ self.sync_focus_chrome();
317
+ }
318
+
319
+ fn sync_visual_state(&self) {
320
+ sync_button_visual_state(
321
+ &self.root,
322
+ &self.presenter,
323
+ self.hovered_state.get(),
324
+ self.pressed_state.get(),
325
+ self.focused_state.get(),
326
+ self.is_enabled(),
327
+ self.background_override.get(),
328
+ self.hover_background_override.get(),
329
+ self.pressed_background_override.get(),
330
+ self.border_override.get(),
331
+ self.text_color_override.get(),
332
+ self.colors_value.get(),
333
+ );
334
+ self.root.cursor(if self.is_enabled() {
335
+ CursorStyle::Pointer
336
+ } else {
337
+ CursorStyle::Default
338
+ });
339
+ self.root
340
+ .opacity(if self.is_enabled() { 1.0 } else { 0.38 });
341
+ }
342
+
343
+ fn sync_focus_chrome(&self) {
344
+ sync_button_focus_chrome(&self.root, self.focused_state.get(), self.is_enabled());
345
+ }
346
+
347
+ fn replace_presenter(&self, next_presenter: Rc<dyn ButtonPresenter>) {
348
+ let previous_presenter = self.presenter.borrow().clone();
349
+ if Rc::ptr_eq(&previous_presenter, &next_presenter) {
350
+ return;
351
+ }
352
+ next_presenter
353
+ .label_node()
354
+ .text(self.label_value.borrow().clone());
355
+ self.root.child(&next_presenter.content_root());
356
+ self.root.remove_child(&previous_presenter.content_root());
357
+ previous_presenter.content_root().dispose();
358
+ self.label.replace(next_presenter.label_node());
359
+ self.presenter.replace(next_presenter);
360
+ self.sync_visual_state();
361
+ self.sync_focus_chrome();
362
+ }
363
+ }
364
+
365
+ impl Node for Button {
366
+ fn retained_node_ref(&self) -> NodeRef {
367
+ self.root.retained_node_ref()
368
+ }
369
+
370
+ fn build_self(&self) {
371
+ self.sync_visual_state();
372
+ self.sync_focus_chrome();
373
+ self.root.build_self();
374
+ }
375
+ }
376
+
377
+ impl HasFlexBoxRoot for Button {
378
+ fn flex_box_root(&self) -> &FlexBox {
379
+ &self.root
380
+ }
381
+ }
382
+
383
+ fn sync_button_visual_state(
384
+ root: &FlexBox,
385
+ presenter: &Rc<RefCell<Rc<dyn ButtonPresenter>>>,
386
+ hovered: bool,
387
+ pressed: bool,
388
+ focused: bool,
389
+ enabled: bool,
390
+ background_override: Option<u32>,
391
+ hover_background_override: Option<u32>,
392
+ pressed_background_override: Option<u32>,
393
+ border_override: Option<Border>,
394
+ text_color_override: Option<u32>,
395
+ colors: Option<ButtonColors>,
396
+ ) {
397
+ let presenter = presenter.borrow().clone();
398
+ presenter.apply(
399
+ root,
400
+ current_theme(),
401
+ ButtonVisualState {
402
+ hovered,
403
+ pressed,
404
+ focused,
405
+ enabled,
406
+ },
407
+ colors,
408
+ );
409
+ let override_background = if !enabled {
410
+ background_override
411
+ } else if pressed {
412
+ pressed_background_override.or(background_override)
413
+ } else if hovered {
414
+ hover_background_override.or(background_override)
415
+ } else {
416
+ background_override
417
+ };
418
+ if let Some(color) = override_background {
419
+ root.bg_color(color);
420
+ }
421
+ if let Some(border) = border_override {
422
+ root.border_config(border);
423
+ }
424
+ if let Some(color) = text_color_override {
425
+ presenter.label_node().text_color(color);
426
+ }
427
+ }
428
+
429
+ fn sync_button_focus_chrome(root: &FlexBox, focused: bool, enabled: bool) {
430
+ if focused && enabled && focus_visibility::keyboard_focus_visible() {
431
+ let radius = current_theme().spacing.sm;
432
+ focus_adorner::show_standard_corners(root, radius, radius, radius, radius);
433
+ return;
434
+ }
435
+ focus_adorner::hide_owner(root);
436
+ }
437
+
438
+ fn create_button_presenter(template: Option<Rc<dyn ButtonTemplate>>) -> Rc<dyn ButtonPresenter> {
439
+ if let Some(template) = template {
440
+ return template.create();
441
+ }
442
+ if let Some(template_set) = get_control_templates() {
443
+ if let Some(template) = template_set.button {
444
+ return template.create();
445
+ }
446
+ }
447
+ DEFAULT_BUTTON_TEMPLATE.create()
448
+ }
449
+
450
+ #[derive(Clone)]
451
+ struct ButtonEventTarget {
452
+ weak_root: WeakFlexBox,
453
+ presenter: Rc<RefCell<Rc<dyn ButtonPresenter>>>,
454
+ click: Rc<RefCell<Option<ClickCallback>>>,
455
+ double_click: Rc<RefCell<Option<ClickCallback>>>,
456
+ triple_click: Rc<RefCell<Option<ClickCallback>>>,
457
+ hovered_state: Rc<Cell<bool>>,
458
+ pressed_state: Rc<Cell<bool>>,
459
+ focused_state: Rc<Cell<bool>>,
460
+ keyboard_armed_key: Rc<RefCell<Option<String>>>,
461
+ background_override: Rc<Cell<Option<u32>>>,
462
+ hover_background_override: Rc<Cell<Option<u32>>>,
463
+ pressed_background_override: Rc<Cell<Option<u32>>>,
464
+ border_override: Rc<Cell<Option<Border>>>,
465
+ text_color_override: Rc<Cell<Option<u32>>>,
466
+ colors_value: Rc<Cell<Option<ButtonColors>>>,
467
+ }
468
+
469
+ impl ButtonEventTarget {
470
+ fn is_enabled(&self) -> bool {
471
+ self.weak_root
472
+ .upgrade()
473
+ .is_some_and(|root| root.retained_node_ref().is_enabled_for_routing())
474
+ }
475
+
476
+ fn sync_visual_state(&self) {
477
+ let Some(root) = self.weak_root.upgrade() else {
478
+ return;
479
+ };
480
+ sync_button_visual_state(
481
+ &root,
482
+ &self.presenter,
483
+ self.hovered_state.get(),
484
+ self.pressed_state.get(),
485
+ self.focused_state.get(),
486
+ root.retained_node_ref().is_enabled_for_routing(),
487
+ self.background_override.get(),
488
+ self.hover_background_override.get(),
489
+ self.pressed_background_override.get(),
490
+ self.border_override.get(),
491
+ self.text_color_override.get(),
492
+ self.colors_value.get(),
493
+ );
494
+ root.cursor(if root.retained_node_ref().is_enabled_for_routing() {
495
+ CursorStyle::Pointer
496
+ } else {
497
+ CursorStyle::Default
498
+ });
499
+ root.opacity(if root.retained_node_ref().is_enabled_for_routing() {
500
+ 1.0
501
+ } else {
502
+ 0.38
503
+ });
504
+ }
505
+
506
+ fn sync_focus_chrome(&self) {
507
+ let Some(root) = self.weak_root.upgrade() else {
508
+ return;
509
+ };
510
+ sync_button_focus_chrome(
511
+ &root,
512
+ self.focused_state.get(),
513
+ root.retained_node_ref().is_enabled_for_routing(),
514
+ );
515
+ }
516
+
517
+ fn begin_press(&self) {
518
+ self.pressed_state.set(true);
519
+ self.sync_visual_state();
520
+ self.sync_focus_chrome();
521
+ }
522
+
523
+ fn end_press(&self) {
524
+ self.pressed_state.set(false);
525
+ self.sync_visual_state();
526
+ self.sync_focus_chrome();
527
+ }
528
+
529
+ fn cancel_press(&self) {
530
+ if self.pressed_state.replace(false) {
531
+ self.sync_visual_state();
532
+ }
533
+ self.sync_focus_chrome();
534
+ }
535
+
536
+ fn set_hovered(&self, hovered: bool) {
537
+ if self.hovered_state.replace(hovered) != hovered {
538
+ self.sync_visual_state();
539
+ }
540
+ self.sync_focus_chrome();
541
+ }
542
+ }