@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,344 @@
1
+ use crate::bindings::ui;
2
+ use crate::ffi::{PositionType, Unit};
3
+ use crate::node::{portal, FlexBox, Node, NodeHandle, WeakFlexBox};
4
+ use std::cell::RefCell;
5
+ use std::rc::Rc;
6
+
7
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
8
+ pub enum PopupPlacement {
9
+ Auto = 0,
10
+ Bottom = 1,
11
+ Top = 2,
12
+ Overlap = 3,
13
+ }
14
+
15
+ #[derive(Clone)]
16
+ #[doc(hidden)]
17
+ pub struct PopupPresenter {
18
+ root: FlexBox,
19
+ overlay_node: FlexBox,
20
+ surface_node: FlexBox,
21
+ semantic_scope_node: Option<FlexBox>,
22
+ state: Rc<RefCell<PopupPresenterState>>,
23
+ }
24
+
25
+ #[derive(Clone)]
26
+ pub(crate) struct PopupPresenterEventTarget {
27
+ root: WeakFlexBox,
28
+ overlay_node: WeakFlexBox,
29
+ state: Rc<RefCell<PopupPresenterState>>,
30
+ }
31
+
32
+ #[derive(Clone, Copy)]
33
+ struct PopupPresenterState {
34
+ open: bool,
35
+ semantic_scope_token: u32,
36
+ edge_padding: f32,
37
+ anchor_gap: f32,
38
+ placement: PopupPlacement,
39
+ backdrop_color: u32,
40
+ background_blur_sigma: f32,
41
+ surface_x: f32,
42
+ surface_y: f32,
43
+ }
44
+
45
+ impl Default for PopupPresenterState {
46
+ fn default() -> Self {
47
+ Self {
48
+ open: false,
49
+ semantic_scope_token: 0,
50
+ edge_padding: 8.0,
51
+ anchor_gap: 4.0,
52
+ placement: PopupPlacement::Auto,
53
+ backdrop_color: 0x00000000,
54
+ background_blur_sigma: 0.0,
55
+ surface_x: 0.0,
56
+ surface_y: 0.0,
57
+ }
58
+ }
59
+ }
60
+
61
+ impl PopupPresenter {
62
+ pub fn new(root: FlexBox, surface_node: FlexBox) -> Self {
63
+ Self::new_with_semantic_scope(root, surface_node.clone(), Some(surface_node))
64
+ }
65
+
66
+ pub fn new_with_semantic_scope(
67
+ root: FlexBox,
68
+ surface_node: FlexBox,
69
+ semantic_scope_node: Option<FlexBox>,
70
+ ) -> Self {
71
+ let overlay_node = FlexBox::default();
72
+ overlay_node
73
+ .position_type(PositionType::Absolute)
74
+ .position(0.0, 0.0)
75
+ .width(100.0, Unit::Percent)
76
+ .height(100.0, Unit::Percent)
77
+ .child(&surface_node);
78
+ surface_node.position_type(PositionType::Absolute);
79
+ let presenter = Self {
80
+ root,
81
+ overlay_node,
82
+ surface_node,
83
+ semantic_scope_node,
84
+ state: Rc::new(RefCell::new(PopupPresenterState::default())),
85
+ };
86
+ presenter.apply_backdrop_style();
87
+ presenter
88
+ }
89
+
90
+ pub fn with_default_root(surface_node: FlexBox) -> Self {
91
+ Self::new(portal(), surface_node)
92
+ }
93
+
94
+ pub fn root(&self) -> FlexBox {
95
+ self.root.clone()
96
+ }
97
+
98
+ pub fn overlay_node(&self) -> FlexBox {
99
+ self.overlay_node.clone()
100
+ }
101
+
102
+ pub fn surface_node(&self) -> FlexBox {
103
+ self.surface_node.clone()
104
+ }
105
+
106
+ pub fn is_open(&self) -> bool {
107
+ self.state.borrow().open
108
+ }
109
+
110
+ pub fn surface_x(&self) -> f32 {
111
+ self.state.borrow().surface_x
112
+ }
113
+
114
+ pub fn surface_y(&self) -> f32 {
115
+ self.state.borrow().surface_y
116
+ }
117
+
118
+ pub fn semantic_scope_token(&self) -> u32 {
119
+ self.state.borrow().semantic_scope_token
120
+ }
121
+
122
+ pub(crate) fn event_target(&self) -> PopupPresenterEventTarget {
123
+ PopupPresenterEventTarget {
124
+ root: self.root.downgrade(),
125
+ overlay_node: self.overlay_node.downgrade(),
126
+ state: self.state.clone(),
127
+ }
128
+ }
129
+
130
+ pub fn placement(&self, value: PopupPlacement) -> &Self {
131
+ self.state.borrow_mut().placement = value;
132
+ self
133
+ }
134
+
135
+ pub fn edge_padding(&self, value: f32) -> &Self {
136
+ self.state.borrow_mut().edge_padding = value.max(0.0);
137
+ self
138
+ }
139
+
140
+ pub fn anchor_gap(&self, value: f32) -> &Self {
141
+ self.state.borrow_mut().anchor_gap = value.max(0.0);
142
+ self
143
+ }
144
+
145
+ pub fn backdrop_color(&self, color: u32) -> &Self {
146
+ self.state.borrow_mut().backdrop_color = color;
147
+ self.apply_backdrop_style();
148
+ self
149
+ }
150
+
151
+ pub fn background_blur(&self, sigma: f32) -> &Self {
152
+ self.state.borrow_mut().background_blur_sigma = sigma.max(0.0);
153
+ self.apply_backdrop_style();
154
+ self
155
+ }
156
+
157
+ pub fn sync_overlay_bounds(&self) {
158
+ let popup_bounds = if self.root.handle() != NodeHandle::INVALID {
159
+ ui::get_bounds(self.root.handle().raw())
160
+ } else {
161
+ None
162
+ };
163
+ let overlay_x = popup_bounds.map(|bounds| -bounds[0]).unwrap_or(0.0);
164
+ let overlay_y = popup_bounds.map(|bounds| -bounds[1]).unwrap_or(0.0);
165
+ self.overlay_node
166
+ .position(overlay_x, overlay_y)
167
+ .width(ui::get_viewport_width(), Unit::Pixel)
168
+ .height(ui::get_viewport_height(), Unit::Pixel);
169
+ }
170
+
171
+ pub fn show_anchored(
172
+ &self,
173
+ anchor_x: f32,
174
+ anchor_y: f32,
175
+ anchor_width: f32,
176
+ anchor_height: f32,
177
+ surface_width: f32,
178
+ surface_height: f32,
179
+ ) {
180
+ let placement = self.state.borrow().placement;
181
+ self.show_anchored_with_placement(
182
+ anchor_x,
183
+ anchor_y,
184
+ anchor_width,
185
+ anchor_height,
186
+ surface_width,
187
+ surface_height,
188
+ placement,
189
+ );
190
+ }
191
+
192
+ pub fn show_anchored_with_placement(
193
+ &self,
194
+ anchor_x: f32,
195
+ anchor_y: f32,
196
+ _anchor_width: f32,
197
+ anchor_height: f32,
198
+ surface_width: f32,
199
+ surface_height: f32,
200
+ placement: PopupPlacement,
201
+ ) {
202
+ if self.root.handle() == NodeHandle::INVALID {
203
+ return;
204
+ }
205
+ self.sync_overlay_bounds();
206
+ let state = *self.state.borrow();
207
+ let clamped_width = if surface_width > 0.0 {
208
+ surface_width
209
+ } else {
210
+ 1.0
211
+ };
212
+ let clamped_height = if surface_height > 0.0 {
213
+ surface_height
214
+ } else {
215
+ 1.0
216
+ };
217
+ let viewport_width = ui::get_viewport_width();
218
+ let viewport_height = ui::get_viewport_height();
219
+ let max_x = state
220
+ .edge_padding
221
+ .max(viewport_width - clamped_width - state.edge_padding);
222
+ let max_y = state
223
+ .edge_padding
224
+ .max(viewport_height - clamped_height - state.edge_padding);
225
+ let below_y = anchor_y + anchor_height + state.anchor_gap;
226
+ let above_y = anchor_y - clamped_height - state.anchor_gap;
227
+ let fits_below = below_y <= max_y;
228
+ let fits_above = above_y >= state.edge_padding;
229
+ let mut panel_y = below_y;
230
+ if placement == PopupPlacement::Top {
231
+ panel_y = above_y;
232
+ } else if placement == PopupPlacement::Overlap {
233
+ panel_y = anchor_y;
234
+ } else if placement == PopupPlacement::Auto && !fits_below && fits_above {
235
+ panel_y = above_y;
236
+ }
237
+ self.set_surface_position(
238
+ anchor_x.clamp(state.edge_padding, max_x),
239
+ panel_y.clamp(state.edge_padding, max_y),
240
+ );
241
+ self.attach();
242
+ }
243
+
244
+ pub fn show_at_point(&self, x: f32, y: f32, surface_width: f32, surface_height: f32) {
245
+ if self.root.handle() == NodeHandle::INVALID {
246
+ return;
247
+ }
248
+ self.sync_overlay_bounds();
249
+ let state = *self.state.borrow();
250
+ let clamped_width = if surface_width > 0.0 {
251
+ surface_width
252
+ } else {
253
+ 1.0
254
+ };
255
+ let clamped_height = if surface_height > 0.0 {
256
+ surface_height
257
+ } else {
258
+ 1.0
259
+ };
260
+ let max_x = state
261
+ .edge_padding
262
+ .max(ui::get_viewport_width() - clamped_width - state.edge_padding);
263
+ let max_y = state
264
+ .edge_padding
265
+ .max(ui::get_viewport_height() - clamped_height - state.edge_padding);
266
+ self.set_surface_position(
267
+ x.clamp(state.edge_padding, max_x),
268
+ y.clamp(state.edge_padding, max_y),
269
+ );
270
+ self.attach();
271
+ }
272
+
273
+ pub fn hide(&self) {
274
+ if !self.is_open() && self.overlay_node.parent_handle().is_none() {
275
+ return;
276
+ }
277
+ self.root.remove_child(&self.overlay_node);
278
+ let mut state = self.state.borrow_mut();
279
+ state.open = false;
280
+ if state.semantic_scope_token != 0 {
281
+ ui::remove_semantic_scope(state.semantic_scope_token);
282
+ state.semantic_scope_token = 0;
283
+ }
284
+ }
285
+
286
+ pub fn dispose(&self) {
287
+ self.hide();
288
+ if self.overlay_node.handle() != NodeHandle::INVALID {
289
+ self.overlay_node.dispose();
290
+ }
291
+ }
292
+
293
+ fn attach(&self) {
294
+ self.root.child(&self.overlay_node);
295
+ self.state.borrow_mut().open = true;
296
+ let semantic_scope_handle = self
297
+ .semantic_scope_node
298
+ .as_ref()
299
+ .map(|node| node.handle())
300
+ .unwrap_or(NodeHandle::INVALID);
301
+ let mut state = self.state.borrow_mut();
302
+ if state.semantic_scope_token == 0 && semantic_scope_handle != NodeHandle::INVALID {
303
+ state.semantic_scope_token = ui::push_semantic_scope(semantic_scope_handle.raw());
304
+ }
305
+ }
306
+
307
+ fn apply_backdrop_style(&self) {
308
+ let state = *self.state.borrow();
309
+ self.overlay_node
310
+ .bg_color(state.backdrop_color)
311
+ .background_blur(state.background_blur_sigma);
312
+ }
313
+
314
+ fn set_surface_position(&self, x: f32, y: f32) {
315
+ {
316
+ let mut state = self.state.borrow_mut();
317
+ state.surface_x = x;
318
+ state.surface_y = y;
319
+ }
320
+ self.surface_node.position(x, y);
321
+ }
322
+ }
323
+
324
+ impl PopupPresenterEventTarget {
325
+ pub(crate) fn hide(&self) {
326
+ let Some(root) = self.root.upgrade() else {
327
+ return;
328
+ };
329
+ let Some(overlay_node) = self.overlay_node.upgrade() else {
330
+ return;
331
+ };
332
+ let open = self.state.borrow().open;
333
+ if !open && overlay_node.parent_handle().is_none() {
334
+ return;
335
+ }
336
+ root.remove_child(&overlay_node);
337
+ let mut state = self.state.borrow_mut();
338
+ state.open = false;
339
+ if state.semantic_scope_token != 0 {
340
+ ui::remove_semantic_scope(state.semantic_scope_token);
341
+ state.semantic_scope_token = 0;
342
+ }
343
+ }
344
+ }