@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/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
|
@@ -4,6 +4,7 @@ pub mod assets;
|
|
|
4
4
|
#[doc(hidden)]
|
|
5
5
|
pub mod bindings;
|
|
6
6
|
pub mod bitmap;
|
|
7
|
+
pub mod color;
|
|
7
8
|
#[doc(hidden)]
|
|
8
9
|
pub mod bridge_callbacks;
|
|
9
10
|
pub(crate) mod context_menu_manager;
|
|
@@ -24,6 +25,7 @@ pub mod frame_scheduler;
|
|
|
24
25
|
pub mod frame_signal;
|
|
25
26
|
#[doc(hidden)]
|
|
26
27
|
pub mod generated;
|
|
28
|
+
pub mod host_events;
|
|
27
29
|
pub mod host_services;
|
|
28
30
|
pub mod image_sampling;
|
|
29
31
|
pub(crate) mod keyboard_scroll;
|
|
@@ -77,6 +79,46 @@ macro_rules! fui_app {
|
|
|
77
79
|
};
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
#[cfg(feature = "worker-runtime")]
|
|
83
|
+
#[macro_export]
|
|
84
|
+
macro_rules! fui_worker {
|
|
85
|
+
($($entry:ident => $job:ty),+ $(,)?) => {
|
|
86
|
+
$(
|
|
87
|
+
#[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."]
|
|
88
|
+
#[no_mangle]
|
|
89
|
+
pub unsafe extern "C" fn $entry(input_ptr: usize, input_len: u32) {
|
|
90
|
+
::std::thread_local! {
|
|
91
|
+
static ACTIVE_JOB: ::std::cell::RefCell<Option<$job>> =
|
|
92
|
+
const { ::std::cell::RefCell::new(None) };
|
|
93
|
+
}
|
|
94
|
+
let input = unsafe {
|
|
95
|
+
$crate::WorkerRuntime::entry_input(input_ptr, input_len)
|
|
96
|
+
};
|
|
97
|
+
ACTIVE_JOB.with(|slot| {
|
|
98
|
+
let mut active = slot.borrow_mut();
|
|
99
|
+
if active.is_none() {
|
|
100
|
+
$crate::worker_runtime::reset_worker_runtime();
|
|
101
|
+
}
|
|
102
|
+
let mut job = active.take().unwrap_or_default();
|
|
103
|
+
if $crate::WorkerJob::resume(&mut job, input) {
|
|
104
|
+
*active = Some(job);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
)+
|
|
109
|
+
|
|
110
|
+
#[no_mangle]
|
|
111
|
+
pub extern "C" fn __fui_worker_text_buffer() -> usize {
|
|
112
|
+
$crate::worker_runtime::worker_text_buffer_ptr()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#[no_mangle]
|
|
116
|
+
pub extern "C" fn __fui_worker_text_buffer_size() -> u32 {
|
|
117
|
+
$crate::worker_runtime::worker_text_buffer_size()
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
80
122
|
#[macro_export]
|
|
81
123
|
macro_rules! fui_managed_app {
|
|
82
124
|
($page_ty:ty, $build_page:expr, $get_root:expr) => {
|
|
@@ -367,6 +409,7 @@ pub mod prelude {
|
|
|
367
409
|
pub use crate::app::{Application, ApplicationRegistration, ManagedApplication};
|
|
368
410
|
pub use crate::bitmap::{Bitmap, BitmapTextReadyEventArgs};
|
|
369
411
|
pub use crate::bridge_callbacks::current_route;
|
|
412
|
+
pub use crate::color::{hsl_to_color, mix_color, rgb, rgba, with_alpha};
|
|
370
413
|
pub use crate::controls::{
|
|
371
414
|
anti_selection_area, button, checkbox, clear_control_templates, combo_box, context_menu,
|
|
372
415
|
create_default_button_presenter, create_default_checkbox_indicator_presenter,
|
|
@@ -435,6 +478,9 @@ pub mod prelude {
|
|
|
435
478
|
pub use crate::focus_visibility::show_keyboard_focus_for_key_event;
|
|
436
479
|
pub use crate::frame_scheduler::{mark_needs_commit, on_loaded, LoadedEventArgs};
|
|
437
480
|
pub use crate::fui_component;
|
|
481
|
+
#[cfg(feature = "worker-runtime")]
|
|
482
|
+
pub use crate::fui_worker;
|
|
483
|
+
pub use crate::host_events::HostEventSubscription;
|
|
438
484
|
pub use crate::image_sampling::{ImageSampling, ImageSamplingMode};
|
|
439
485
|
pub use crate::logger;
|
|
440
486
|
pub use crate::navigation;
|
|
@@ -442,9 +488,10 @@ pub mod prelude {
|
|
|
442
488
|
auto, column, custom_drawable, fill, flex_box, grid, image, pct, portal, px, row,
|
|
443
489
|
scroll_box, scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Border,
|
|
444
490
|
Child, ContextMenuEventArgs, Corners, CustomDrawable, DrawableInvalidator, EdgeInsets,
|
|
445
|
-
FlexBox, FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode,
|
|
446
|
-
|
|
447
|
-
Shadow, Svg, SvgNode, Text, TextCore, TextNode,
|
|
491
|
+
FlexBox, FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode,
|
|
492
|
+
Length, Node, PresenterHostStyle, ScrollBar, ScrollBarStyle, ScrollBarVisibility,
|
|
493
|
+
ScrollBox, ScrollState, ScrollView, Shadow, Svg, SvgNode, Text, TextCore, TextNode,
|
|
494
|
+
ThemeBindable, VirtualList,
|
|
448
495
|
};
|
|
449
496
|
pub use crate::persisted;
|
|
450
497
|
pub use crate::platform;
|
|
@@ -489,6 +536,7 @@ pub use app::{Application, ApplicationRegistration, ManagedApplication};
|
|
|
489
536
|
pub use assets::*;
|
|
490
537
|
pub use bitmap::{Bitmap, BitmapTextReadyEventArgs};
|
|
491
538
|
pub use bridge_callbacks::current_route;
|
|
539
|
+
pub use color::{hsl_to_color, mix_color, rgb, rgba, with_alpha};
|
|
492
540
|
pub use controls::{
|
|
493
541
|
anti_selection_area, button, checkbox, clear_control_templates, combo_box, context_menu,
|
|
494
542
|
create_default_button_presenter, create_default_checkbox_indicator_presenter,
|
|
@@ -553,6 +601,7 @@ pub use file::{
|
|
|
553
601
|
pub use focus_visibility::show_keyboard_focus_for_key_event;
|
|
554
602
|
pub use frame_scheduler::{mark_needs_commit, on_loaded, LoadedEventArgs};
|
|
555
603
|
pub use frame_signal::{frame_time_signal, FrameTimeSignalHandle};
|
|
604
|
+
pub use host_events::HostEventSubscription;
|
|
556
605
|
pub use image_sampling::{ImageSampling, ImageSamplingMode};
|
|
557
606
|
pub use logger::*;
|
|
558
607
|
pub use navigation::*;
|
|
@@ -561,8 +610,8 @@ pub use node::{
|
|
|
561
610
|
scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Border, Child,
|
|
562
611
|
ContextMenuEventArgs, Corners, CustomDrawable, DrawableInvalidator, EdgeInsets, FlexBox,
|
|
563
612
|
FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode, Length, Node,
|
|
564
|
-
PresenterHostStyle, ScrollBar, ScrollBarVisibility, ScrollBox, ScrollState,
|
|
565
|
-
Svg, SvgNode, Text, TextCore, TextNode, ThemeBindable, VirtualList,
|
|
613
|
+
PresenterHostStyle, ScrollBar, ScrollBarStyle, ScrollBarVisibility, ScrollBox, ScrollState,
|
|
614
|
+
ScrollView, Shadow, Svg, SvgNode, Text, TextCore, TextNode, ThemeBindable, VirtualList,
|
|
566
615
|
};
|
|
567
616
|
pub use persisted::*;
|
|
568
617
|
pub use platform::*;
|
|
@@ -592,8 +641,5 @@ pub use worker::{Worker, WorkerCompletedEventArgs, WorkerErrorEventArgs, WorkerP
|
|
|
592
641
|
pub use worker_job::{WorkerJob, WorkerJobState};
|
|
593
642
|
#[cfg(feature = "worker-runtime")]
|
|
594
643
|
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,
|
|
644
|
+
file_read_chunk, file_worker_write_chunk, reset_worker_runtime, WorkerRuntime,
|
|
599
645
|
};
|
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,
|
|
@@ -532,6 +513,26 @@ impl NodeRef {
|
|
|
532
513
|
self.inner.borrow().handle
|
|
533
514
|
}
|
|
534
515
|
|
|
516
|
+
pub(crate) fn set_semantic_checked(
|
|
517
|
+
&self,
|
|
518
|
+
state: SemanticCheckedState,
|
|
519
|
+
announce: bool,
|
|
520
|
+
) {
|
|
521
|
+
let handle = {
|
|
522
|
+
let mut core = self.inner.borrow_mut();
|
|
523
|
+
core.behavior.semantic_checked = Some(state);
|
|
524
|
+
core.handle
|
|
525
|
+
};
|
|
526
|
+
if handle == NodeHandle::INVALID {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
ui::set_semantic_checked(handle.raw(), state as u32);
|
|
530
|
+
if announce {
|
|
531
|
+
ui::request_semantic_announcement(handle.raw());
|
|
532
|
+
}
|
|
533
|
+
crate::frame_scheduler::mark_needs_commit();
|
|
534
|
+
}
|
|
535
|
+
|
|
535
536
|
pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
|
|
536
537
|
Rc::ptr_eq(&self.inner, &other.inner)
|
|
537
538
|
}
|
|
@@ -2219,7 +2220,7 @@ pub trait Node: Clone {
|
|
|
2219
2220
|
}
|
|
2220
2221
|
}
|
|
2221
2222
|
|
|
2222
|
-
impl<T: Node
|
|
2223
|
+
impl<T: Node> Node for &T {
|
|
2223
2224
|
fn retained_node_ref(&self) -> NodeRef {
|
|
2224
2225
|
(*self).retained_node_ref()
|
|
2225
2226
|
}
|
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
|