@effindomv2/fui-rs 0.1.22 → 0.1.24

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 (46) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +12 -0
  3. package/package.json +1 -1
  4. package/src/controls/anti_selection_area.rs +0 -18
  5. package/src/controls/button.rs +14 -42
  6. package/src/controls/checkbox.rs +7 -0
  7. package/src/controls/combobox.rs +7 -6
  8. package/src/controls/context_menu.rs +38 -5
  9. package/src/controls/dialog.rs +41 -3
  10. package/src/controls/dropdown.rs +2 -2
  11. package/src/controls/form.rs +16 -20
  12. package/src/controls/internal/button_presenter.rs +5 -5
  13. package/src/controls/internal/checkbox_indicator_presenter.rs +1 -1
  14. package/src/controls/internal/pressable_labeled_control.rs +21 -7
  15. package/src/controls/internal/selectable_popup_list.rs +2 -2
  16. package/src/controls/internal/text_input_core.rs +38 -68
  17. package/src/controls/internal/text_input_presenter.rs +4 -4
  18. package/src/controls/mod.rs +11 -4
  19. package/src/controls/popup.rs +35 -20
  20. package/src/controls/radio_button.rs +7 -0
  21. package/src/controls/radio_group.rs +17 -0
  22. package/src/controls/selection_area.rs +0 -18
  23. package/src/controls/shared.rs +2 -17
  24. package/src/controls/switch.rs +7 -0
  25. package/src/controls/tests.rs +230 -6
  26. package/src/controls/text_area.rs +28 -142
  27. package/src/controls/text_editor_surface.rs +167 -0
  28. package/src/controls/text_input.rs +30 -144
  29. package/src/lib.rs +26 -20
  30. package/src/mobile_text_selection_toolbar.rs +2 -2
  31. package/src/node/core.rs +451 -60
  32. package/src/node/custom_drawable.rs +20 -0
  33. package/src/node/flex_box.rs +39 -47
  34. package/src/node/grid.rs +43 -128
  35. package/src/node/helpers.rs +34 -43
  36. package/src/node/image.rs +47 -56
  37. package/src/node/mod.rs +398 -73
  38. package/src/node/scroll_bar.rs +6 -0
  39. package/src/node/scroll_box.rs +8 -21
  40. package/src/node/scroll_view.rs +144 -13
  41. package/src/node/svg_node.rs +47 -66
  42. package/src/node/text_node.rs +358 -79
  43. package/src/node/virtual_list.rs +17 -0
  44. package/src/popup_presenter.rs +31 -0
  45. package/src/text.rs +59 -0
  46. package/src/text_indices.rs +48 -0
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "fui-rs"
3
- version = "0.1.22"
3
+ version = "0.1.24"
4
4
  edition = "2021"
5
5
  license = "AGPL-3.0-only OR LicenseRef-EffinDom-Commercial"
6
6
 
package/README.md CHANGED
@@ -186,6 +186,18 @@ calls.
186
186
  Retained controls are cheap clone handles. Cloning a control gives another Rust
187
187
  handle to the same retained UI object.
188
188
 
189
+ FUI-RS maps retained inheritance to capability traits. `Node` supplies the
190
+ universal retained/event surface; FlexBox-derived visuals additionally expose
191
+ `LayoutSurface`, `BoxStyleSurface`, `FlexLayoutSurface`, and
192
+ `ChildContainerSurface`. `TextSurface` covers `Text` and `RichText`, while
193
+ `TextEditorSurface` covers `TextInput` and `TextArea`.
194
+
195
+ Use `on_pointer_click(...)` for raw routed pointer input. Use
196
+ `on_pointer_double_click(...)` and `on_pointer_triple_click(...)` for exact raw
197
+ multi-click gestures. `Button`, `Checkbox`, `RadioButton`, and `Switch` expose
198
+ count-free `on_click(...)` semantic activation for supported pointer and
199
+ keyboard input.
200
+
189
201
  ## License
190
202
 
