@effindomv2/fui-rs 0.1.16 → 0.1.18
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 +3 -2
- package/scripts/build.sh +6 -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/bitmap.rs +39 -3
- package/src/bridge_callbacks.rs +27 -17
- 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/slider.rs +1 -0
- package/src/controls/switch.rs +1 -0
- package/src/controls/tests.rs +19 -7
- package/src/debug.rs +8 -5
- package/src/drag_drop.rs +1 -3
- package/src/drawing.rs +55 -1
- 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 +52 -9
- package/src/node/core.rs +7 -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/text_node.rs +4 -0
- package/src/node/virtual_list.rs +120 -33
- package/src/platform.rs +3 -0
- package/src/popup_presenter.rs +1 -0
- package/src/text.rs +41 -4
- package/src/theme.rs +2 -2
- package/src/timers.rs +1 -1
- package/src/typography.rs +15 -15
- package/src/worker.rs +25 -9
- package/src/worker_runtime.rs +61 -17
package/src/file.rs
CHANGED
|
@@ -1124,11 +1124,8 @@ fn finish_worker_process(
|
|
|
1124
1124
|
Option<FileWorkerCompleteCallback>,
|
|
1125
1125
|
Option<FileErrorCallback>,
|
|
1126
1126
|
)> {
|
|
1127
|
-
let
|
|
1128
|
-
|
|
1129
|
-
else {
|
|
1130
|
-
return None;
|
|
1131
|
-
};
|
|
1127
|
+
let request = ACTIVE_WORKER_PROCESS_REQUESTS
|
|
1128
|
+
.with(|requests| requests.borrow_mut().remove(&request_id))?;
|
|
1132
1129
|
let mut inner = request.borrow_mut();
|
|
1133
1130
|
if inner.finished {
|
|
1134
1131
|
return None;
|
|
@@ -1160,8 +1157,10 @@ pub fn reset_file_runtime() {
|
|
|
1160
1157
|
NEXT_FILE_REQUEST_ID.with(|slot| *slot.borrow_mut() = 1);
|
|
1161
1158
|
}
|
|
1162
1159
|
|
|
1163
|
-
#[no_mangle]
|
|
1164
|
-
|
|
1160
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1161
|
+
/// # Safety
|
|
1162
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1163
|
+
pub unsafe extern "C" fn __fui_on_file_pick_result(
|
|
1165
1164
|
request_id: u32,
|
|
1166
1165
|
status: u32,
|
|
1167
1166
|
payload_ptr: *const u8,
|
|
@@ -1191,8 +1190,10 @@ pub extern "C" fn __fui_on_file_pick_result(
|
|
|
1191
1190
|
);
|
|
1192
1191
|
}
|
|
1193
1192
|
|
|
1194
|
-
#[no_mangle]
|
|
1195
|
-
|
|
1193
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1194
|
+
/// # Safety
|
|
1195
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1196
|
+
pub unsafe extern "C" fn __fui_on_file_read_result(
|
|
1196
1197
|
request_id: u32,
|
|
1197
1198
|
status: u32,
|
|
1198
1199
|
offset_bytes: u64,
|
|
@@ -1227,8 +1228,10 @@ pub extern "C" fn __fui_on_file_read_result(
|
|
|
1227
1228
|
);
|
|
1228
1229
|
}
|
|
1229
1230
|
|
|
1230
|
-
#[no_mangle]
|
|
1231
|
-
|
|
1231
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1232
|
+
/// # Safety
|
|
1233
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1234
|
+
pub unsafe extern "C" fn __fui_on_file_save_result(
|
|
1232
1235
|
request_id: u32,
|
|
1233
1236
|
status: u32,
|
|
1234
1237
|
written_bytes: u64,
|
|
@@ -1264,8 +1267,10 @@ pub extern "C" fn __fui_on_file_save_result(
|
|
|
1264
1267
|
);
|
|
1265
1268
|
}
|
|
1266
1269
|
|
|
1267
|
-
#[no_mangle]
|
|
1268
|
-
|
|
1270
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1271
|
+
/// # Safety
|
|
1272
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1273
|
+
pub unsafe extern "C" fn __fui_on_file_writer_created(
|
|
1269
1274
|
request_id: u32,
|
|
1270
1275
|
status: u32,
|
|
1271
1276
|
payload_ptr: *const u8,
|
|
@@ -1301,8 +1306,10 @@ pub extern "C" fn __fui_on_file_writer_created(
|
|
|
1301
1306
|
);
|
|
1302
1307
|
}
|
|
1303
1308
|
|
|
1304
|
-
#[no_mangle]
|
|
1305
|
-
|
|
1309
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1310
|
+
/// # Safety
|
|
1311
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1312
|
+
pub unsafe extern "C" fn __fui_on_file_write_result(
|
|
1306
1313
|
request_id: u32,
|
|
1307
1314
|
status: u32,
|
|
1308
1315
|
written_bytes: u64,
|
|
@@ -1332,8 +1339,10 @@ pub extern "C" fn __fui_on_file_write_result(
|
|
|
1332
1339
|
);
|
|
1333
1340
|
}
|
|
1334
1341
|
|
|
1335
|
-
#[no_mangle]
|
|
1336
|
-
|
|
1342
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1343
|
+
/// # Safety
|
|
1344
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1345
|
+
pub unsafe extern "C" fn __fui_on_file_finish_result(
|
|
1337
1346
|
request_id: u32,
|
|
1338
1347
|
status: u32,
|
|
1339
1348
|
written_bytes: u64,
|
|
@@ -1370,8 +1379,10 @@ pub extern "C" fn __fui_on_file_finish_result(
|
|
|
1370
1379
|
);
|
|
1371
1380
|
}
|
|
1372
1381
|
|
|
1373
|
-
#[no_mangle]
|
|
1374
|
-
|
|
1382
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1383
|
+
/// # Safety
|
|
1384
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1385
|
+
pub unsafe extern "C" fn __fui_on_file_worker_process_progress(
|
|
1375
1386
|
request_id: u32,
|
|
1376
1387
|
processed_bytes: u64,
|
|
1377
1388
|
total_bytes: u64,
|
|
@@ -1398,8 +1409,10 @@ pub extern "C" fn __fui_on_file_worker_process_progress(
|
|
|
1398
1409
|
}
|
|
1399
1410
|
}
|
|
1400
1411
|
|
|
1401
|
-
#[no_mangle]
|
|
1402
|
-
|
|
1412
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1413
|
+
/// # Safety
|
|
1414
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1415
|
+
pub unsafe extern "C" fn __fui_on_file_worker_process_chunk(
|
|
1403
1416
|
request_id: u32,
|
|
1404
1417
|
offset_bytes: u64,
|
|
1405
1418
|
file_size_bytes: u64,
|
|
@@ -1426,8 +1439,10 @@ pub extern "C" fn __fui_on_file_worker_process_chunk(
|
|
|
1426
1439
|
}
|
|
1427
1440
|
}
|
|
1428
1441
|
|
|
1429
|
-
#[no_mangle]
|
|
1430
|
-
|
|
1442
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1443
|
+
/// # Safety
|
|
1444
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1445
|
+
pub unsafe extern "C" fn __fui_on_file_worker_process_complete(
|
|
1431
1446
|
request_id: u32,
|
|
1432
1447
|
processed_bytes: u64,
|
|
1433
1448
|
payload_ptr: *const u8,
|
|
@@ -1451,8 +1466,10 @@ pub extern "C" fn __fui_on_file_worker_process_complete(
|
|
|
1451
1466
|
}
|
|
1452
1467
|
}
|
|
1453
1468
|
|
|
1454
|
-
#[no_mangle]
|
|
1455
|
-
|
|
1469
|
+
#[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
|
|
1470
|
+
/// # Safety
|
|
1471
|
+
/// `payload_ptr` must be null for an empty payload or point to `payload_len` readable bytes.
|
|
1472
|
+
pub unsafe extern "C" fn __fui_on_file_worker_process_error(
|
|
1456
1473
|
request_id: u32,
|
|
1457
1474
|
status: u32,
|
|
1458
1475
|
payload_ptr: *const u8,
|
|
@@ -1513,12 +1530,14 @@ mod tests {
|
|
|
1513
1530
|
payload.extend_from_slice(b"note.txt");
|
|
1514
1531
|
payload.extend_from_slice(&10u32.to_le_bytes());
|
|
1515
1532
|
payload.extend_from_slice(b"text/plain");
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1533
|
+
unsafe {
|
|
1534
|
+
super::__fui_on_file_pick_result(
|
|
1535
|
+
1,
|
|
1536
|
+
FILE_STATUS_SUCCESS,
|
|
1537
|
+
payload.as_ptr(),
|
|
1538
|
+
payload.len() as u32,
|
|
1539
|
+
);
|
|
1540
|
+
}
|
|
1522
1541
|
|
|
1523
1542
|
let picked = picked.borrow();
|
|
1524
1543
|
assert_eq!(picked.len(), 1);
|
|
@@ -1542,14 +1561,16 @@ mod tests {
|
|
|
1542
1561
|
assert!(calls.iter().any(|call| matches!(call, Call::FileReadChunk { request_id, file_id, offset_bytes, max_bytes } if *request_id == 1 && file_id == "picked-1" && *offset_bytes == 10 && *max_bytes == 8)));
|
|
1543
1562
|
|
|
1544
1563
|
let bytes = b"1234".to_vec();
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1564
|
+
unsafe {
|
|
1565
|
+
super::__fui_on_file_read_result(
|
|
1566
|
+
1,
|
|
1567
|
+
FILE_STATUS_SUCCESS,
|
|
1568
|
+
10,
|
|
1569
|
+
100,
|
|
1570
|
+
bytes.as_ptr(),
|
|
1571
|
+
bytes.len() as u32,
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1553
1574
|
let chunk = chunk.borrow().clone().expect("chunk");
|
|
1554
1575
|
assert_eq!(chunk.offset_bytes, 10);
|
|
1555
1576
|
assert_eq!(chunk.file_size_bytes, 100);
|
|
@@ -1585,12 +1606,14 @@ mod tests {
|
|
|
1585
1606
|
"writer-1",
|
|
1586
1607
|
Some("report.txt"),
|
|
1587
1608
|
);
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1609
|
+
unsafe {
|
|
1610
|
+
super::__fui_on_file_writer_created(
|
|
1611
|
+
1,
|
|
1612
|
+
FILE_STATUS_SUCCESS,
|
|
1613
|
+
payload.as_ptr(),
|
|
1614
|
+
payload.len() as u32,
|
|
1615
|
+
);
|
|
1616
|
+
}
|
|
1594
1617
|
let writer = writer.borrow().clone().expect("writer");
|
|
1595
1618
|
assert_eq!(writer.file_name, "report.txt");
|
|
1596
1619
|
assert_eq!(writer.mode, FileSaveMode::NativePicker);
|
|
@@ -1604,13 +1627,15 @@ mod tests {
|
|
|
1604
1627
|
let calls = ffi::test::take_calls();
|
|
1605
1628
|
assert!(calls.iter().any(|call| matches!(call, Call::FileWriterFinish { request_id, writer_id } if *request_id == 2 && writer_id == "writer-1")));
|
|
1606
1629
|
let payload = writer_payload(FileSaveMode::NativePicker as u32, "report.txt", None);
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1630
|
+
unsafe {
|
|
1631
|
+
super::__fui_on_file_finish_result(
|
|
1632
|
+
2,
|
|
1633
|
+
FILE_STATUS_SUCCESS,
|
|
1634
|
+
44,
|
|
1635
|
+
payload.as_ptr(),
|
|
1636
|
+
payload.len() as u32,
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1614
1639
|
let finished = finished.borrow().clone().expect("finish");
|
|
1615
1640
|
assert_eq!(finished.file_name, "report.txt");
|
|
1616
1641
|
assert_eq!(finished.written_bytes, 44);
|
|
@@ -1657,18 +1682,22 @@ mod tests {
|
|
|
1657
1682
|
let calls = ffi::test::take_calls();
|
|
1658
1683
|
assert!(calls.iter().any(|call| matches!(call, Call::FileProcessWorkerStart { request_id, worker_wasm_path, worker_entry_name, file_id, suggested_name, chunk_bytes, save_to_picked_file } if *request_id == 1 && worker_wasm_path == "./workers/file_worker.wasm" && worker_entry_name == "entry" && file_id == "picked-1" && suggested_name == "copy.bin" && *chunk_bytes == 64 * 1024 && *save_to_picked_file)));
|
|
1659
1684
|
|
|
1660
|
-
|
|
1685
|
+
unsafe {
|
|
1686
|
+
super::__fui_on_file_worker_process_progress(1, 20, 100, b"copy.bin".as_ptr(), 8);
|
|
1687
|
+
}
|
|
1661
1688
|
let progress = progress.borrow().clone().expect("progress");
|
|
1662
1689
|
assert_eq!(progress.processed_bytes, 20);
|
|
1663
1690
|
assert_eq!(progress.output_file_name, Some("copy.bin".to_string()));
|
|
1664
1691
|
|
|
1665
1692
|
let payload = b"copy.bin\0sha256".to_vec();
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1693
|
+
unsafe {
|
|
1694
|
+
super::__fui_on_file_worker_process_complete(
|
|
1695
|
+
1,
|
|
1696
|
+
100,
|
|
1697
|
+
payload.as_ptr(),
|
|
1698
|
+
payload.len() as u32,
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1672
1701
|
let result = result.borrow().clone().expect("result");
|
|
1673
1702
|
assert_eq!(result.processed_bytes, 100);
|
|
1674
1703
|
assert_eq!(result.output_file_name, Some("copy.bin".to_string()));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#[must_use = "the host-event handler is removed when the subscription is dropped"]
|
|
2
|
+
pub struct HostEventSubscription {
|
|
3
|
+
unsubscribe: Option<Box<dyn FnOnce()>>,
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
impl HostEventSubscription {
|
|
7
|
+
#[doc(hidden)]
|
|
8
|
+
pub fn new(unsubscribe: impl FnOnce() + 'static) -> Self {
|
|
9
|
+
Self {
|
|
10
|
+
unsubscribe: Some(Box::new(unsubscribe)),
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
impl Drop for HostEventSubscription {
|
|
16
|
+
fn drop(&mut self) {
|
|
17
|
+
if let Some(unsubscribe) = self.unsubscribe.take() {
|
|
18
|
+
unsubscribe();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#[cfg(test)]
|
|
24
|
+
mod tests {
|
|
25
|
+
use super::*;
|
|
26
|
+
use std::cell::Cell;
|
|
27
|
+
use std::rc::Rc;
|
|
28
|
+
|
|
29
|
+
#[test]
|
|
30
|
+
fn dropping_host_event_subscription_runs_unsubscribe_once() {
|
|
31
|
+
let unsubscribe_count = Rc::new(Cell::new(0));
|
|
32
|
+
let captured_count = unsubscribe_count.clone();
|
|
33
|
+
let subscription = HostEventSubscription::new(move || {
|
|
34
|
+
captured_count.set(captured_count.get() + 1);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
drop(subscription);
|
|
38
|
+
|
|
39
|
+
assert_eq!(unsubscribe_count.get(), 1);
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/lib.rs
CHANGED
|
@@ -24,6 +24,7 @@ pub mod frame_scheduler;
|
|
|
24
24
|
pub mod frame_signal;
|
|
25
25
|
#[doc(hidden)]
|
|
26
26
|
pub mod generated;
|
|
27
|
+
pub mod host_events;
|
|
27
28
|
pub mod host_services;
|
|
28
29
|
pub mod image_sampling;
|
|
29
30
|
pub(crate) mod keyboard_scroll;
|
|
@@ -77,6 +78,46 @@ macro_rules! fui_app {
|
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
#[cfg(feature = "worker-runtime")]
|
|
82
|
+
#[macro_export]
|
|
83
|
+
macro_rules! fui_worker {
|
|
84
|
+
($($entry:ident => $job:ty),+ $(,)?) => {
|
|
85
|
+
$(
|
|
86
|
+
#[doc = "Worker entrypoint generated by `fui_worker!`.\n\n# Safety\n`input_ptr` must reference `input_len` readable bytes when `input_len` is non-zero."]
|
|
87
|
+
#[no_mangle]
|
|
88
|
+
pub unsafe extern "C" fn $entry(input_ptr: usize, input_len: u32) {
|
|
89
|
+
::std::thread_local! {
|
|
90
|
+
static ACTIVE_JOB: ::std::cell::RefCell<Option<$job>> =
|
|
91
|
+
const { ::std::cell::RefCell::new(None) };
|
|
92
|
+
}
|
|
93
|
+
let input = unsafe {
|
|
94
|
+
$crate::WorkerRuntime::entry_input(input_ptr, input_len)
|
|
95
|
+
};
|
|
96
|
+
ACTIVE_JOB.with(|slot| {
|
|
97
|
+
let mut active = slot.borrow_mut();
|
|
98
|
+
if active.is_none() {
|
|
99
|
+
$crate::worker_runtime::reset_worker_runtime();
|
|
100
|
+
}
|
|
101
|
+
let mut job = active.take().unwrap_or_default();
|
|
102
|
+
if $crate::WorkerJob::resume(&mut job, input) {
|
|
103
|
+
*active = Some(job);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
)+
|
|
108
|
+
|
|
109
|
+
#[no_mangle]
|
|
110
|
+
pub extern "C" fn __fui_worker_text_buffer() -> usize {
|
|
111
|
+
$crate::worker_runtime::worker_text_buffer_ptr()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#[no_mangle]
|
|
115
|
+
pub extern "C" fn __fui_worker_text_buffer_size() -> u32 {
|
|
116
|
+
$crate::worker_runtime::worker_text_buffer_size()
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
80
121
|
#[macro_export]
|
|
81
122
|
macro_rules! fui_managed_app {
|
|
82
123
|
($page_ty:ty, $build_page:expr, $get_root:expr) => {
|
|
@@ -435,6 +476,9 @@ pub mod prelude {
|
|
|
435
476
|
pub use crate::focus_visibility::show_keyboard_focus_for_key_event;
|
|
436
477
|
pub use crate::frame_scheduler::{mark_needs_commit, on_loaded, LoadedEventArgs};
|
|
437
478
|
pub use crate::fui_component;
|
|
479
|
+
#[cfg(feature = "worker-runtime")]
|
|
480
|
+
pub use crate::fui_worker;
|
|
481
|
+
pub use crate::host_events::HostEventSubscription;
|
|
438
482
|
pub use crate::image_sampling::{ImageSampling, ImageSamplingMode};
|
|
439
483
|
pub use crate::logger;
|
|
440
484
|
pub use crate::navigation;
|
|
@@ -442,9 +486,10 @@ pub mod prelude {
|
|
|
442
486
|
auto, column, custom_drawable, fill, flex_box, grid, image, pct, portal, px, row,
|
|
443
487
|
scroll_box, scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Border,
|
|
444
488
|
Child, ContextMenuEventArgs, Corners, CustomDrawable, DrawableInvalidator, EdgeInsets,
|
|
445
|
-
FlexBox, FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode,
|
|
446
|
-
|
|
447
|
-
Shadow, Svg, SvgNode, Text, TextCore, TextNode,
|
|
489
|
+
FlexBox, FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode,
|
|
490
|
+
Length, Node, PresenterHostStyle, ScrollBar, ScrollBarStyle, ScrollBarVisibility,
|
|
491
|
+
ScrollBox, ScrollState, ScrollView, Shadow, Svg, SvgNode, Text, TextCore, TextNode,
|
|
492
|
+
ThemeBindable, VirtualList,
|
|
448
493
|
};
|
|
449
494
|
pub use crate::persisted;
|
|
450
495
|
pub use crate::platform;
|
|
@@ -553,6 +598,7 @@ pub use file::{
|
|
|
553
598
|
pub use focus_visibility::show_keyboard_focus_for_key_event;
|
|
554
599
|
pub use frame_scheduler::{mark_needs_commit, on_loaded, LoadedEventArgs};
|
|
555
600
|
pub use frame_signal::{frame_time_signal, FrameTimeSignalHandle};
|
|
601
|
+
pub use host_events::HostEventSubscription;
|
|
556
602
|
pub use image_sampling::{ImageSampling, ImageSamplingMode};
|
|
557
603
|
pub use logger::*;
|
|
558
604
|
pub use navigation::*;
|
|
@@ -561,8 +607,8 @@ pub use node::{
|
|
|
561
607
|
scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Border, Child,
|
|
562
608
|
ContextMenuEventArgs, Corners, CustomDrawable, DrawableInvalidator, EdgeInsets, FlexBox,
|
|
563
609
|
FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode, Length, Node,
|
|
564
|
-
PresenterHostStyle, ScrollBar, ScrollBarVisibility, ScrollBox, ScrollState,
|
|
565
|
-
Svg, SvgNode, Text, TextCore, TextNode, ThemeBindable, VirtualList,
|
|
610
|
+
PresenterHostStyle, ScrollBar, ScrollBarStyle, ScrollBarVisibility, ScrollBox, ScrollState,
|
|
611
|
+
ScrollView, Shadow, Svg, SvgNode, Text, TextCore, TextNode, ThemeBindable, VirtualList,
|
|
566
612
|
};
|
|
567
613
|
pub use persisted::*;
|
|
568
614
|
pub use platform::*;
|
|
@@ -592,8 +638,5 @@ pub use worker::{Worker, WorkerCompletedEventArgs, WorkerErrorEventArgs, WorkerP
|
|
|
592
638
|
pub use worker_job::{WorkerJob, WorkerJobState};
|
|
593
639
|
#[cfg(feature = "worker-runtime")]
|
|
594
640
|
pub use worker_runtime::{
|
|
595
|
-
file_read_chunk, file_worker_write_chunk,
|
|
596
|
-
handle_fetch_error as __fui_on_fetch_error, reset_worker_runtime,
|
|
597
|
-
worker_text_buffer_ptr as __fui_worker_text_buffer,
|
|
598
|
-
worker_text_buffer_size as __fui_worker_text_buffer_size, WorkerRuntime,
|
|
641
|
+
file_read_chunk, file_worker_write_chunk, reset_worker_runtime, WorkerRuntime,
|
|
599
642
|
};
|
package/src/node/core.rs
CHANGED
|
@@ -262,7 +262,7 @@ pub(crate) struct LinearGradient {
|
|
|
262
262
|
pub(crate) offsets: Vec<f32>,
|
|
263
263
|
pub(crate) colors: Vec<u32>,
|
|
264
264
|
}
|
|
265
|
-
#[derive(Clone)]
|
|
265
|
+
#[derive(Clone, Default)]
|
|
266
266
|
pub(crate) struct FlexBoxProps {
|
|
267
267
|
pub(crate) width: Option<(f32, Unit)>,
|
|
268
268
|
pub(crate) height: Option<(f32, Unit)>,
|
|
@@ -278,25 +278,6 @@ pub(crate) struct FlexBoxProps {
|
|
|
278
278
|
pub(crate) transitions: Option<NodeTransitions>,
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
impl Default for FlexBoxProps {
|
|
282
|
-
fn default() -> Self {
|
|
283
|
-
Self {
|
|
284
|
-
width: None,
|
|
285
|
-
height: None,
|
|
286
|
-
bg_color: None,
|
|
287
|
-
padding: None,
|
|
288
|
-
flex_direction: None,
|
|
289
|
-
box_style: None,
|
|
290
|
-
opacity: None,
|
|
291
|
-
blur_sigma: None,
|
|
292
|
-
drop_shadow: None,
|
|
293
|
-
background_blur_sigma: None,
|
|
294
|
-
linear_gradient: None,
|
|
295
|
-
transitions: None,
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
281
|
#[derive(Clone, Default)]
|
|
301
282
|
pub(crate) struct TextProps {
|
|
302
283
|
pub(crate) content: String,
|
|
@@ -1577,6 +1558,11 @@ pub trait Node: Clone {
|
|
|
1577
1558
|
#[doc(hidden)]
|
|
1578
1559
|
fn build_self(&self);
|
|
1579
1560
|
|
|
1561
|
+
#[doc(hidden)]
|
|
1562
|
+
fn required_font_ids_for_preparation(&self) -> Vec<u32> {
|
|
1563
|
+
Vec::new()
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1580
1566
|
fn node_id(&self, node_id: impl Into<String>) -> &Self
|
|
1581
1567
|
where
|
|
1582
1568
|
Self: Sized,
|
|
@@ -2214,7 +2200,7 @@ pub trait Node: Clone {
|
|
|
2214
2200
|
}
|
|
2215
2201
|
}
|
|
2216
2202
|
|
|
2217
|
-
impl<T: Node
|
|
2203
|
+
impl<T: Node> Node for &T {
|
|
2218
2204
|
fn retained_node_ref(&self) -> NodeRef {
|
|
2219
2205
|
(*self).retained_node_ref()
|
|
2220
2206
|
}
|
package/src/node/helpers.rs
CHANGED
|
@@ -31,7 +31,7 @@ pub fn scroll_box() -> ScrollBox {
|
|
|
31
31
|
ScrollBox::new()
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
pub fn virtual_list(total_items: i32, item_height: f32) -> VirtualList {
|
|
34
|
+
pub fn virtual_list(total_items: i32, item_height: f32) -> VirtualList<FlexBox> {
|
|
35
35
|
VirtualList::new(total_items, item_height)
|
|
36
36
|
}
|
|
37
37
|
|
package/src/node/mod.rs
CHANGED
|
@@ -48,7 +48,7 @@ pub use helpers::{
|
|
|
48
48
|
pub use image::ImageNode;
|
|
49
49
|
pub(crate) use presenter_host_style::HostStyleLayers;
|
|
50
50
|
pub use presenter_host_style::{Corners, EdgeInsets, PresenterHostStyle, Shadow};
|
|
51
|
-
pub use scroll_bar::{ScrollBar, ScrollBarVisibility};
|
|
51
|
+
pub use scroll_bar::{ScrollBar, ScrollBarStyle, ScrollBarVisibility};
|
|
52
52
|
pub use scroll_box::ScrollBox;
|
|
53
53
|
pub use scroll_state::ScrollState;
|
|
54
54
|
pub use scroll_view::ScrollView;
|
package/src/node/scroll_bar.rs
CHANGED
|
@@ -12,6 +12,91 @@ const DEFAULT_TRACK_THICKNESS: f32 = 8.0;
|
|
|
12
12
|
const DEFAULT_THUMB_THICKNESS: f32 = 8.0;
|
|
13
13
|
const DEFAULT_MIN_THUMB_SIZE: f32 = 18.0;
|
|
14
14
|
|
|
15
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
16
|
+
pub struct ScrollBarStyle {
|
|
17
|
+
track_width: f32,
|
|
18
|
+
thumb_width: f32,
|
|
19
|
+
thumb_min_height: f32,
|
|
20
|
+
track_corner_radius: f32,
|
|
21
|
+
thumb_corner_radius: f32,
|
|
22
|
+
track_color: Option<u32>,
|
|
23
|
+
thumb_color: Option<u32>,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
impl ScrollBarStyle {
|
|
27
|
+
pub fn new() -> Self {
|
|
28
|
+
Self::default()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub fn track_width(mut self, value: f32) -> Self {
|
|
32
|
+
self.track_width = value;
|
|
33
|
+
self
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn thumb_width(mut self, value: f32) -> Self {
|
|
37
|
+
self.thumb_width = value;
|
|
38
|
+
self
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pub fn thumb_min_height(mut self, value: f32) -> Self {
|
|
42
|
+
self.thumb_min_height = value;
|
|
43
|
+
self
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
pub fn track_corner_radius(mut self, value: f32) -> Self {
|
|
47
|
+
self.track_corner_radius = value;
|
|
48
|
+
self
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub fn thumb_corner_radius(mut self, value: f32) -> Self {
|
|
52
|
+
self.thumb_corner_radius = value;
|
|
53
|
+
self
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub fn track_color(mut self, value: u32) -> Self {
|
|
57
|
+
self.track_color = Some(value);
|
|
58
|
+
self
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub fn thumb_color(mut self, value: u32) -> Self {
|
|
62
|
+
self.thumb_color = Some(value);
|
|
63
|
+
self
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pub(crate) fn apply_to(self, scroll_bar: &ScrollBar) {
|
|
67
|
+
scroll_bar
|
|
68
|
+
.track_width(self.track_width)
|
|
69
|
+
.thumb_width(self.thumb_width)
|
|
70
|
+
.thumb_min_height(self.thumb_min_height)
|
|
71
|
+
.track_corner_radius(self.track_corner_radius)
|
|
72
|
+
.thumb_corner_radius(self.thumb_corner_radius);
|
|
73
|
+
if let Some(color) = self.track_color {
|
|
74
|
+
scroll_bar.track_color(color);
|
|
75
|
+
} else {
|
|
76
|
+
scroll_bar.clear_track_color();
|
|
77
|
+
}
|
|
78
|
+
if let Some(color) = self.thumb_color {
|
|
79
|
+
scroll_bar.thumb_color(color);
|
|
80
|
+
} else {
|
|
81
|
+
scroll_bar.clear_thumb_color();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
impl Default for ScrollBarStyle {
|
|
87
|
+
fn default() -> Self {
|
|
88
|
+
Self {
|
|
89
|
+
track_width: DEFAULT_TRACK_THICKNESS,
|
|
90
|
+
thumb_width: DEFAULT_THUMB_THICKNESS,
|
|
91
|
+
thumb_min_height: DEFAULT_MIN_THUMB_SIZE,
|
|
92
|
+
track_corner_radius: 0.0,
|
|
93
|
+
thumb_corner_radius: 0.0,
|
|
94
|
+
track_color: None,
|
|
95
|
+
thumb_color: None,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
15
100
|
fn clamp(value: f32, min: f32, max: f32) -> f32 {
|
|
16
101
|
if value < min {
|
|
17
102
|
return min;
|
|
@@ -237,6 +322,14 @@ impl ScrollBar {
|
|
|
237
322
|
self
|
|
238
323
|
}
|
|
239
324
|
|
|
325
|
+
fn clear_track_color(&self) {
|
|
326
|
+
self.inner.track_color_overridden.set(false);
|
|
327
|
+
self.inner
|
|
328
|
+
.track_color
|
|
329
|
+
.set(current_theme().colors.scrollbar_track);
|
|
330
|
+
self.apply_color_style();
|
|
331
|
+
}
|
|
332
|
+
|
|
240
333
|
pub fn thumb_color(&self, color: u32) -> &Self {
|
|
241
334
|
self.inner.thumb_color_overridden.set(true);
|
|
242
335
|
self.inner.thumb_color.set(color);
|
|
@@ -244,6 +337,14 @@ impl ScrollBar {
|
|
|
244
337
|
self
|
|
245
338
|
}
|
|
246
339
|
|
|
340
|
+
fn clear_thumb_color(&self) {
|
|
341
|
+
self.inner.thumb_color_overridden.set(false);
|
|
342
|
+
self.inner
|
|
343
|
+
.thumb_color
|
|
344
|
+
.set(current_theme().colors.scrollbar_thumb);
|
|
345
|
+
self.apply_color_style();
|
|
346
|
+
}
|
|
347
|
+
|
|
247
348
|
pub fn bind_scroll_handle(&self, handle: u64) {
|
|
248
349
|
self.inner.target_handle.set(handle);
|
|
249
350
|
self.inner
|
package/src/node/scroll_box.rs
CHANGED
|
@@ -219,6 +219,13 @@ impl ScrollBox {
|
|
|
219
219
|
self
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
pub fn scrollbar_style(&self, style: ScrollBarStyle) -> &Self {
|
|
223
|
+
style.apply_to(&self.inner.vertical_scrollbar);
|
|
224
|
+
style.apply_to(&self.inner.horizontal_scrollbar);
|
|
225
|
+
self.refresh_chrome();
|
|
226
|
+
self
|
|
227
|
+
}
|
|
228
|
+
|
|
222
229
|
fn attach_listeners(&self) {
|
|
223
230
|
let weak = Rc::downgrade(&self.inner);
|
|
224
231
|
self.inner
|
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/text_node.rs
CHANGED