@effindomv2/fui-rs 0.1.17 → 0.1.19
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.
- package/Cargo.toml +1 -1
- package/README.md +69 -0
- package/package.json +1 -1
- package/scripts/hostgen/rust-host-events.ts +43 -13
- package/src/app.rs +7 -0
- package/src/assets.rs +2 -2
- package/src/bindings/ui.rs +2 -0
- package/src/bridge_callbacks.rs +27 -17
- package/src/color.rs +112 -0
- package/src/controls/button.rs +1 -0
- package/src/controls/checkbox.rs +1 -0
- package/src/controls/combobox.rs +5 -3
- package/src/controls/dropdown.rs +3 -1
- package/src/controls/internal/pressable_labeled_control.rs +1 -0
- package/src/controls/internal/text_input_core.rs +7 -3
- package/src/controls/radio_button.rs +1 -0
- package/src/controls/shared.rs +2 -5
- package/src/controls/slider.rs +1 -0
- package/src/controls/switch.rs +1 -0
- package/src/controls/tests.rs +36 -7
- package/src/debug.rs +8 -5
- package/src/drag_drop.rs +1 -3
- package/src/drawing.rs +8 -0
- package/src/event.rs +39 -27
- package/src/fetch.rs +21 -7
- package/src/ffi.rs +3 -1
- package/src/file.rs +88 -59
- package/src/host_events.rs +41 -0
- package/src/lib.rs +55 -9
- package/src/node/core.rs +22 -21
- package/src/node/helpers.rs +1 -1
- package/src/node/mod.rs +1 -1
- package/src/node/scroll_bar.rs +101 -0
- package/src/node/scroll_box.rs +7 -0
- package/src/node/scroll_view.rs +20 -14
- package/src/node/virtual_list.rs +120 -33
- package/src/platform.rs +3 -0
- package/src/popup_presenter.rs +1 -0
- package/src/theme.rs +8 -48
- package/src/timers.rs +1 -1
- package/src/typography.rs +6 -14
- package/src/worker.rs +25 -9
- package/src/worker_runtime.rs +61 -17
package/src/node/scroll_view.rs
CHANGED
|
@@ -16,6 +16,12 @@ pub struct ScrollView {
|
|
|
16
16
|
active_animations: Rc<RefCell<ScrollViewAnimationState>>,
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
impl Default for ScrollView {
|
|
20
|
+
fn default() -> Self {
|
|
21
|
+
Self::new()
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
impl ScrollView {
|
|
20
26
|
pub fn new() -> Self {
|
|
21
27
|
let core = Rc::new(RefCell::new(NodeCore::new(NodeKind::ScrollView)));
|
|
@@ -473,6 +479,20 @@ impl ScrollView {
|
|
|
473
479
|
}
|
|
474
480
|
}
|
|
475
481
|
|
|
482
|
+
impl Node for ScrollView {
|
|
483
|
+
fn retained_node_ref(&self) -> NodeRef {
|
|
484
|
+
NodeRef::from_node(self.core.clone(), self.clone())
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
fn build_self(&self) {
|
|
488
|
+
apply_scroll_view_props(
|
|
489
|
+
self.handle(),
|
|
490
|
+
&self.props.borrow(),
|
|
491
|
+
self.core.borrow().behavior.clone(),
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
476
496
|
#[cfg(test)]
|
|
477
497
|
mod tests {
|
|
478
498
|
use super::*;
|
|
@@ -544,17 +564,3 @@ mod tests {
|
|
|
544
564
|
)));
|
|
545
565
|
}
|
|
546
566
|
}
|
|
547
|
-
|
|
548
|
-
impl Node for ScrollView {
|
|
549
|
-
fn retained_node_ref(&self) -> NodeRef {
|
|
550
|
-
NodeRef::from_node(self.core.clone(), self.clone())
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
fn build_self(&self) {
|
|
554
|
-
apply_scroll_view_props(
|
|
555
|
-
self.handle(),
|
|
556
|
-
&self.props.borrow(),
|
|
557
|
-
self.core.borrow().behavior.clone(),
|
|
558
|
-
);
|
|
559
|
-
}
|
|
560
|
-
}
|
package/src/node/virtual_list.rs
CHANGED
|
@@ -4,6 +4,7 @@ use crate::controls::selection_area;
|
|
|
4
4
|
use crate::controls::SelectionArea;
|
|
5
5
|
use crate::frame_scheduler::mark_needs_commit;
|
|
6
6
|
use crate::signal::Subscription;
|
|
7
|
+
use std::any::Any;
|
|
7
8
|
use std::cell::{Cell, RefCell};
|
|
8
9
|
use std::rc::Rc;
|
|
9
10
|
|
|
@@ -11,9 +12,9 @@ const FULL_SIZE: f32 = 100.0;
|
|
|
11
12
|
const DEFAULT_MAX_VISIBLE_ITEMS: i32 = 20;
|
|
12
13
|
const POOL_OVERSCAN_ITEMS: i32 = 2;
|
|
13
14
|
const MISSING_BIND_ITEM_MESSAGE: &str =
|
|
14
|
-
"VirtualList: item renderer not configured. Call .
|
|
15
|
+
"VirtualList: item renderer not configured. Call .on_bind_item() after construction.";
|
|
15
16
|
|
|
16
|
-
type VirtualListBinder = Rc<dyn Fn(
|
|
17
|
+
type VirtualListBinder = Rc<dyn Fn(usize, i32)>;
|
|
17
18
|
|
|
18
19
|
struct VirtualListInner {
|
|
19
20
|
root: FlexBox,
|
|
@@ -27,18 +28,28 @@ struct VirtualListInner {
|
|
|
27
28
|
pool_size: i32,
|
|
28
29
|
pool_rows: Vec<SelectionArea>,
|
|
29
30
|
pool_containers: Vec<FlexBox>,
|
|
31
|
+
row_state_owner: RefCell<Option<Rc<dyn Any>>>,
|
|
30
32
|
pool_item_index_by_row: RefCell<Vec<i32>>,
|
|
31
33
|
subscriptions: RefCell<Vec<Subscription>>,
|
|
32
34
|
current_first_visible_index: Cell<i32>,
|
|
33
35
|
current_last_visible_index: Cell<i32>,
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
pub struct VirtualList {
|
|
38
|
+
pub struct VirtualList<T = FlexBox> {
|
|
38
39
|
inner: Rc<VirtualListInner>,
|
|
40
|
+
row_states: Rc<Vec<T>>,
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
impl VirtualList {
|
|
43
|
+
impl<T> Clone for VirtualList<T> {
|
|
44
|
+
fn clone(&self) -> Self {
|
|
45
|
+
Self {
|
|
46
|
+
inner: self.inner.clone(),
|
|
47
|
+
row_states: self.row_states.clone(),
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
impl VirtualList<FlexBox> {
|
|
42
53
|
pub fn new(total_items: i32, item_height: f32) -> Self {
|
|
43
54
|
Self::with_max_visible(total_items, item_height, DEFAULT_MAX_VISIBLE_ITEMS)
|
|
44
55
|
}
|
|
@@ -105,13 +116,43 @@ impl VirtualList {
|
|
|
105
116
|
bottom_spacer,
|
|
106
117
|
pool_size,
|
|
107
118
|
pool_rows,
|
|
108
|
-
pool_containers,
|
|
119
|
+
pool_containers: pool_containers.clone(),
|
|
120
|
+
row_state_owner: RefCell::new(None),
|
|
109
121
|
pool_item_index_by_row: RefCell::new(pool_item_index_by_row),
|
|
110
122
|
subscriptions: RefCell::new(Vec::new()),
|
|
111
123
|
current_first_visible_index: Cell::new(-1),
|
|
112
124
|
current_last_visible_index: Cell::new(-1),
|
|
113
125
|
});
|
|
114
|
-
let
|
|
126
|
+
let row_states = Rc::new(pool_containers);
|
|
127
|
+
inner
|
|
128
|
+
.row_state_owner
|
|
129
|
+
.replace(Some(row_states.clone() as Rc<dyn Any>));
|
|
130
|
+
let list = Self { inner, row_states };
|
|
131
|
+
list.attach_listeners();
|
|
132
|
+
list
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
impl<T: 'static> VirtualList<T> {
|
|
137
|
+
pub fn item_template<U: 'static>(self, template: impl Fn(&FlexBox) -> U) -> VirtualList<U> {
|
|
138
|
+
let row_states = Rc::new(
|
|
139
|
+
self.inner
|
|
140
|
+
.pool_containers
|
|
141
|
+
.iter()
|
|
142
|
+
.map(template)
|
|
143
|
+
.collect::<Vec<_>>(),
|
|
144
|
+
);
|
|
145
|
+
self.inner
|
|
146
|
+
.row_state_owner
|
|
147
|
+
.replace(Some(row_states.clone() as Rc<dyn Any>));
|
|
148
|
+
*self.inner.bind_item.borrow_mut() = Rc::new(|_, _| panic!("{MISSING_BIND_ITEM_MESSAGE}"));
|
|
149
|
+
self.inner.current_first_visible_index.set(-1);
|
|
150
|
+
self.inner.current_last_visible_index.set(-1);
|
|
151
|
+
self.inner.subscriptions.borrow_mut().clear();
|
|
152
|
+
let list = VirtualList {
|
|
153
|
+
inner: self.inner,
|
|
154
|
+
row_states,
|
|
155
|
+
};
|
|
115
156
|
list.attach_listeners();
|
|
116
157
|
list
|
|
117
158
|
}
|
|
@@ -181,19 +222,17 @@ impl VirtualList {
|
|
|
181
222
|
self
|
|
182
223
|
}
|
|
183
224
|
|
|
184
|
-
pub fn on_bind_item(&self, renderer: impl Fn(&
|
|
185
|
-
|
|
225
|
+
pub fn on_bind_item(&self, renderer: impl Fn(&T, i32) + 'static) -> &Self {
|
|
226
|
+
let row_states = self.row_states.clone();
|
|
227
|
+
*self.inner.bind_item.borrow_mut() = Rc::new(move |pool_index, item_index| {
|
|
228
|
+
renderer(&row_states[pool_index], item_index);
|
|
229
|
+
});
|
|
186
230
|
self.inner.current_first_visible_index.set(-1);
|
|
187
231
|
self.inner.current_last_visible_index.set(-1);
|
|
188
232
|
self.rebuild_visible_range(true);
|
|
189
233
|
self
|
|
190
234
|
}
|
|
191
235
|
|
|
192
|
-
#[allow(non_snake_case)]
|
|
193
|
-
pub fn onBindItem(&self, renderer: impl Fn(&FlexBox, i32) + 'static) -> &Self {
|
|
194
|
-
self.on_bind_item(renderer)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
236
|
pub fn update_item_count(&self, next: i32) {
|
|
198
237
|
self.inner.total_items.set(next.max(0));
|
|
199
238
|
self.inner
|
|
@@ -217,27 +256,33 @@ impl VirtualList {
|
|
|
217
256
|
|
|
218
257
|
fn attach_listeners(&self) {
|
|
219
258
|
let weak = Rc::downgrade(&self.inner);
|
|
259
|
+
let weak_row_states = Rc::downgrade(&self.row_states);
|
|
220
260
|
self.inner
|
|
221
261
|
.subscriptions
|
|
222
262
|
.borrow_mut()
|
|
223
263
|
.push(self.inner.scroll_state.subscribe_offset_y(move || {
|
|
224
|
-
if let Some(inner) = weak.upgrade()
|
|
225
|
-
|
|
264
|
+
if let (Some(inner), Some(row_states)) = (weak.upgrade(), weak_row_states.upgrade())
|
|
265
|
+
{
|
|
266
|
+
VirtualList { inner, row_states }.handle_scroll_offset_changed();
|
|
226
267
|
}
|
|
227
268
|
}));
|
|
228
269
|
let weak = Rc::downgrade(&self.inner);
|
|
270
|
+
let weak_row_states = Rc::downgrade(&self.row_states);
|
|
229
271
|
self.inner.subscriptions.borrow_mut().push(
|
|
230
272
|
self.inner.scroll_state.subscribe_viewport_height(move || {
|
|
231
|
-
if let Some(inner) = weak.upgrade()
|
|
232
|
-
|
|
273
|
+
if let (Some(inner), Some(row_states)) = (weak.upgrade(), weak_row_states.upgrade())
|
|
274
|
+
{
|
|
275
|
+
VirtualList { inner, row_states }.handle_metrics_changed();
|
|
233
276
|
}
|
|
234
277
|
}),
|
|
235
278
|
);
|
|
236
279
|
let weak = Rc::downgrade(&self.inner);
|
|
280
|
+
let weak_row_states = Rc::downgrade(&self.row_states);
|
|
237
281
|
self.inner.subscriptions.borrow_mut().push(
|
|
238
282
|
self.inner.scroll_state.subscribe_content_height(move || {
|
|
239
|
-
if let Some(inner) = weak.upgrade()
|
|
240
|
-
|
|
283
|
+
if let (Some(inner), Some(row_states)) = (weak.upgrade(), weak_row_states.upgrade())
|
|
284
|
+
{
|
|
285
|
+
VirtualList { inner, row_states }.handle_metrics_changed();
|
|
241
286
|
}
|
|
242
287
|
}),
|
|
243
288
|
);
|
|
@@ -325,8 +370,12 @@ impl VirtualList {
|
|
|
325
370
|
let previous_item_index_by_row = self.inner.pool_item_index_by_row.borrow().clone();
|
|
326
371
|
let visible_items = (last_visible_index - first_visible_index) as usize;
|
|
327
372
|
|
|
328
|
-
for pool_index in
|
|
329
|
-
|
|
373
|
+
for (pool_index, previous_item_index) in previous_item_index_by_row
|
|
374
|
+
.iter()
|
|
375
|
+
.copied()
|
|
376
|
+
.enumerate()
|
|
377
|
+
.take(self.inner.pool_size as usize)
|
|
378
|
+
{
|
|
330
379
|
if previous_item_index != -1
|
|
331
380
|
&& (previous_item_index < first_visible_index
|
|
332
381
|
|| previous_item_index >= last_visible_index)
|
|
@@ -340,8 +389,7 @@ impl VirtualList {
|
|
|
340
389
|
if pool_index < visible_items {
|
|
341
390
|
let next_item_index = first_visible_index + pool_index as i32;
|
|
342
391
|
row_area.height(self.inner.item_height, Unit::Pixel);
|
|
343
|
-
|
|
344
|
-
self.render_item(container, next_item_index);
|
|
392
|
+
self.render_item(pool_index, next_item_index);
|
|
345
393
|
self.inner.pool_item_index_by_row.borrow_mut()[pool_index] = next_item_index;
|
|
346
394
|
} else {
|
|
347
395
|
self.hide_pool_item(pool_index);
|
|
@@ -450,9 +498,9 @@ impl VirtualList {
|
|
|
450
498
|
mark_needs_commit();
|
|
451
499
|
}
|
|
452
500
|
|
|
453
|
-
fn render_item(&self,
|
|
501
|
+
fn render_item(&self, pool_index: usize, index: i32) {
|
|
454
502
|
let binder = self.inner.bind_item.borrow().clone();
|
|
455
|
-
binder(
|
|
503
|
+
binder(pool_index, index);
|
|
456
504
|
}
|
|
457
505
|
|
|
458
506
|
fn max_offset_for_current_viewport(&self) -> f32 {
|
|
@@ -478,7 +526,7 @@ impl VirtualList {
|
|
|
478
526
|
}
|
|
479
527
|
}
|
|
480
528
|
|
|
481
|
-
impl Node for VirtualList {
|
|
529
|
+
impl<T: 'static> Node for VirtualList<T> {
|
|
482
530
|
fn retained_node_ref(&self) -> NodeRef {
|
|
483
531
|
let list = self.clone();
|
|
484
532
|
self.inner
|
|
@@ -507,22 +555,24 @@ impl Node for VirtualList {
|
|
|
507
555
|
}
|
|
508
556
|
}
|
|
509
557
|
|
|
510
|
-
impl HasFlexBoxRoot for VirtualList {
|
|
558
|
+
impl<T: 'static> HasFlexBoxRoot for VirtualList<T> {
|
|
511
559
|
fn flex_box_root(&self) -> &FlexBox {
|
|
512
560
|
&self.inner.root
|
|
513
561
|
}
|
|
514
562
|
}
|
|
515
563
|
|
|
516
|
-
impl ThemeBindable for VirtualList {
|
|
564
|
+
impl<T: 'static> ThemeBindable for VirtualList<T> {
|
|
517
565
|
fn theme_binding_node(&self) -> NodeRef {
|
|
518
566
|
self.inner.root.retained_node_ref()
|
|
519
567
|
}
|
|
520
568
|
|
|
521
569
|
fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
|
|
522
570
|
let weak = Rc::downgrade(&self.inner);
|
|
571
|
+
let weak_row_states = Rc::downgrade(&self.row_states);
|
|
523
572
|
Box::new(move || {
|
|
524
573
|
Some(VirtualList {
|
|
525
574
|
inner: weak.upgrade()?,
|
|
575
|
+
row_states: weak_row_states.upgrade()?,
|
|
526
576
|
})
|
|
527
577
|
})
|
|
528
578
|
}
|
|
@@ -583,7 +633,7 @@ mod tests {
|
|
|
583
633
|
let list = VirtualList::new(10_000, 20.0);
|
|
584
634
|
let captured_indices = rendered_indices.clone();
|
|
585
635
|
let captured_labels = labels.clone();
|
|
586
|
-
list.
|
|
636
|
+
list.on_bind_item(move |container, index| {
|
|
587
637
|
tracked_bind_virtual_list_item(&captured_indices, &captured_labels, container, index);
|
|
588
638
|
});
|
|
589
639
|
list.width(180.0, Unit::Pixel);
|
|
@@ -608,7 +658,7 @@ mod tests {
|
|
|
608
658
|
let list = VirtualList::new(10_000, 20.0);
|
|
609
659
|
let captured_indices = rendered_indices.clone();
|
|
610
660
|
let captured_labels = labels.clone();
|
|
611
|
-
list.
|
|
661
|
+
list.on_bind_item(move |container, index| {
|
|
612
662
|
tracked_bind_virtual_list_item(&captured_indices, &captured_labels, container, index);
|
|
613
663
|
});
|
|
614
664
|
list.width(180.0, Unit::Pixel);
|
|
@@ -653,7 +703,7 @@ mod tests {
|
|
|
653
703
|
let labels = Rc::new(RefCell::new(HashMap::new()));
|
|
654
704
|
let list = VirtualList::new(10_000, 24.0);
|
|
655
705
|
let captured_labels = labels.clone();
|
|
656
|
-
list.
|
|
706
|
+
list.on_bind_item(move |container, index| {
|
|
657
707
|
static_bind_virtual_list_item(&captured_labels, container, index);
|
|
658
708
|
});
|
|
659
709
|
list.height(120.0, Unit::Pixel);
|
|
@@ -676,7 +726,7 @@ mod tests {
|
|
|
676
726
|
let list = VirtualList::new(10_000, 20.0);
|
|
677
727
|
let captured_indices = rendered_indices.clone();
|
|
678
728
|
let captured_labels = labels.clone();
|
|
679
|
-
list.
|
|
729
|
+
list.on_bind_item(move |container, index| {
|
|
680
730
|
tracked_bind_virtual_list_item(&captured_indices, &captured_labels, container, index);
|
|
681
731
|
});
|
|
682
732
|
list.width(180.0, Unit::Pixel);
|
|
@@ -690,4 +740,41 @@ mod tests {
|
|
|
690
740
|
assert_eq!(rendered[rendered.len() - 1], 5);
|
|
691
741
|
list.dispose();
|
|
692
742
|
}
|
|
743
|
+
|
|
744
|
+
#[test]
|
|
745
|
+
fn typed_item_template_creates_one_retained_state_per_pool_row_and_rebinds_it() {
|
|
746
|
+
#[derive(Clone)]
|
|
747
|
+
struct Row {
|
|
748
|
+
label: TextNode,
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
ffi::test::reset();
|
|
752
|
+
let template_count = Rc::new(Cell::new(0));
|
|
753
|
+
let captured_template_count = template_count.clone();
|
|
754
|
+
let list = VirtualList::with_max_visible(10_000, 20.0, 4).item_template(move |container| {
|
|
755
|
+
captured_template_count.set(captured_template_count.get() + 1);
|
|
756
|
+
let label = text("");
|
|
757
|
+
container.child(&label);
|
|
758
|
+
Row { label }
|
|
759
|
+
});
|
|
760
|
+
let bound_indices = Rc::new(RefCell::new(Vec::new()));
|
|
761
|
+
let captured_indices = bound_indices.clone();
|
|
762
|
+
list.on_bind_item(move |row, index| {
|
|
763
|
+
captured_indices.borrow_mut().push(index);
|
|
764
|
+
row.label.text(format!("typed item {index}"));
|
|
765
|
+
});
|
|
766
|
+
list.height(60.0, Unit::Pixel);
|
|
767
|
+
Application::mount(list.clone());
|
|
768
|
+
|
|
769
|
+
assert_eq!(template_count.get(), 6);
|
|
770
|
+
bound_indices.borrow_mut().clear();
|
|
771
|
+
ffi::test::reset();
|
|
772
|
+
list.scroll_state().set_offset_y(40.0);
|
|
773
|
+
|
|
774
|
+
assert_eq!(&*bound_indices.borrow(), &[2, 3, 4, 5]);
|
|
775
|
+
assert!(!ffi::test::take_calls()
|
|
776
|
+
.iter()
|
|
777
|
+
.any(|call| matches!(call, Call::CreateNode { .. } | Call::DeleteNode { .. })));
|
|
778
|
+
Application::unmount();
|
|
779
|
+
}
|
|
693
780
|
}
|
package/src/platform.rs
CHANGED
|
@@ -260,6 +260,9 @@ pub fn show_open_folder_dialog(
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
#[cfg(feature = "native-runtime")]
|
|
263
|
+
/// # Safety
|
|
264
|
+
/// `payload` must reference at least `payload_length` readable bytes when
|
|
265
|
+
/// `payload_length` is non-zero.
|
|
263
266
|
#[no_mangle]
|
|
264
267
|
pub unsafe extern "C" fn __fui_complete_native_file_dialog(
|
|
265
268
|
request_id: u64,
|
package/src/popup_presenter.rs
CHANGED
package/src/theme.rs
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
use crate::generated::framework_host_services;
|
|
2
|
+
use crate::color::{
|
|
3
|
+
color_alpha, color_blue, color_green, color_red, mix_color, rgb, rgba, with_alpha,
|
|
4
|
+
};
|
|
2
5
|
use crate::signal::{Callback, Signal, SubscriptionGuard};
|
|
3
6
|
use crate::typography::{FontFamily, FontStack};
|
|
4
7
|
use std::cell::RefCell;
|
|
5
8
|
use std::rc::Rc;
|
|
6
9
|
|
|
7
|
-
const DEFAULT_ACCENT_COLOR: u32 =
|
|
8
|
-
const WHITE: u32 =
|
|
9
|
-
const BLACK: u32 =
|
|
10
|
+
const DEFAULT_ACCENT_COLOR: u32 = rgb(0x25, 0x63, 0xeb);
|
|
11
|
+
const WHITE: u32 = rgb(0xff, 0xff, 0xff);
|
|
12
|
+
const BLACK: u32 = rgb(0x00, 0x00, 0x00);
|
|
10
13
|
|
|
11
14
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
12
15
|
pub struct Colors {
|
|
@@ -166,49 +169,6 @@ fn default_fonts() -> Fonts {
|
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
171
|
|
|
169
|
-
const fn rgba(r: u32, g: u32, b: u32, a: u32) -> u32 {
|
|
170
|
-
(r << 24) | (g << 16) | (b << 8) | a
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
fn color_red(color: u32) -> u32 {
|
|
174
|
-
(color >> 24) & 0xff
|
|
175
|
-
}
|
|
176
|
-
fn color_green(color: u32) -> u32 {
|
|
177
|
-
(color >> 16) & 0xff
|
|
178
|
-
}
|
|
179
|
-
fn color_blue(color: u32) -> u32 {
|
|
180
|
-
(color >> 8) & 0xff
|
|
181
|
-
}
|
|
182
|
-
fn color_alpha(color: u32) -> u32 {
|
|
183
|
-
color & 0xff
|
|
184
|
-
}
|
|
185
|
-
fn clamp_unit(value: f32) -> f32 {
|
|
186
|
-
value.clamp(0.0, 1.0)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
fn mix_channel(from: u32, to: u32, amount: f32) -> u32 {
|
|
190
|
-
let weight = clamp_unit(amount);
|
|
191
|
-
(from as f32 + ((to as f32 - from as f32) * weight)).round() as u32
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
fn mix_color(from: u32, to: u32, amount: f32) -> u32 {
|
|
195
|
-
rgba(
|
|
196
|
-
mix_channel(color_red(from), color_red(to), amount),
|
|
197
|
-
mix_channel(color_green(from), color_green(to), amount),
|
|
198
|
-
mix_channel(color_blue(from), color_blue(to), amount),
|
|
199
|
-
mix_channel(color_alpha(from), color_alpha(to), amount),
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
fn with_alpha(color: u32, alpha: u32) -> u32 {
|
|
204
|
-
rgba(
|
|
205
|
-
color_red(color),
|
|
206
|
-
color_green(color),
|
|
207
|
-
color_blue(color),
|
|
208
|
-
alpha,
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
172
|
fn normalize_accent_color(color: u32) -> u32 {
|
|
213
173
|
if color == 0 {
|
|
214
174
|
return DEFAULT_ACCENT_COLOR;
|
|
@@ -517,12 +477,12 @@ trait Pipe: Sized {
|
|
|
517
477
|
|
|
518
478
|
impl<T> Pipe for T {}
|
|
519
479
|
|
|
520
|
-
#[no_mangle]
|
|
480
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
521
481
|
pub extern "C" fn __fui_on_system_dark_mode_changed(is_dark: bool) {
|
|
522
482
|
handle_system_dark_mode_changed(is_dark);
|
|
523
483
|
}
|
|
524
484
|
|
|
525
|
-
#[no_mangle]
|
|
485
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
526
486
|
pub extern "C" fn __fui_on_system_accent_color_changed(color: u32) {
|
|
527
487
|
handle_system_accent_color_changed(color);
|
|
528
488
|
}
|
package/src/timers.rs
CHANGED
|
@@ -58,7 +58,7 @@ pub fn cancel_all_timers() {
|
|
|
58
58
|
ACTIVE_TIMERS.with(|timers| timers.borrow_mut().clear());
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
#[no_mangle]
|
|
61
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
62
62
|
pub extern "C" fn __fui_on_timer(timer_id: u32) {
|
|
63
63
|
let callback = ACTIVE_TIMERS.with(|timers| timers.borrow_mut().remove(&timer_id));
|
|
64
64
|
if let Some(callback) = callback {
|
package/src/typography.rs
CHANGED
|
@@ -15,32 +15,22 @@ thread_local! {
|
|
|
15
15
|
static REGISTERED_FONT_FALLBACKS: RefCell<Vec<(u32, u32)>> = const { RefCell::new(Vec::new()) };
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
18
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
|
19
19
|
pub enum FontStyle {
|
|
20
|
+
#[default]
|
|
20
21
|
Normal = 0,
|
|
21
22
|
Italic = 1,
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
fn default() -> Self {
|
|
26
|
-
Self::Normal
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
25
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
|
31
26
|
pub enum FontWeight {
|
|
27
|
+
#[default]
|
|
32
28
|
Regular = 400,
|
|
33
29
|
Medium = 500,
|
|
34
30
|
Semibold = 600,
|
|
35
31
|
Bold = 700,
|
|
36
32
|
}
|
|
37
33
|
|
|
38
|
-
impl Default for FontWeight {
|
|
39
|
-
fn default() -> Self {
|
|
40
|
-
Self::Regular
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
34
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
45
35
|
pub struct FontFaceLoadedEventArgs {
|
|
46
36
|
pub font: FontFace,
|
|
@@ -308,6 +298,7 @@ pub struct FontFamily {
|
|
|
308
298
|
}
|
|
309
299
|
|
|
310
300
|
impl FontFamily {
|
|
301
|
+
#[allow(clippy::too_many_arguments)]
|
|
311
302
|
pub fn new(
|
|
312
303
|
regular_stack: FontStack,
|
|
313
304
|
bold_stack: Option<FontStack>,
|
|
@@ -331,6 +322,7 @@ impl FontFamily {
|
|
|
331
322
|
}
|
|
332
323
|
|
|
333
324
|
#[cfg(test)]
|
|
325
|
+
#[allow(clippy::too_many_arguments)]
|
|
334
326
|
pub(crate) fn from_ids(
|
|
335
327
|
regular: u32,
|
|
336
328
|
bold: u32,
|
package/src/worker.rs
CHANGED
|
@@ -108,7 +108,7 @@ impl Worker {
|
|
|
108
108
|
if already_started {
|
|
109
109
|
return self;
|
|
110
110
|
}
|
|
111
|
-
if input.
|
|
111
|
+
if input.len() > MAX_WORKER_START_INPUT_BYTES {
|
|
112
112
|
let (worker_id, callback) = {
|
|
113
113
|
let mut inner = self.inner.borrow_mut();
|
|
114
114
|
inner.started = true;
|
|
@@ -186,8 +186,14 @@ fn with_active_worker(worker_id: u32, callback: impl FnOnce(&mut WorkerInner)) {
|
|
|
186
186
|
callback(&mut inner);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
#[no_mangle]
|
|
190
|
-
|
|
189
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
190
|
+
/// # Safety
|
|
191
|
+
/// `text_ptr` must be null for an empty message or point to `text_len` readable bytes.
|
|
192
|
+
pub unsafe extern "C" fn __fui_on_worker_progress(
|
|
193
|
+
worker_id: u32,
|
|
194
|
+
text_ptr: *const u8,
|
|
195
|
+
text_len: u32,
|
|
196
|
+
) {
|
|
191
197
|
let message = if text_ptr.is_null() || text_len == 0 {
|
|
192
198
|
String::new()
|
|
193
199
|
} else {
|
|
@@ -204,8 +210,14 @@ pub extern "C" fn __fui_on_worker_progress(worker_id: u32, text_ptr: *const u8,
|
|
|
204
210
|
});
|
|
205
211
|
}
|
|
206
212
|
|
|
207
|
-
#[no_mangle]
|
|
208
|
-
|
|
213
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
214
|
+
/// # Safety
|
|
215
|
+
/// `text_ptr` must be null for an empty result or point to `text_len` readable bytes.
|
|
216
|
+
pub unsafe extern "C" fn __fui_on_worker_complete(
|
|
217
|
+
worker_id: u32,
|
|
218
|
+
text_ptr: *const u8,
|
|
219
|
+
text_len: u32,
|
|
220
|
+
) {
|
|
209
221
|
let result = if text_ptr.is_null() || text_len == 0 {
|
|
210
222
|
String::new()
|
|
211
223
|
} else {
|
|
@@ -228,8 +240,10 @@ pub extern "C" fn __fui_on_worker_complete(worker_id: u32, text_ptr: *const u8,
|
|
|
228
240
|
}
|
|
229
241
|
}
|
|
230
242
|
|
|
231
|
-
#[no_mangle]
|
|
232
|
-
|
|
243
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
244
|
+
/// # Safety
|
|
245
|
+
/// `text_ptr` must be null for an empty message or point to `text_len` readable bytes.
|
|
246
|
+
pub unsafe extern "C" fn __fui_on_worker_error(worker_id: u32, text_ptr: *const u8, text_len: u32) {
|
|
233
247
|
let message = if text_ptr.is_null() || text_len == 0 {
|
|
234
248
|
String::new()
|
|
235
249
|
} else {
|
|
@@ -300,8 +314,10 @@ mod tests {
|
|
|
300
314
|
result_clone.replace(event.result);
|
|
301
315
|
})
|
|
302
316
|
.start("hello");
|
|
303
|
-
|
|
304
|
-
|
|
317
|
+
unsafe {
|
|
318
|
+
super::__fui_on_worker_progress(1, b"25%".as_ptr(), 3);
|
|
319
|
+
super::__fui_on_worker_complete(1, b"done".as_ptr(), 4);
|
|
320
|
+
}
|
|
305
321
|
assert_eq!(&*progress.borrow(), "25%");
|
|
306
322
|
assert_eq!(&*result.borrow(), "done");
|
|
307
323
|
}
|