191
203
  AGPL-3.0-only, or commercial license. See [COMMERCIAL.md](COMMERCIAL.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effindomv2/fui-rs",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "private": false,
5
5
  "license": "AGPL-3.0-only OR LicenseRef-EffinDom-Commercial",
6
6
  "description": "EffinDom v2 Rust frontend framework SDK and host generators",
@@ -11,24 +11,6 @@ impl AntiSelectionArea {
11
11
  root.selection_area_barrier(true);
12
12
  Self { root }
13
13
  }
14
-
15
- pub fn child<T: Node>(&self, node: &T) -> &Self {
16
- self.root.child(node);
17
- self
18
- }
19
-
20
- pub fn children<I, C>(&self, nodes: I) -> &Self
21
- where
22
- I: IntoIterator<Item = C>,
23
- C: Into<Child>,
24
- {
25
- for node in nodes {
26
- self.root
27
- .retained_node_ref()
28
- .append_child_ref(&node.into().node_ref);
29
- }
30
- self
31
- }
32
14
  }
33
15
 
34
16
  impl Default for AntiSelectionArea {
@@ -3,7 +3,7 @@ use super::internal::button_presenter::{
3
3
  };
4
4
  use super::*;
5
5
  use crate::ffi::CursorStyle;
6
- use crate::node::{TextCore, WeakFlexBox};
6
+ use crate::node::{TextNode, WeakFlexBox};
7
7
  use crate::theme::subscribe;
8
8
  use crate::{focus_adorner, focus_visibility};
9
9
  use std::rc::Rc;
@@ -12,12 +12,10 @@ use std::rc::Rc;
12
12
  pub struct Button {
13
13
  root: FlexBox,
14
14
  presenter: Rc<RefCell<Rc<dyn ButtonPresenter>>>,
15
- label: Rc<RefCell<TextCore>>,
15
+ label: Rc<RefCell<TextNode>>,
16
16
  template: Rc<RefCell<Option<Rc<dyn ButtonTemplate>>>>,
17
17
  label_value: Rc<RefCell<String>>,
18
18
  click: Rc<RefCell<Option<ClickCallback>>>,
19
- double_click: Rc<RefCell<Option<ClickCallback>>>,
20
- triple_click: Rc<RefCell<Option<ClickCallback>>>,
21
19
  hovered_state: Rc<Cell<bool>>,
22
20
  pressed_state: Rc<Cell<bool>>,
23
21
  focused_state: Rc<Cell<bool>>,
@@ -49,8 +47,6 @@ impl Button {
49
47
  template: Rc::new(RefCell::new(None)),
50
48
  label_value: Rc::new(RefCell::new(label.clone())),
51
49
  click: Rc::new(RefCell::new(None)),
52
- double_click: Rc::new(RefCell::new(None)),
53
- triple_click: Rc::new(RefCell::new(None)),
54
50
  hovered_state: Rc::new(Cell::new(false)),
55
51
  pressed_state: Rc::new(Cell::new(false)),
56
52
  focused_state: Rc::new(Cell::new(false)),
@@ -94,13 +90,8 @@ impl Button {
94
90
  });
95
91
 
96
92
  let event_target = self.event_target();
97
- self.root.on_click(move |event| {
98
- fire_click_callbacks(
99
- &event_target.click,
100
- &event_target.double_click,
101
- &event_target.triple_click,
102
- event.click_count.max(1),
103
- );
93
+ self.root.on_pointer_click(move |event| {
94
+ fire_click_callback(&event_target.click);
104
95
  event.handled = true;
105
96
  });
106
97
  let event_target = self.event_target();
@@ -126,12 +117,7 @@ impl Button {
126
117
  if armed.as_deref() == Some(event.key.as_str()) {
127
118
  *event_target.keyboard_armed_key.borrow_mut() = None;
128
119
  event_target.end_press();
129
- fire_click_callbacks(
130
- &event_target.click,
131
- &event_target.double_click,
132
- &event_target.triple_click,
133
- 1,
134
- );
120
+ fire_click_callback(&event_target.click);
135
121
  event.handled = true;
136
122
  }
137
123
  });
@@ -185,21 +171,6 @@ impl Button {
185
171
  self
186
172
  }
187
173
 
188
- pub fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
189
- *self.click.borrow_mut() = Some(Rc::new(handler));
190
- self
191
- }
192
-
193
- pub fn on_double_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
194
- *self.double_click.borrow_mut() = Some(Rc::new(handler));
195
- self
196
- }
197
-
198
- pub fn on_triple_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
199
- *self.triple_click.borrow_mut() = Some(Rc::new(handler));
200
- self
201
- }
202
-
203
174
  pub fn enabled(&self, enabled: bool) -> &Self {
204
175
  self.root.enabled(enabled);
205
176
  if !enabled {
@@ -255,8 +226,6 @@ impl Button {
255
226
  template: self.template.clone(),
256
227
  label_value: self.label_value.clone(),
257
228
  click: self.click.clone(),
258
- double_click: self.double_click.clone(),
259
- triple_click: self.triple_click.clone(),
260
229
  hovered_state: self.hovered_state.clone(),
261
230
  pressed_state: self.pressed_state.clone(),
262
231
  focused_state: self.focused_state.clone(),
@@ -283,7 +252,7 @@ impl Button {
283
252
  self.sync_visual_state();
284
253
  self.sync_focus_chrome();
285
254
  if activate {
286
- fire_click_callbacks(&self.click, &self.double_click, &self.triple_click, 1);
255
+ fire_click_callback(&self.click);
287
256
  }
288
257
  }
289
258
 
@@ -331,6 +300,13 @@ impl Button {
331
300
  }
332
301
  }
333
302
 
303
+ impl Clickable for Button {
304
+ fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
305
+ *self.click.borrow_mut() = Some(Rc::new(handler));
306
+ self
307
+ }
308
+ }
309
+
334
310
  impl Node for Button {
335
311
  fn retained_node_ref(&self) -> NodeRef {
336
312
  self.root.retained_node_ref()
@@ -450,12 +426,10 @@ fn create_button_presenter(template: Option<Rc<dyn ButtonTemplate>>) -> Rc<dyn B
450
426
  struct ButtonEventTarget {
451
427
  weak_root: WeakFlexBox,
452
428
  presenter: Rc<RefCell<Rc<dyn ButtonPresenter>>>,
453
- label: Rc<RefCell<TextCore>>,
429
+ label: Rc<RefCell<TextNode>>,
454
430
  template: Rc<RefCell<Option<Rc<dyn ButtonTemplate>>>>,
455
431
  label_value: Rc<RefCell<String>>,
456
432
  click: Rc<RefCell<Option<ClickCallback>>>,
457
- double_click: Rc<RefCell<Option<ClickCallback>>>,
458
- triple_click: Rc<RefCell<Option<ClickCallback>>>,
459
433
  hovered_state: Rc<Cell<bool>>,
460
434
  pressed_state: Rc<Cell<bool>>,
461
435
  focused_state: Rc<Cell<bool>>,
@@ -475,8 +449,6 @@ impl ButtonEventTarget {
475
449
  template: self.template.clone(),
476
450
  label_value: self.label_value.clone(),
477
451
  click: self.click.clone(),
478
- double_click: self.double_click.clone(),
479
- triple_click: self.triple_click.clone(),
480
452
  hovered_state: self.hovered_state.clone(),
481
453
  pressed_state: self.pressed_state.clone(),
482
454
  focused_state: self.focused_state.clone(),
@@ -289,6 +289,13 @@ impl Checkbox {
289
289
  }
290
290
  }
291
291
 
292
+ impl Clickable for Checkbox {
293
+ fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
294
+ self.base.on_click(handler);
295
+ self
296
+ }
297
+ }
298
+
292
299
  impl LabeledControlTextStyle for Checkbox {
293
300
  fn set_label_font_family(&self, family: crate::FontFamily) {
294
301
  self.base.font_family(family);
@@ -10,7 +10,7 @@ use super::internal::selectable_popup_list::{
10
10
  use super::internal::text_input_presenter::{
11
11
  TextInputPresenter, TextInputTemplate, TextInputVisualState,
12
12
  };
13
- use super::{DropdownColors, DropdownSizing, TextInput, TextInputColors};
13
+ use super::{DropdownColors, DropdownSizing, TextEditorSurface, TextInput, TextInputColors};
14
14
  use crate::bindings::ui;
15
15
  use crate::event::{self, TextChangedEventArgs};
16
16
  use crate::ffi::{
@@ -20,7 +20,8 @@ use crate::focus_adorner;
20
20
  use crate::focus_visibility;
21
21
  use crate::logger;
22
22
  use crate::node::{
23
- row, FlexBox, FlexBoxSurface, HasFlexBoxRoot, Node, NodeRef, TextCore, WeakFlexBox,
23
+ row, BoxStyleSurface, FlexBox, HasFlexBoxRoot, LayoutSurface, Node, NodeRef, TextNode,
24
+ WeakFlexBox,
24
25
  };
25
26
  use crate::signal::SubscriptionGuard;
26
27
  use crate::theme::{current_theme, subscribe, Theme};
@@ -88,12 +89,12 @@ fn resolve_text_input_colors(
88
89
 
89
90
  #[derive(Clone, Default)]
90
91
  struct ComboBoxEditorPresenter {
91
- editor_host: RefCell<Option<TextCore>>,
92
+ editor_host: RefCell<Option<TextNode>>,
92
93
  placeholder_host: RefCell<Option<FlexBox>>,
93
94
  }
94
95
 
95
96
  impl TextInputPresenter for ComboBoxEditorPresenter {
96
- fn bind(&self, editor_host: TextCore, placeholder_host: FlexBox) {
97
+ fn bind(&self, editor_host: TextNode, placeholder_host: FlexBox) {
97
98
  *self.editor_host.borrow_mut() = Some(editor_host);
98
99
  *self.placeholder_host.borrow_mut() = Some(placeholder_host);
99
100
  }
@@ -401,7 +402,7 @@ impl ComboBox {
401
402
  root.retained_node_ref().retain_attachment(shared.clone());
402
403
  shared.rebuild_filtered_indices();
403
404
 
404
- popup_list.popup_presenter.overlay_node().on_click({
405
+ popup_list.popup_presenter.overlay_node().on_pointer_click({
405
406
  let weak_shared = Rc::downgrade(&shared);
406
407
  move |_event| {
407
408
  if let Some(shared) = weak_shared.upgrade() {
@@ -589,7 +590,7 @@ impl ComboBox {
589
590
  self.shared.editor.editor_node().editor_command_keys(true);
590
591
 
591
592
  let weak_shared = Rc::downgrade(&self.shared);
592
- self.shared.chevron_host.on_click(move |event| {
593
+ self.shared.chevron_host.on_pointer_click(move |event| {
593
594
  let Some(shared) = weak_shared.upgrade() else {
594
595
  return;
595
596
  };
@@ -8,8 +8,8 @@ use crate::ffi::{
8
8
  use crate::logger::warn;
9
9
  use crate::navigation;
10
10
  use crate::node::{
11
- column, flex_box, grid, portal, Border, FlexBox, Grid, GridTrack, Node, NodeRef, TextNode,
12
- WeakFlexBox,
11
+ column, flex_box, grid, portal, Border, BoxStyleSurface, FlexBox, Grid, GridTrack,
12
+ LayoutSurface, Node, NodeRef, TextNode, ThemeBindable, WeakFlexBox,
13
13
  };
14
14
  use crate::popup_presenter::{PopupPresenter, PopupPresenterEventTarget};
15
15
  use crate::theme::{current_theme, subscribe, Theme};
@@ -816,8 +816,8 @@ impl ContextMenuEventTarget {
816
816
  return;
817
817
  };
818
818
  let state = self.state.borrow();
819
+ Grid::shared_size_scope(&panel, true);
819
820
  panel
820
- .shared_size_scope(true)
821
821
  .width(state.menu_width, Unit::Pixel)
822
822
  .bg_color(state.panel_background_color)
823
823
  .background_blur(state.panel_background_blur_sigma)
@@ -968,9 +968,9 @@ impl ContextMenu {
968
968
  let theme = current_theme();
969
969
  let root = portal();
970
970
  let panel = column();
971
+ panel.position_type(crate::ffi::PositionType::Absolute);
972
+ Grid::shared_size_scope(&panel, true);
971
973
  panel
972
- .position_type(crate::ffi::PositionType::Absolute)
973
- .shared_size_scope(true)
974
974
  .width(MENU_WIDTH, Unit::Pixel)
975
975
  .padding(4.0, 4.0, 4.0, 4.0)
976
976
  .border(1.0, theme.context_menu.panel_border_color);
@@ -1265,3 +1265,36 @@ impl crate::node::HasFlexBoxRoot for ContextMenu {
1265
1265
  &self.root
1266
1266
  }
1267
1267
  }
1268
+
1269
+ impl ThemeBindable for ContextMenu {
1270
+ fn theme_binding_node(&self) -> NodeRef {
1271
+ self.root.retained_node_ref()
1272
+ }
1273
+
1274
+ fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
1275
+ let root = self.root.downgrade();
1276
+ let panel = self.panel.downgrade();
1277
+ let popup_presenter = self.popup_presenter.downgrade();
1278
+ let items = Rc::downgrade(&self.items);
1279
+ let entries = self.entries.clone();
1280
+ let separators = self.separators.clone();
1281
+ let current_items = Rc::downgrade(&self.current_items);
1282
+ let current_item_tops = Rc::downgrade(&self.current_item_tops);
1283
+ let current_item_heights = Rc::downgrade(&self.current_item_heights);
1284
+ let state = Rc::downgrade(&self.state);
1285
+ Box::new(move || {
1286
+ Some(Self {
1287
+ root: root.upgrade()?,
1288
+ panel: panel.upgrade()?,
1289
+ popup_presenter: popup_presenter.upgrade()?,
1290
+ items: items.upgrade()?,
1291
+ entries: entries.clone(),
1292
+ separators: separators.clone(),
1293
+ current_items: current_items.upgrade()?,
1294
+ current_item_tops: current_item_tops.upgrade()?,
1295
+ current_item_heights: current_item_heights.upgrade()?,
1296
+ state: state.upgrade()?,
1297
+ })
1298
+ })
1299
+ }
1300
+ }
@@ -1,11 +1,14 @@
1
1
  use super::DialogAppearance;
2
- use super::{Button, Form};
2
+ use super::{Button, Clickable, Form};
3
3
  use crate::app;
4
4
  use crate::bindings::ui;
5
5
  use crate::ffi::{
6
6
  AlignItems, BorderStyle, FlexDirection, JustifyContent, PositionType, SemanticRole, Unit,
7
7
  };
8
- use crate::node::{flex_box, portal, Border, FlexBox, Node, NodeRef, TextNode, WeakFlexBox};
8
+ use crate::node::{
9
+ flex_box, portal, Border, ChildContainerSurface, FlexBox, Node, NodeRef, TextNode,
10
+ ThemeBindable, WeakFlexBox,
11
+ };
9
12
  use crate::theme::{current_theme, subscribe, Theme};
10
13
  use std::cell::RefCell;
11
14
  use std::rc::Rc;
@@ -363,7 +366,7 @@ impl Dialog {
363
366
  });
364
367
 
365
368
  let event_target = self.event_target();
366
- self.overlay.on_click(move |event| {
369
+ self.overlay.on_pointer_click(move |event| {
367
370
  event_target.handle_backdrop_click(event);
368
371
  });
369
372
 
@@ -434,6 +437,41 @@ impl crate::node::HasFlexBoxRoot for Dialog {
434
437
  }
435
438
  }
436
439
 
440
+ impl ThemeBindable for Dialog {
441
+ fn theme_binding_node(&self) -> NodeRef {
442
+ self.root.retained_node_ref()
443
+ }
444
+
445
+ fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
446
+ let root = self.root.downgrade();
447
+ let title_node = self.title_node.clone();
448
+ let body_node = self.body_node.clone();
449
+ let content_host = self.content_host.clone();
450
+ let accept_button = self.accept_button.clone();
451
+ let cancel_button = self.cancel_button.clone();
452
+ let buttons_row = self._buttons_row.clone();
453
+ let form = self.form.clone();
454
+ let card = self.card.clone();
455
+ let overlay = self.overlay.clone();
456
+ let state = self.state.clone();
457
+ Box::new(move || {
458
+ Some(Self {
459
+ root: root.upgrade()?,
460
+ title_node: title_node.clone(),
461
+ body_node: body_node.clone(),
462
+ content_host: content_host.clone(),
463
+ accept_button: accept_button.clone(),
464
+ cancel_button: cancel_button.clone(),
465
+ _buttons_row: buttons_row.clone(),
466
+ form: form.clone(),
467
+ card: card.clone(),
468
+ overlay: overlay.clone(),
469
+ state: state.clone(),
470
+ })
471
+ })
472
+ }
473
+ }
474
+
437
475
  impl DialogEventTarget {
438
476
  fn hide(&self) {
439
477
  let Some(root) = self.root.upgrade() else {
@@ -18,7 +18,7 @@ use crate::ffi::{AlignItems, CursorStyle, FlexDirection, KeyEventType, NodeType,
18
18
  use crate::focus_adorner;
19
19
  use crate::focus_visibility;
20
20
  use crate::logger;
21
- use crate::node::{row, FlexBox, FlexBoxSurface, HasFlexBoxRoot, Node, NodeRef, WeakFlexBox};
21
+ use crate::node::{row, BoxStyleSurface, FlexBox, HasFlexBoxRoot, Node, NodeRef, WeakFlexBox};
22
22
  use crate::persisted::{persisted_value_adapter, PersistedInt32Codec};
23
23
  use crate::signal::SubscriptionGuard;
24
24
  use crate::theme::{current_theme, subscribe};
@@ -243,7 +243,7 @@ impl Dropdown {
243
243
  *shared_slot.borrow_mut() = Some(Rc::downgrade(&shared));
244
244
  root.retained_node_ref().retain_attachment(shared.clone());
245
245
 
246
- popup_list.popup_presenter.overlay_node().on_click({
246
+ popup_list.popup_presenter.overlay_node().on_pointer_click({
247
247
  let weak_shared = Rc::downgrade(&shared);
248
248
  move |_event| {
249
249
  if let Some(shared) = weak_shared.upgrade() {
@@ -1,7 +1,7 @@
1
1
  use super::Button;
2
2
  use crate::event;
3
3
  use crate::ffi::{FlexDirection, KeyEventType, SemanticRole};
4
- use crate::node::{flex_box, Child, FlexBox, Node, NodeRef};
4
+ use crate::node::{flex_box, FlexBox, Node, NodeRef, ThemeBindable};
5
5
  use std::any::Any;
6
6
  use std::cell::{Cell, RefCell};
7
7
  use std::rc::Rc;
@@ -61,25 +61,6 @@ impl Form {
61
61
  self
62
62
  }
63
63
 
64
- pub fn child<T: Node>(&self, node: &T) -> &Self {
65
- self.shared.root.child(node);
66
- self
67
- }
68
-
69
- pub fn children<I, C>(&self, nodes: I) -> &Self
70
- where
71
- I: IntoIterator<Item = C>,
72
- C: Into<Child>,
73
- {
74
- for node in nodes {
75
- self.shared
76
- .root
77
- .retained_node_ref()
78
- .append_child_ref(&node.into().node_ref);
79
- }
80
- self
81
- }
82
-
83
64
  pub fn activate(&self) {
84
65
  if self.shared.key_filter_token.get() != 0
85
66
  || (self.shared.default_button.borrow().is_none()
@@ -233,3 +214,18 @@ impl crate::node::HasFlexBoxRoot for Form {
233
214
  &self.shared.root
234
215
  }
235
216
  }
217
+
218
+ impl ThemeBindable for Form {
219
+ fn theme_binding_node(&self) -> NodeRef {
220
+ self.shared.root.retained_node_ref()
221
+ }
222
+
223
+ fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
224
+ let shared = Rc::downgrade(&self.shared);
225
+ Box::new(move || {
226
+ Some(Self {
227
+ shared: shared.upgrade()?,
228
+ })
229
+ })
230
+ }
231
+ }
@@ -1,7 +1,7 @@
1
1
  use crate::controls::ButtonColors;
2
2
  use crate::ffi::{AlignItems, FlexDirection, JustifyContent};
3
3
  use crate::node::{
4
- flex_box, Border, Corners, EdgeInsets, FlexBox, PresenterHostStyle, Shadow, TextCore,
4
+ flex_box, Border, Corners, EdgeInsets, FlexBox, PresenterHostStyle, Shadow, TextNode,
5
5
  };
6
6
  use crate::theme::Theme;
7
7
  use crate::{FontStyle, FontWeight};
@@ -17,7 +17,7 @@ pub struct ButtonVisualState {
17
17
 
18
18
  pub trait ButtonPresenter {
19
19
  fn content_root(&self) -> FlexBox;
20
- fn label_node(&self) -> TextCore;
20
+ fn label_node(&self) -> TextNode;
21
21
  fn present(
22
22
  &self,
23
23
  theme: Theme,
@@ -33,12 +33,12 @@ pub trait ButtonTemplate {
33
33
  #[derive(Clone)]
34
34
  pub struct DefaultButtonPresenter {
35
35
  content_root: FlexBox,
36
- label_node: TextCore,
36
+ label_node: TextNode,
37
37
  }
38
38
 
39
39
  impl DefaultButtonPresenter {
40
40
  pub fn new() -> Self {
41
- let label_node = TextCore::new("");
41
+ let label_node = TextNode::new_core("");
42
42
  let content_root = flex_box();
43
43
  content_root
44
44
  .flex_direction(FlexDirection::Row)
@@ -57,7 +57,7 @@ impl ButtonPresenter for DefaultButtonPresenter {
57
57
  self.content_root.clone()
58
58
  }
59
59
 
60
- fn label_node(&self) -> TextCore {
60
+ fn label_node(&self) -> TextNode {
61
61
  self.label_node.clone()
62
62
  }
63
63
 
@@ -3,7 +3,7 @@ use super::pressable_indicator_presenter::{
3
3
  };
4
4
  use crate::controls::{LabeledControlColors, LabeledControlSizing};
5
5
  use crate::ffi::{AlignItems, JustifyContent, SemanticCheckedState, Unit};
6
- use crate::node::{flex_box, svg, FlexBox, SvgNode};
6
+ use crate::node::{flex_box, svg, BoxStyleSurface, FlexBox, SvgNode};
7
7
  use crate::theme::Theme;
8
8
  use std::rc::Rc;
9
9
 
@@ -1,9 +1,9 @@
1
- use crate::controls::LabeledControlColors;
1
+ use crate::controls::{ClickCallback, ClickEventArgs, LabeledControlColors};
2
2
  use crate::event::{FocusChangedEventArgs, KeyEventArgs, PointerEventArgs};
3
3
  use crate::ffi::{
4
4
  AlignItems, CursorStyle, FlexDirection, KeyEventType, PointerEventType, SemanticRole, Unit,
5
5
  };
6
- use crate::node::{flex_box, FlexBox, Node, TextCore, WeakFlexBox};
6
+ use crate::node::{flex_box, FlexBox, Node, TextNode, WeakFlexBox};
7
7
  use crate::theme::{current_theme, subscribe};
8
8
  use crate::{focus_adorner, focus_visibility};
9
9
  use std::cell::{Cell, RefCell};
@@ -27,7 +27,7 @@ pub(crate) struct PressableLabeledControlState {
27
27
  pub(crate) struct PressableLabeledControl {
28
28
  root: FlexBox,
29
29
  indicator_root: Rc<RefCell<FlexBox>>,
30
- label_node: TextCore,
30
+ label_node: TextNode,
31
31
  gap_node: FlexBox,
32
32
  label_host: FlexBox,
33
33
  hovered_state: Rc<Cell<bool>>,
@@ -41,6 +41,7 @@ pub(crate) struct PressableLabeledControl {
41
41
  label_text_color_override: Rc<Cell<Option<u32>>>,
42
42
  colors_value: Rc<Cell<Option<LabeledControlColors>>>,
43
43
  activation: Rc<RefCell<Option<ActivationCallback>>>,
44
+ click: Rc<RefCell<Option<ClickCallback>>>,
44
45
  state_changed: Rc<RefCell<Option<StateCallback>>>,
45
46
  key_handler: Rc<RefCell<Option<KeyCallback>>>,
46
47
  }
@@ -49,7 +50,7 @@ impl PressableLabeledControl {
49
50
  pub fn new(role: SemanticRole, label: impl Into<String>, indicator_root: FlexBox) -> Self {
50
51
  let label = label.into();
51
52
  let root = flex_box();
52
- let label_node = TextCore::new(&label);
53
+ let label_node = TextNode::new_core(&label);
53
54
  let gap_node = flex_box();
54
55
  let label_host = flex_box();
55
56
  label_host.child(&label_node);
@@ -82,6 +83,7 @@ impl PressableLabeledControl {
82
83
  label_text_color_override: Rc::new(Cell::new(None)),
83
84
  colors_value: Rc::new(Cell::new(None)),
84
85
  activation: Rc::new(RefCell::new(None)),
86
+ click: Rc::new(RefCell::new(None)),
85
87
  state_changed: Rc::new(RefCell::new(None)),
86
88
  key_handler: Rc::new(RefCell::new(None)),
87
89
  };
@@ -114,6 +116,7 @@ impl PressableLabeledControl {
114
116
  label_text_color_override: self.label_text_color_override.clone(),
115
117
  colors_value: self.colors_value.clone(),
116
118
  activation: self.activation.clone(),
119
+ click: self.click.clone(),
117
120
  state_changed: self.state_changed.clone(),
118
121
  key_handler: self.key_handler.clone(),
119
122
  }
@@ -133,6 +136,10 @@ impl PressableLabeledControl {
133
136
  *self.activation.borrow_mut() = Some(Rc::new(callback));
134
137
  }
135
138
 
139
+ pub(crate) fn on_click(&self, callback: impl Fn(ClickEventArgs) + 'static) {
140
+ *self.click.borrow_mut() = Some(Rc::new(callback));
141
+ }
142
+
136
143
  pub(crate) fn set_state_changed(
137
144
  &self,
138
145
  callback: impl Fn(PressableLabeledControlState) + 'static,
@@ -298,6 +305,7 @@ impl PressableLabeledControl {
298
305
  label_text_color_override: self.label_text_color_override.clone(),
299
306
  colors_value: self.colors_value.clone(),
300
307
  activation: self.activation.clone(),
308
+ click: self.click.clone(),
301
309
  state_changed: self.state_changed.clone(),
302
310
  key_handler: self.key_handler.clone(),
303
311
  }
@@ -329,7 +337,7 @@ impl PressableLabeledControl {
329
337
  pub(crate) struct WeakPressableLabeledControl {
330
338
  root: WeakFlexBox,
331
339
  indicator_root: Rc<RefCell<FlexBox>>,
332
- label_node: TextCore,
340
+ label_node: TextNode,
333
341
  gap_node: FlexBox,
334
342
  label_host: FlexBox,
335
343
  hovered_state: Rc<Cell<bool>>,
@@ -343,6 +351,7 @@ pub(crate) struct WeakPressableLabeledControl {
343
351
  label_text_color_override: Rc<Cell<Option<u32>>>,
344
352
  colors_value: Rc<Cell<Option<LabeledControlColors>>>,
345
353
  activation: Rc<RefCell<Option<ActivationCallback>>>,
354
+ click: Rc<RefCell<Option<ClickCallback>>>,
346
355
  state_changed: Rc<RefCell<Option<StateCallback>>>,
347
356
  key_handler: Rc<RefCell<Option<KeyCallback>>>,
348
357
  }
@@ -366,6 +375,7 @@ impl WeakPressableLabeledControl {
366
375
  label_text_color_override: self.label_text_color_override.clone(),
367
376
  colors_value: self.colors_value.clone(),
368
377
  activation: self.activation.clone(),
378
+ click: self.click.clone(),
369
379
  state_changed: self.state_changed.clone(),
370
380
  key_handler: self.key_handler.clone(),
371
381
  })
@@ -375,7 +385,7 @@ impl WeakPressableLabeledControl {
375
385
  #[allow(clippy::too_many_arguments)]
376
386
  fn sync_base_theme_parts(
377
387
  root: &FlexBox,
378
- label_node: &TextCore,
388
+ label_node: &TextNode,
379
389
  gap_node: &FlexBox,
380
390
  label_font_size_override: f32,
381
391
  label_font_family_override: Option<crate::FontFamily>,
@@ -435,7 +445,7 @@ fn is_space_key(event: &KeyEventArgs) -> bool {
435
445
  #[derive(Clone)]
436
446
  struct PressableLabeledControlEventTarget {
437
447
  weak_root: WeakFlexBox,
438
- label_node: TextCore,
448
+ label_node: TextNode,
439
449
  gap_node: FlexBox,
440
450
  hovered_state: Rc<Cell<bool>>,
441
451
  pressed_state: Rc<Cell<bool>>,
@@ -448,6 +458,7 @@ struct PressableLabeledControlEventTarget {
448
458
  label_text_color_override: Rc<Cell<Option<u32>>>,
449
459
  colors_value: Rc<Cell<Option<LabeledControlColors>>>,
450
460
  activation: Rc<RefCell<Option<ActivationCallback>>>,
461
+ click: Rc<RefCell<Option<ClickCallback>>>,
451
462
  state_changed: Rc<RefCell<Option<StateCallback>>>,
452
463
  key_handler: Rc<RefCell<Option<KeyCallback>>>,
453
464
  }
@@ -489,6 +500,9 @@ impl PressableLabeledControlEventTarget {
489
500
  if let Some(callback) = self.activation.borrow().clone() {
490
501
  callback(self.snapshot_state());
491
502
  }
503
+ if let Some(callback) = self.click.borrow().clone() {
504
+ callback(ClickEventArgs);
505
+ }
492
506
  }
493
507
 
494
508
  fn clear_pointer_state(&self) {
@@ -7,8 +7,8 @@ use crate::controls::{DropdownColors, DropdownSizing};
7
7
  use crate::ffi::{CursorStyle, FlexDirection, HandleValue, PositionType, SemanticRole, Unit};
8
8
  use crate::logger;
9
9
  use crate::node::{
10
- flex_box, portal, scroll_box, FlexBox, FlexBoxSurface, Node, NodeHandle, ScrollBarVisibility,
11
- ScrollBox,
10
+ flex_box, portal, scroll_box, ChildContainerSurface, FlexBox, LayoutSurface, Node, NodeHandle,
11
+ ScrollBarVisibility, ScrollBox,
12
12
  };
13
13
  use crate::popup_presenter::PopupPresenter;
14
14
  use crate::theme::current_theme;