@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
package/src/drawing.rs ADDED
@@ -0,0 +1,385 @@
1
+ use crate::ffi;
2
+ use crate::image_sampling::ImageSampling;
3
+ use crate::logger::error;
4
+ use crate::node::Node;
5
+ use crate::text::TextLayout;
6
+ use std::cell::RefCell;
7
+ use std::rc::Rc;
8
+
9
+ const OP_SAVE: u32 = 1;
10
+ const OP_RESTORE: u32 = 2;
11
+ const OP_TRANSLATE: u32 = 3;
12
+ const OP_SCALE: u32 = 4;
13
+ const OP_ROTATE: u32 = 5;
14
+ const OP_CLIP_RECT: u32 = 6;
15
+ const OP_CLIP_ROUND_RECT: u32 = 7;
16
+ const OP_DRAW_RECT: u32 = 10;
17
+ const OP_DRAW_CIRCLE: u32 = 11;
18
+ const OP_DRAW_LINE: u32 = 12;
19
+ const OP_DRAW_ROUND_RECT: u32 = 13;
20
+ const OP_DRAW_PATH: u32 = 20;
21
+ const OP_DRAW_TEXT_NODE: u32 = 30;
22
+ const OP_DRAW_IMAGE: u32 = 31;
23
+ const OP_DRAW_SVG: u32 = 32;
24
+
25
+ #[derive(Clone, Copy, Debug, PartialEq)]
26
+ pub struct Paint {
27
+ pub fill_color: u32,
28
+ pub stroke_color: u32,
29
+ pub stroke_width: f32,
30
+ }
31
+
32
+ impl Paint {
33
+ pub fn fill(color: u32) -> Self {
34
+ Self {
35
+ fill_color: color,
36
+ stroke_color: 0,
37
+ stroke_width: 0.0,
38
+ }
39
+ }
40
+
41
+ pub fn stroke(color: u32, width: f32) -> Self {
42
+ Self {
43
+ fill_color: 0,
44
+ stroke_color: color,
45
+ stroke_width: width,
46
+ }
47
+ }
48
+
49
+ pub fn filled_stroke(fill_color: u32, stroke_color: u32, stroke_width: f32) -> Self {
50
+ Self {
51
+ fill_color,
52
+ stroke_color,
53
+ stroke_width,
54
+ }
55
+ }
56
+
57
+ pub fn has_fill(self) -> bool {
58
+ (self.fill_color & 0xff) != 0
59
+ }
60
+
61
+ pub fn has_stroke(self) -> bool {
62
+ self.stroke_width > 0.0 && (self.stroke_color & 0xff) != 0
63
+ }
64
+ }
65
+
66
+ pub struct Path {
67
+ id: u32,
68
+ disposed: bool,
69
+ }
70
+
71
+ impl Path {
72
+ pub fn new() -> Self {
73
+ let id = unsafe { ffi::fui_path_create() };
74
+ Self {
75
+ id,
76
+ disposed: false,
77
+ }
78
+ }
79
+
80
+ pub fn id(&self) -> u32 {
81
+ self.id
82
+ }
83
+
84
+ pub fn move_to(&mut self, x: f32, y: f32) -> &mut Self {
85
+ unsafe { ffi::fui_path_move_to(self.id, x, y) };
86
+ self
87
+ }
88
+
89
+ pub fn line_to(&mut self, x: f32, y: f32) -> &mut Self {
90
+ unsafe { ffi::fui_path_line_to(self.id, x, y) };
91
+ self
92
+ }
93
+
94
+ pub fn quad_to(&mut self, cx: f32, cy: f32, x: f32, y: f32) -> &mut Self {
95
+ unsafe { ffi::fui_path_quad_to(self.id, cx, cy, x, y) };
96
+ self
97
+ }
98
+
99
+ pub fn cubic_to(
100
+ &mut self,
101
+ cx1: f32,
102
+ cy1: f32,
103
+ cx2: f32,
104
+ cy2: f32,
105
+ x: f32,
106
+ y: f32,
107
+ ) -> &mut Self {
108
+ unsafe { ffi::fui_path_cubic_to(self.id, cx1, cy1, cx2, cy2, x, y) };
109
+ self
110
+ }
111
+
112
+ pub fn close(&mut self) -> &mut Self {
113
+ unsafe { ffi::fui_path_close(self.id) };
114
+ self
115
+ }
116
+
117
+ pub fn add_rect(&mut self, x: f32, y: f32, w: f32, h: f32) -> &mut Self {
118
+ unsafe { ffi::fui_path_add_rect(self.id, x, y, w, h) };
119
+ self
120
+ }
121
+
122
+ pub fn add_circle(&mut self, cx: f32, cy: f32, r: f32) -> &mut Self {
123
+ unsafe { ffi::fui_path_add_circle(self.id, cx, cy, r) };
124
+ self
125
+ }
126
+ }
127
+
128
+ impl Drop for Path {
129
+ fn drop(&mut self) {
130
+ if !self.disposed {
131
+ unsafe { ffi::fui_path_destroy(self.id) };
132
+ self.disposed = true;
133
+ }
134
+ }
135
+ }
136
+
137
+ #[derive(Default)]
138
+ struct DrawContextState {
139
+ canvas_ptr: usize,
140
+ words: Vec<u32>,
141
+ }
142
+
143
+ #[derive(Clone, Default)]
144
+ pub struct DrawContext {
145
+ inner: Rc<RefCell<DrawContextState>>,
146
+ }
147
+
148
+ impl DrawContext {
149
+ pub fn new(canvas_ptr: usize) -> Self {
150
+ Self {
151
+ inner: Rc::new(RefCell::new(DrawContextState {
152
+ canvas_ptr,
153
+ words: Vec::new(),
154
+ })),
155
+ }
156
+ }
157
+
158
+ fn push_float(words: &mut Vec<u32>, value: f32) {
159
+ words.push(value.to_bits());
160
+ }
161
+
162
+ pub fn flush(&self) {
163
+ let mut state = self.inner.borrow_mut();
164
+ if state.words.is_empty() {
165
+ return;
166
+ }
167
+ unsafe {
168
+ ffi::fui_canvas_draw_batch(
169
+ state.canvas_ptr,
170
+ state.words.as_ptr() as usize,
171
+ state.words.len() as u32,
172
+ )
173
+ };
174
+ state.words.clear();
175
+ }
176
+
177
+ pub fn save(&self) {
178
+ self.inner.borrow_mut().words.push(OP_SAVE);
179
+ }
180
+
181
+ pub fn restore(&self) {
182
+ self.inner.borrow_mut().words.push(OP_RESTORE);
183
+ }
184
+
185
+ pub fn translate(&self, x: f32, y: f32) {
186
+ let mut state = self.inner.borrow_mut();
187
+ state.words.push(OP_TRANSLATE);
188
+ Self::push_float(&mut state.words, x);
189
+ Self::push_float(&mut state.words, y);
190
+ }
191
+
192
+ pub fn scale(&self, sx: f32, sy: f32) {
193
+ let mut state = self.inner.borrow_mut();
194
+ state.words.push(OP_SCALE);
195
+ Self::push_float(&mut state.words, sx);
196
+ Self::push_float(&mut state.words, sy);
197
+ }
198
+
199
+ pub fn rotate(&self, degrees: f32) {
200
+ let mut state = self.inner.borrow_mut();
201
+ state.words.push(OP_ROTATE);
202
+ Self::push_float(&mut state.words, degrees);
203
+ }
204
+
205
+ pub fn clip_rect(&self, x: f32, y: f32, w: f32, h: f32) {
206
+ let mut state = self.inner.borrow_mut();
207
+ state.words.push(OP_CLIP_RECT);
208
+ Self::push_float(&mut state.words, x);
209
+ Self::push_float(&mut state.words, y);
210
+ Self::push_float(&mut state.words, w);
211
+ Self::push_float(&mut state.words, h);
212
+ }
213
+
214
+ pub fn clip_round_rect(
215
+ &self,
216
+ x: f32,
217
+ y: f32,
218
+ w: f32,
219
+ h: f32,
220
+ tl: f32,
221
+ tr: f32,
222
+ br: f32,
223
+ bl: f32,
224
+ ) {
225
+ let mut state = self.inner.borrow_mut();
226
+ state.words.push(OP_CLIP_ROUND_RECT);
227
+ Self::push_float(&mut state.words, x);
228
+ Self::push_float(&mut state.words, y);
229
+ Self::push_float(&mut state.words, w);
230
+ Self::push_float(&mut state.words, h);
231
+ Self::push_float(&mut state.words, tl);
232
+ Self::push_float(&mut state.words, tr);
233
+ Self::push_float(&mut state.words, br);
234
+ Self::push_float(&mut state.words, bl);
235
+ }
236
+
237
+ pub fn draw_rect(&self, x: f32, y: f32, w: f32, h: f32, paint: Paint) {
238
+ let mut state = self.inner.borrow_mut();
239
+ state.words.push(OP_DRAW_RECT);
240
+ Self::push_float(&mut state.words, x);
241
+ Self::push_float(&mut state.words, y);
242
+ Self::push_float(&mut state.words, w);
243
+ Self::push_float(&mut state.words, h);
244
+ state.words.push(paint.fill_color);
245
+ state.words.push(paint.stroke_color);
246
+ Self::push_float(&mut state.words, paint.stroke_width);
247
+ }
248
+
249
+ pub fn draw_circle(&self, cx: f32, cy: f32, radius: f32, paint: Paint) {
250
+ let mut state = self.inner.borrow_mut();
251
+ state.words.push(OP_DRAW_CIRCLE);
252
+ Self::push_float(&mut state.words, cx);
253
+ Self::push_float(&mut state.words, cy);
254
+ Self::push_float(&mut state.words, radius);
255
+ state.words.push(paint.fill_color);
256
+ state.words.push(paint.stroke_color);
257
+ Self::push_float(&mut state.words, paint.stroke_width);
258
+ }
259
+
260
+ pub fn draw_line(&self, x1: f32, y1: f32, x2: f32, y2: f32, color: u32, stroke_width: f32) {
261
+ let mut state = self.inner.borrow_mut();
262
+ state.words.push(OP_DRAW_LINE);
263
+ Self::push_float(&mut state.words, x1);
264
+ Self::push_float(&mut state.words, y1);
265
+ Self::push_float(&mut state.words, x2);
266
+ Self::push_float(&mut state.words, y2);
267
+ state.words.push(color);
268
+ Self::push_float(&mut state.words, stroke_width);
269
+ }
270
+
271
+ pub fn draw_round_rect(&self, x: f32, y: f32, w: f32, h: f32, rx: f32, ry: f32, paint: Paint) {
272
+ let mut state = self.inner.borrow_mut();
273
+ state.words.push(OP_DRAW_ROUND_RECT);
274
+ Self::push_float(&mut state.words, x);
275
+ Self::push_float(&mut state.words, y);
276
+ Self::push_float(&mut state.words, w);
277
+ Self::push_float(&mut state.words, h);
278
+ Self::push_float(&mut state.words, rx);
279
+ Self::push_float(&mut state.words, ry);
280
+ state.words.push(paint.fill_color);
281
+ state.words.push(paint.stroke_color);
282
+ Self::push_float(&mut state.words, paint.stroke_width);
283
+ }
284
+
285
+ pub fn draw_path(&self, path: &Path, paint: Paint) {
286
+ let mut state = self.inner.borrow_mut();
287
+ state.words.push(OP_DRAW_PATH);
288
+ state.words.push(path.id());
289
+ state.words.push(paint.fill_color);
290
+ state.words.push(paint.stroke_color);
291
+ Self::push_float(&mut state.words, paint.stroke_width);
292
+ }
293
+
294
+ pub fn draw_text_node<T: Node>(&self, node: &T, x: f32, y: f32) {
295
+ let handle = node.handle().raw();
296
+ let mut state = self.inner.borrow_mut();
297
+ state.words.push(OP_DRAW_TEXT_NODE);
298
+ state.words.push(handle as u32);
299
+ state.words.push((handle >> 32) as u32);
300
+ Self::push_float(&mut state.words, x);
301
+ Self::push_float(&mut state.words, y);
302
+ }
303
+
304
+ pub fn draw_text_layout(&self, layout: &TextLayout, x: f32, y: f32) {
305
+ if !layout.is_ready() {
306
+ error(
307
+ "TextLayout",
308
+ "DrawContext.draw_text_layout() called before the TextLayout was ready; register on_ready and draw after the callback.",
309
+ );
310
+ return;
311
+ }
312
+ let node = layout.draw_node();
313
+ self.draw_text_node(&node, x, y);
314
+ }
315
+
316
+ pub fn draw_image(&self, texture_id: u32, x: f32, y: f32, w: f32, h: f32) {
317
+ self.draw_image_sampling(texture_id, x, y, w, h, ImageSampling::linear());
318
+ }
319
+
320
+ pub fn draw_image_sampling(
321
+ &self,
322
+ texture_id: u32,
323
+ x: f32,
324
+ y: f32,
325
+ w: f32,
326
+ h: f32,
327
+ sampling: ImageSampling,
328
+ ) {
329
+ let mut state = self.inner.borrow_mut();
330
+ state.words.push(OP_DRAW_IMAGE);
331
+ state.words.push(texture_id);
332
+ Self::push_float(&mut state.words, x);
333
+ Self::push_float(&mut state.words, y);
334
+ Self::push_float(&mut state.words, w);
335
+ Self::push_float(&mut state.words, h);
336
+ state.words.push(sampling.ffi_kind() as u32);
337
+ state.words.push(sampling.max_aniso());
338
+ }
339
+
340
+ pub fn draw_svg(&self, svg_id: u32, x: f32, y: f32, w: f32, h: f32) {
341
+ let mut state = self.inner.borrow_mut();
342
+ state.words.push(OP_DRAW_SVG);
343
+ state.words.push(svg_id);
344
+ Self::push_float(&mut state.words, x);
345
+ Self::push_float(&mut state.words, y);
346
+ Self::push_float(&mut state.words, w);
347
+ Self::push_float(&mut state.words, h);
348
+ }
349
+ }
350
+
351
+ #[cfg(test)]
352
+ mod tests {
353
+ use super::{DrawContext, Paint, Path};
354
+ use crate::ffi::{self, Call};
355
+ use crate::image_sampling::ImageSampling;
356
+
357
+ #[test]
358
+ fn path_and_draw_context_emit_batched_host_calls() {
359
+ ffi::test::reset();
360
+
361
+ let mut path = Path::new();
362
+ path.move_to(1.0, 2.0)
363
+ .line_to(3.0, 4.0)
364
+ .add_circle(8.0, 9.0, 10.0);
365
+
366
+ let ctx = DrawContext::new(77);
367
+ ctx.draw_rect(0.0, 1.0, 20.0, 30.0, Paint::fill(0xFF00FFFF));
368
+ ctx.draw_path(&path, Paint::stroke(0xFFFFFFFF, 2.0));
369
+ ctx.draw_image_sampling(9, 0.0, 0.0, 40.0, 50.0, ImageSampling::linear());
370
+ ctx.flush();
371
+
372
+ let calls = ffi::test::take_calls();
373
+ assert!(calls
374
+ .iter()
375
+ .any(|call| matches!(call, Call::PathCreate { .. })));
376
+ assert!(calls.iter().any(|call| matches!(
377
+ call,
378
+ Call::PathMoveTo { x, y, .. } if (*x - 1.0).abs() < f32::EPSILON && (*y - 2.0).abs() < f32::EPSILON
379
+ )));
380
+ assert!(calls.iter().any(|call| matches!(
381
+ call,
382
+ Call::CanvasDrawBatch { canvas_ptr: 77, words } if !words.is_empty()
383
+ )));
384
+ }
385
+ }