@effindomv2/fui-rs 0.1.22 → 0.1.24
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 +12 -0
- package/package.json +1 -1
- package/src/controls/anti_selection_area.rs +0 -18
- package/src/controls/button.rs +14 -42
- package/src/controls/checkbox.rs +7 -0
- package/src/controls/combobox.rs +7 -6
- package/src/controls/context_menu.rs +38 -5
- package/src/controls/dialog.rs +41 -3
- package/src/controls/dropdown.rs +2 -2
- package/src/controls/form.rs +16 -20
- package/src/controls/internal/button_presenter.rs +5 -5
- package/src/controls/internal/checkbox_indicator_presenter.rs +1 -1
- package/src/controls/internal/pressable_labeled_control.rs +21 -7
- package/src/controls/internal/selectable_popup_list.rs +2 -2
- package/src/controls/internal/text_input_core.rs +38 -68
- package/src/controls/internal/text_input_presenter.rs +4 -4
- package/src/controls/mod.rs +11 -4
- package/src/controls/popup.rs +35 -20
- package/src/controls/radio_button.rs +7 -0
- package/src/controls/radio_group.rs +17 -0
- package/src/controls/selection_area.rs +0 -18
- package/src/controls/shared.rs +2 -17
- package/src/controls/switch.rs +7 -0
- package/src/controls/tests.rs +230 -6
- package/src/controls/text_area.rs +28 -142
- package/src/controls/text_editor_surface.rs +167 -0
- package/src/controls/text_input.rs +30 -144
- package/src/lib.rs +26 -20
- package/src/mobile_text_selection_toolbar.rs +2 -2
- package/src/node/core.rs +451 -60
- package/src/node/custom_drawable.rs +20 -0
- package/src/node/flex_box.rs +39 -47
- package/src/node/grid.rs +43 -128
- package/src/node/helpers.rs +34 -43
- package/src/node/image.rs +47 -56
- package/src/node/mod.rs +398 -73
- package/src/node/scroll_bar.rs +6 -0
- package/src/node/scroll_box.rs +8 -21
- package/src/node/scroll_view.rs +144 -13
- package/src/node/svg_node.rs +47 -66
- package/src/node/text_node.rs +358 -79
- package/src/node/virtual_list.rs +17 -0
- package/src/popup_presenter.rs +31 -0
- package/src/text.rs +59 -0
- package/src/text_indices.rs +48 -0
package/src/controls/tests.rs
CHANGED
|
@@ -8,26 +8,28 @@ use crate::ffi::{
|
|
|
8
8
|
use crate::focus_visibility;
|
|
9
9
|
use crate::generated::ffi::NodeType;
|
|
10
10
|
use crate::node::Node;
|
|
11
|
-
use crate::node::{
|
|
11
|
+
use crate::node::{
|
|
12
|
+
column, text, BoxStyleSurface, Child, ChildContainerSurface, FlexLayoutSurface, LayoutSurface,
|
|
13
|
+
};
|
|
12
14
|
use crate::theme::{current_theme, generate_theme, use_custom_theme, use_system_theme};
|
|
13
15
|
use crate::Application;
|
|
14
16
|
use crate::Border;
|
|
15
17
|
use crate::PointerType;
|
|
16
18
|
use crate::ScrollBarVisibility;
|
|
17
|
-
use crate::
|
|
19
|
+
use crate::TextNode;
|
|
18
20
|
use std::cell::Cell;
|
|
19
21
|
use std::rc::Rc;
|
|
20
22
|
|
|
21
23
|
#[derive(Clone)]
|
|
22
24
|
struct TestButtonPresenter {
|
|
23
25
|
content_root: FlexBox,
|
|
24
|
-
label:
|
|
26
|
+
label: TextNode,
|
|
25
27
|
border_color: u32,
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
impl TestButtonPresenter {
|
|
29
31
|
fn new(border_color: u32) -> Self {
|
|
30
|
-
let label =
|
|
32
|
+
let label = TextNode::new_core("");
|
|
31
33
|
let content_root = flex_box();
|
|
32
34
|
content_root.child(&label);
|
|
33
35
|
Self {
|
|
@@ -43,7 +45,7 @@ impl ButtonPresenter for TestButtonPresenter {
|
|
|
43
45
|
self.content_root.clone()
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
fn label_node(&self) ->
|
|
48
|
+
fn label_node(&self) -> TextNode {
|
|
47
49
|
self.label.clone()
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -76,7 +78,7 @@ struct TestTextInputPresenter {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
impl TextInputPresenter for TestTextInputPresenter {
|
|
79
|
-
fn bind(&self, _editor_host:
|
|
81
|
+
fn bind(&self, _editor_host: TextNode, _placeholder_host: FlexBox) {}
|
|
80
82
|
|
|
81
83
|
fn present(
|
|
82
84
|
&self,
|
|
@@ -1330,6 +1332,114 @@ fn flex_box_backed_controls_preserve_concrete_bind_theme_dx() {
|
|
|
1330
1332
|
assert_eq!(invocations.get(), 13);
|
|
1331
1333
|
}
|
|
1332
1334
|
|
|
1335
|
+
#[test]
|
|
1336
|
+
fn newly_covered_composed_controls_keep_one_theme_callback_after_wrapper_drop() {
|
|
1337
|
+
ffi::test::reset();
|
|
1338
|
+
let previous_theme = current_theme();
|
|
1339
|
+
let invocations = Rc::new(Cell::new(0));
|
|
1340
|
+
let invoked_controls = Rc::new(Cell::new(0u32));
|
|
1341
|
+
let root = column();
|
|
1342
|
+
|
|
1343
|
+
let form = form();
|
|
1344
|
+
form.bind_theme({
|
|
1345
|
+
let invocations = invocations.clone();
|
|
1346
|
+
let invoked_controls = invoked_controls.clone();
|
|
1347
|
+
move |control, theme| {
|
|
1348
|
+
invocations.set(invocations.get() + 1);
|
|
1349
|
+
invoked_controls.set(invoked_controls.get() | 1);
|
|
1350
|
+
control.bg_color(theme.colors.surface);
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
let group = radio_group();
|
|
1354
|
+
group.bind_theme({
|
|
1355
|
+
let invocations = invocations.clone();
|
|
1356
|
+
let invoked_controls = invoked_controls.clone();
|
|
1357
|
+
move |control, theme| {
|
|
1358
|
+
invocations.set(invocations.get() + 1);
|
|
1359
|
+
invoked_controls.set(invoked_controls.get() | 2);
|
|
1360
|
+
control.bg_color(theme.colors.surface);
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
let popup = popup();
|
|
1364
|
+
popup.bind_theme({
|
|
1365
|
+
let invocations = invocations.clone();
|
|
1366
|
+
let invoked_controls = invoked_controls.clone();
|
|
1367
|
+
move |control, theme| {
|
|
1368
|
+
invocations.set(invocations.get() + 1);
|
|
1369
|
+
invoked_controls.set(invoked_controls.get() | 4);
|
|
1370
|
+
control.surface().bg_color(theme.colors.surface);
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
let dialog = dialog("Theme", "Dialog");
|
|
1374
|
+
dialog.bind_theme({
|
|
1375
|
+
let invocations = invocations.clone();
|
|
1376
|
+
let invoked_controls = invoked_controls.clone();
|
|
1377
|
+
move |control, _theme| {
|
|
1378
|
+
invocations.set(invocations.get() + 1);
|
|
1379
|
+
invoked_controls.set(invoked_controls.get() | 8);
|
|
1380
|
+
control.content("Theme", "Dialog");
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
let menu = ContextMenu::new();
|
|
1384
|
+
menu.bind_theme({
|
|
1385
|
+
let invocations = invocations.clone();
|
|
1386
|
+
let invoked_controls = invoked_controls.clone();
|
|
1387
|
+
move |control, theme| {
|
|
1388
|
+
invocations.set(invocations.get() + 1);
|
|
1389
|
+
invoked_controls.set(invoked_controls.get() | 16);
|
|
1390
|
+
control.appearance(
|
|
1391
|
+
ContextMenuAppearance::new()
|
|
1392
|
+
.panel(SurfaceAppearance::new().background(theme.colors.surface)),
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
assert_eq!(invocations.get(), 5);
|
|
1398
|
+
assert_eq!(invoked_controls.replace(0), 31);
|
|
1399
|
+
root.child(&form)
|
|
1400
|
+
.child(&group)
|
|
1401
|
+
.child(&popup)
|
|
1402
|
+
.child(&dialog)
|
|
1403
|
+
.child(&menu);
|
|
1404
|
+
Application::mount(root);
|
|
1405
|
+
drop(form);
|
|
1406
|
+
drop(group);
|
|
1407
|
+
drop(popup);
|
|
1408
|
+
drop(dialog);
|
|
1409
|
+
drop(menu);
|
|
1410
|
+
|
|
1411
|
+
use_custom_theme(generate_theme(false, 0x2A6F97FF));
|
|
1412
|
+
assert_eq!(
|
|
1413
|
+
invoked_controls.get(),
|
|
1414
|
+
31,
|
|
1415
|
+
"missing retained theme callback bit; form=1 group=2 popup=4 dialog=8 menu=16"
|
|
1416
|
+
);
|
|
1417
|
+
assert_eq!(invocations.get(), 10);
|
|
1418
|
+
use_custom_theme(previous_theme);
|
|
1419
|
+
Application::unmount();
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
#[test]
|
|
1423
|
+
fn composed_theme_subscription_stops_after_unmount_and_releases_retained_root() {
|
|
1424
|
+
let previous_theme = current_theme();
|
|
1425
|
+
let invocations = Rc::new(Cell::new(0));
|
|
1426
|
+
let form = form();
|
|
1427
|
+
let weak_root = form.flex_box_root().downgrade();
|
|
1428
|
+
form.bind_theme({
|
|
1429
|
+
let invocations = invocations.clone();
|
|
1430
|
+
move |_control, _theme| invocations.set(invocations.get() + 1)
|
|
1431
|
+
});
|
|
1432
|
+
Application::mount(form.clone());
|
|
1433
|
+
assert_eq!(invocations.get(), 1);
|
|
1434
|
+
|
|
1435
|
+
Application::unmount();
|
|
1436
|
+
drop(form);
|
|
1437
|
+
use_custom_theme(generate_theme(false, 0x314159FF));
|
|
1438
|
+
assert_eq!(invocations.get(), 1);
|
|
1439
|
+
assert!(weak_root.upgrade().is_none());
|
|
1440
|
+
use_custom_theme(previous_theme);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1333
1443
|
#[test]
|
|
1334
1444
|
fn retained_pressable_and_slider_keep_theme_subscriptions_after_wrappers_drop() {
|
|
1335
1445
|
ffi::test::reset();
|
|
@@ -1676,11 +1786,16 @@ fn button_local_template_replaces_presenter_tree_and_retains_label_updates() {
|
|
|
1676
1786
|
fn pressable_labeled_enabled_forwarding_blocks_activation() {
|
|
1677
1787
|
ffi::test::reset();
|
|
1678
1788
|
let checkbox_changes = Rc::new(Cell::new(0));
|
|
1789
|
+
let checkbox_clicks = Rc::new(Cell::new(0));
|
|
1679
1790
|
let checkbox_changes_clone = checkbox_changes.clone();
|
|
1791
|
+
let checkbox_clicks_clone = checkbox_clicks.clone();
|
|
1680
1792
|
let checkbox = checkbox("Agree");
|
|
1681
1793
|
checkbox.on_changed(move |_event| {
|
|
1682
1794
|
checkbox_changes_clone.set(checkbox_changes_clone.get() + 1);
|
|
1683
1795
|
});
|
|
1796
|
+
checkbox.on_click(move |_event| {
|
|
1797
|
+
checkbox_clicks_clone.set(checkbox_clicks_clone.get() + 1);
|
|
1798
|
+
});
|
|
1684
1799
|
checkbox.enabled(false);
|
|
1685
1800
|
Application::mount(checkbox.clone());
|
|
1686
1801
|
let calls = ffi::test::take_calls();
|
|
@@ -1698,14 +1813,20 @@ fn pressable_labeled_enabled_forwarding_blocks_activation() {
|
|
|
1698
1813
|
key_event(KeyEventType::Down, "Space", 0);
|
|
1699
1814
|
key_event(KeyEventType::Up, "Space", 0);
|
|
1700
1815
|
assert_eq!(checkbox_changes.get(), 0);
|
|
1816
|
+
assert_eq!(checkbox_clicks.get(), 0);
|
|
1701
1817
|
|
|
1702
1818
|
ffi::test::reset();
|
|
1703
1819
|
let radio_changes = Rc::new(Cell::new(0));
|
|
1820
|
+
let radio_clicks = Rc::new(Cell::new(0));
|
|
1704
1821
|
let radio_changes_clone = radio_changes.clone();
|
|
1822
|
+
let radio_clicks_clone = radio_clicks.clone();
|
|
1705
1823
|
let radio = radio_button("Option");
|
|
1706
1824
|
radio.on_changed(move |_event| {
|
|
1707
1825
|
radio_changes_clone.set(radio_changes_clone.get() + 1);
|
|
1708
1826
|
});
|
|
1827
|
+
radio.on_click(move |_event| {
|
|
1828
|
+
radio_clicks_clone.set(radio_clicks_clone.get() + 1);
|
|
1829
|
+
});
|
|
1709
1830
|
radio.enabled(false);
|
|
1710
1831
|
Application::mount(radio.clone());
|
|
1711
1832
|
let radio_ref = radio.retained_node_ref();
|
|
@@ -1715,14 +1836,20 @@ fn pressable_labeled_enabled_forwarding_blocks_activation() {
|
|
|
1715
1836
|
key_event(KeyEventType::Down, "Space", 0);
|
|
1716
1837
|
key_event(KeyEventType::Up, "Space", 0);
|
|
1717
1838
|
assert_eq!(radio_changes.get(), 0);
|
|
1839
|
+
assert_eq!(radio_clicks.get(), 0);
|
|
1718
1840
|
|
|
1719
1841
|
ffi::test::reset();
|
|
1720
1842
|
let switch_changes = Rc::new(Cell::new(0));
|
|
1843
|
+
let switch_clicks = Rc::new(Cell::new(0));
|
|
1721
1844
|
let switch_changes_clone = switch_changes.clone();
|
|
1845
|
+
let switch_clicks_clone = switch_clicks.clone();
|
|
1722
1846
|
let switch = switch("Toggle");
|
|
1723
1847
|
switch.on_changed(move |_event| {
|
|
1724
1848
|
switch_changes_clone.set(switch_changes_clone.get() + 1);
|
|
1725
1849
|
});
|
|
1850
|
+
switch.on_click(move |_event| {
|
|
1851
|
+
switch_clicks_clone.set(switch_clicks_clone.get() + 1);
|
|
1852
|
+
});
|
|
1726
1853
|
switch.enabled(false);
|
|
1727
1854
|
Application::mount(switch.clone());
|
|
1728
1855
|
let switch_ref = switch.retained_node_ref();
|
|
@@ -1732,6 +1859,7 @@ fn pressable_labeled_enabled_forwarding_blocks_activation() {
|
|
|
1732
1859
|
key_event(KeyEventType::Down, "Space", 0);
|
|
1733
1860
|
key_event(KeyEventType::Up, "Space", 0);
|
|
1734
1861
|
assert_eq!(switch_changes.get(), 0);
|
|
1862
|
+
assert_eq!(switch_clicks.get(), 0);
|
|
1735
1863
|
}
|
|
1736
1864
|
|
|
1737
1865
|
#[test]
|
|
@@ -2986,17 +3114,21 @@ fn checkbox_persisted_state_restores_and_emits_without_announcement() {
|
|
|
2986
3114
|
)));
|
|
2987
3115
|
|
|
2988
3116
|
let changes = Rc::new(Cell::new(0));
|
|
3117
|
+
let clicks = Rc::new(Cell::new(0));
|
|
2989
3118
|
let changes_clone = changes.clone();
|
|
3119
|
+
let clicks_clone = clicks.clone();
|
|
2990
3120
|
let restored = checkbox("Agree");
|
|
2991
3121
|
restored.node_id("checkbox-persisted");
|
|
2992
3122
|
restored.tri_state(true);
|
|
2993
3123
|
restored.on_changed(move |_event| changes_clone.set(changes_clone.get() + 1));
|
|
3124
|
+
restored.on_click(move |_event| clicks_clone.set(clicks_clone.get() + 1));
|
|
2994
3125
|
Application::mount(restored.clone());
|
|
2995
3126
|
let _ = ffi::test::take_calls();
|
|
2996
3127
|
Application::restore_persisted_ui_state();
|
|
2997
3128
|
|
|
2998
3129
|
assert_eq!(restored.checked_state(), CheckState::Mixed);
|
|
2999
3130
|
assert_eq!(changes.get(), 1);
|
|
3131
|
+
assert_eq!(clicks.get(), 0);
|
|
3000
3132
|
let calls = ffi::test::take_calls();
|
|
3001
3133
|
assert!(!calls
|
|
3002
3134
|
.iter()
|
|
@@ -3023,16 +3155,20 @@ fn switch_persisted_state_restores_and_emits_without_announcement() {
|
|
|
3023
3155
|
)));
|
|
3024
3156
|
|
|
3025
3157
|
let changes = Rc::new(Cell::new(0));
|
|
3158
|
+
let clicks = Rc::new(Cell::new(0));
|
|
3026
3159
|
let changes_clone = changes.clone();
|
|
3160
|
+
let clicks_clone = clicks.clone();
|
|
3027
3161
|
let restored = switch("Toggle");
|
|
3028
3162
|
restored.node_id("switch-persisted");
|
|
3029
3163
|
restored.on_changed(move |_event| changes_clone.set(changes_clone.get() + 1));
|
|
3164
|
+
restored.on_click(move |_event| clicks_clone.set(clicks_clone.get() + 1));
|
|
3030
3165
|
Application::mount(restored.clone());
|
|
3031
3166
|
let _ = ffi::test::take_calls();
|
|
3032
3167
|
Application::restore_persisted_ui_state();
|
|
3033
3168
|
|
|
3034
3169
|
assert!(restored.is_checked());
|
|
3035
3170
|
assert_eq!(changes.get(), 1);
|
|
3171
|
+
assert_eq!(clicks.get(), 0);
|
|
3036
3172
|
let calls = ffi::test::take_calls();
|
|
3037
3173
|
assert!(!calls
|
|
3038
3174
|
.iter()
|
|
@@ -4240,6 +4376,94 @@ fn text_input_text_replaced_event_updates_value_and_emits_changed() {
|
|
|
4240
4376
|
Application::unmount();
|
|
4241
4377
|
}
|
|
4242
4378
|
|
|
4379
|
+
#[test]
|
|
4380
|
+
fn editable_controls_implement_the_shared_text_editor_surface() {
|
|
4381
|
+
fn require<T: TextEditorSurface + Node + HasFlexBoxRoot + crate::ThemeBindable>() {}
|
|
4382
|
+
|
|
4383
|
+
require::<TextInput>();
|
|
4384
|
+
require::<TextArea>();
|
|
4385
|
+
}
|
|
4386
|
+
|
|
4387
|
+
#[test]
|
|
4388
|
+
fn editable_node_metadata_and_focus_route_to_editor_while_layout_routes_to_shell() {
|
|
4389
|
+
ffi::test::reset();
|
|
4390
|
+
let input = text_input();
|
|
4391
|
+
let focused = Rc::new(Cell::new(false));
|
|
4392
|
+
input
|
|
4393
|
+
.width(320.0, Unit::Pixel)
|
|
4394
|
+
.node_id("routed-editor")
|
|
4395
|
+
.semantic_label("Explicit editor label")
|
|
4396
|
+
.focusable(true, 4)
|
|
4397
|
+
.on_focus_changed({
|
|
4398
|
+
let focused = focused.clone();
|
|
4399
|
+
move |event| focused.set(event.focused)
|
|
4400
|
+
});
|
|
4401
|
+
|
|
4402
|
+
Application::mount(input.clone());
|
|
4403
|
+
let calls = ffi::test::take_calls();
|
|
4404
|
+
let root_handle = input.retained_node_ref().handle().raw();
|
|
4405
|
+
let editor_handle = calls
|
|
4406
|
+
.iter()
|
|
4407
|
+
.find_map(|call| match call {
|
|
4408
|
+
Call::SetNodeId { handle, node_id } if node_id == "routed-editor" => Some(*handle),
|
|
4409
|
+
_ => None,
|
|
4410
|
+
})
|
|
4411
|
+
.expect("expected editor node id");
|
|
4412
|
+
|
|
4413
|
+
assert_ne!(root_handle, editor_handle);
|
|
4414
|
+
assert!(calls.iter().any(|call| matches!(
|
|
4415
|
+
call,
|
|
4416
|
+
Call::SetWidth { handle, value, unit_enum }
|
|
4417
|
+
if *handle == root_handle && *value == 320.0 && *unit_enum == Unit::Pixel as u32
|
|
4418
|
+
)));
|
|
4419
|
+
assert!(calls.iter().any(|call| matches!(
|
|
4420
|
+
call,
|
|
4421
|
+
Call::SetSemanticLabel { handle, label }
|
|
4422
|
+
if *handle == editor_handle && label == "Explicit editor label"
|
|
4423
|
+
)));
|
|
4424
|
+
assert!(calls.iter().any(|call| matches!(
|
|
4425
|
+
call,
|
|
4426
|
+
Call::SetFocusable { handle, focusable, tab_index }
|
|
4427
|
+
if *handle == editor_handle && *focusable && *tab_index == 4
|
|
4428
|
+
)));
|
|
4429
|
+
|
|
4430
|
+
event::__fui_on_focus_changed(editor_handle, true);
|
|
4431
|
+
assert!(focused.get());
|
|
4432
|
+
input.focus_now();
|
|
4433
|
+
let calls = ffi::test::take_calls();
|
|
4434
|
+
assert!(calls.iter().any(|call| matches!(
|
|
4435
|
+
call,
|
|
4436
|
+
Call::RequestFocus { handle } if *handle == editor_handle
|
|
4437
|
+
)));
|
|
4438
|
+
Application::unmount();
|
|
4439
|
+
}
|
|
4440
|
+
|
|
4441
|
+
#[test]
|
|
4442
|
+
fn text_area_prebuild_utf8_selection_replays_scalar_range_as_runtime_bytes() {
|
|
4443
|
+
ffi::test::reset();
|
|
4444
|
+
let input = text_area();
|
|
4445
|
+
input
|
|
4446
|
+
.node_id("prebuild-utf8-area")
|
|
4447
|
+
.text("a😄b")
|
|
4448
|
+
.selection_range(1, 2);
|
|
4449
|
+
Application::mount(input.clone());
|
|
4450
|
+
let calls = ffi::test::take_calls();
|
|
4451
|
+
let editor_handle = calls
|
|
4452
|
+
.iter()
|
|
4453
|
+
.find_map(|call| match call {
|
|
4454
|
+
Call::SetNodeId { handle, node_id } if node_id == "prebuild-utf8-area" => Some(*handle),
|
|
4455
|
+
_ => None,
|
|
4456
|
+
})
|
|
4457
|
+
.expect("expected text area editor node id");
|
|
4458
|
+
|
|
4459
|
+
assert!(calls.iter().any(|call| matches!(
|
|
4460
|
+
call,
|
|
4461
|
+
Call::SetTextSelectionRange { handle, start, end }
|
|
4462
|
+
if *handle == editor_handle && *start == 1 && *end == 5
|
|
4463
|
+
)));
|
|
4464
|
+
Application::unmount();
|
|
4465
|
+
}
|
|
4466
|
+
|
|
4243
4467
|
#[test]
|
|
4244
4468
|
fn text_input_selection_range_uses_char_indices_and_sends_utf8_bytes() {
|
|
4245
4469
|
ffi::test::reset();
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
use super::internal::text_input_core::TextInputCore;
|
|
2
|
-
use super::
|
|
3
|
-
use
|
|
4
|
-
use crate::event::{FocusChangedEventArgs, SelectionChangedEventArgs, TextChangedEventArgs};
|
|
2
|
+
use super::text_editor_surface::impl_text_editor_surface;
|
|
3
|
+
use crate::event::FocusChangedEventArgs;
|
|
5
4
|
use crate::node::{FlexBox, HasFlexBoxRoot, Node, NodeRef, ScrollBarVisibility};
|
|
6
|
-
use crate::FontFamily;
|
|
7
5
|
use std::any::Any;
|
|
8
6
|
use std::rc::Rc;
|
|
9
7
|
|
|
@@ -25,116 +23,6 @@ impl TextArea {
|
|
|
25
23
|
Self { core }
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
pub fn text(&self, value: impl Into<String>) -> &Self {
|
|
29
|
-
self.core.text(value);
|
|
30
|
-
self
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
pub fn value(&self) -> String {
|
|
34
|
-
self.core.value()
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
pub fn selection_start(&self) -> u32 {
|
|
38
|
-
self.core.selection_start()
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
pub fn selection_end(&self) -> u32 {
|
|
42
|
-
self.core.selection_end()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
pub fn selection_start_byte_offset(&self) -> u32 {
|
|
46
|
-
self.core.selection_start_byte_offset()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
pub fn selection_end_byte_offset(&self) -> u32 {
|
|
50
|
-
self.core.selection_end_byte_offset()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
pub fn placeholder(&self, value: impl Into<String>) -> &Self {
|
|
54
|
-
self.core.placeholder(value);
|
|
55
|
-
self
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
pub fn max_chars(&self, limit: i32) -> &Self {
|
|
59
|
-
self.core.max_chars(limit);
|
|
60
|
-
self
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
pub fn read_only(&self, flag: bool) -> &Self {
|
|
64
|
-
self.core.read_only(flag);
|
|
65
|
-
self
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
pub fn accepts_tab(&self, flag: bool) -> &Self {
|
|
69
|
-
self.core.accepts_tab(flag);
|
|
70
|
-
self
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
pub fn selection_range(&self, start: u32, end: u32) -> &Self {
|
|
74
|
-
self.core.selection_range(start, end);
|
|
75
|
-
self
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
pub fn caret(&self, position: u32) -> &Self {
|
|
79
|
-
self.core.caret(position);
|
|
80
|
-
self
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
pub fn caret_to_end(&self) -> &Self {
|
|
84
|
-
self.core.caret_to_end();
|
|
85
|
-
self
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
pub fn colors(&self, colors: TextInputColors) -> &Self {
|
|
89
|
-
self.core.colors(colors);
|
|
90
|
-
self
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
pub fn clear_colors(&self) -> &Self {
|
|
94
|
-
self.core.clear_colors();
|
|
95
|
-
self
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
pub fn template(&self, template: Rc<dyn TextInputTemplate>) -> &Self {
|
|
99
|
-
self.core.template(template);
|
|
100
|
-
self
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
pub fn clear_template(&self) -> &Self {
|
|
104
|
-
self.core.clear_template();
|
|
105
|
-
self
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
pub fn enabled(&self, enabled: bool) -> &Self {
|
|
109
|
-
self.core.enabled(enabled);
|
|
110
|
-
self
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
pub fn focusable(&self, enabled: bool, tab_index: i32) -> &Self {
|
|
114
|
-
self.core.focusable(enabled, tab_index);
|
|
115
|
-
self
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
pub fn node_id(&self, id: impl Into<String>) -> &Self {
|
|
119
|
-
self.core.node_id(id);
|
|
120
|
-
self
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
pub fn line_height(&self, value: f32) -> &Self {
|
|
124
|
-
self.core.line_height(value);
|
|
125
|
-
self
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
pub fn font_family(&self, family: FontFamily) -> &Self {
|
|
129
|
-
self.core.font_family(family);
|
|
130
|
-
self
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
pub fn font_size(&self, size: f32) -> &Self {
|
|
134
|
-
self.core.font_size(size);
|
|
135
|
-
self
|
|
136
|
-
}
|
|
137
|
-
|
|
138
26
|
pub fn wrapping(&self, flag: bool) -> &Self {
|
|
139
27
|
self.core.wrapping(flag);
|
|
140
28
|
self
|
|
@@ -150,34 +38,6 @@ impl TextArea {
|
|
|
150
38
|
self
|
|
151
39
|
}
|
|
152
40
|
|
|
153
|
-
pub fn on_changed(&self, handler: impl Fn(TextChangedEventArgs) + 'static) -> &Self {
|
|
154
|
-
self.core.on_changed(handler);
|
|
155
|
-
self
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
pub fn on_text_changed(&self, handler: impl Fn(TextChangedEventArgs) + 'static) -> &Self {
|
|
159
|
-
self.core.on_text_changed(handler);
|
|
160
|
-
self
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
pub fn on_selection_changed(
|
|
164
|
-
&self,
|
|
165
|
-
handler: impl Fn(SelectionChangedEventArgs) + 'static,
|
|
166
|
-
) -> &Self {
|
|
167
|
-
self.core.on_selection_changed(handler);
|
|
168
|
-
self
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
pub fn on_focus_changed(&self, handler: impl Fn(FocusChangedEventArgs) + 'static) -> &Self {
|
|
172
|
-
self.core.on_focus_changed(handler);
|
|
173
|
-
self
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
pub fn focus_now(&self) -> &Self {
|
|
177
|
-
self.core.focus_now();
|
|
178
|
-
self
|
|
179
|
-
}
|
|
180
|
-
|
|
181
41
|
pub fn scroll_offset_x(&self) -> f32 {
|
|
182
42
|
self.core.scroll_offset_x()
|
|
183
43
|
}
|
|
@@ -192,6 +52,8 @@ impl TextArea {
|
|
|
192
52
|
}
|
|
193
53
|
}
|
|
194
54
|
|
|
55
|
+
impl_text_editor_surface!(TextArea);
|
|
56
|
+
|
|
195
57
|
impl HasFlexBoxRoot for TextArea {
|
|
196
58
|
fn flex_box_root(&self) -> &FlexBox {
|
|
197
59
|
self.core.flex_box_root()
|
|
@@ -214,6 +76,30 @@ impl crate::ThemeBindable for TextArea {
|
|
|
214
76
|
}
|
|
215
77
|
|
|
216
78
|
impl Node for TextArea {
|
|
79
|
+
fn apply_node_id(&self, node_id: String) {
|
|
80
|
+
self.core.node_id(node_id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fn apply_semantic_label(&self, label: String) {
|
|
84
|
+
self.core.semantic_label(label);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fn apply_focusable(&self, enabled: bool, tab_index: i32) {
|
|
88
|
+
self.core.focusable(enabled, tab_index);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fn apply_focus_now(&self) {
|
|
92
|
+
self.core.focus_now();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fn apply_enabled(&self, enabled: bool) {
|
|
96
|
+
self.core.enabled(enabled);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fn apply_focus_changed_handler(&self, handler: Rc<dyn Fn(FocusChangedEventArgs)>) {
|
|
100
|
+
self.core.set_focus_changed_callback(handler);
|
|
101
|
+
}
|
|
102
|
+
|
|
217
103
|
fn retained_node_ref(&self) -> NodeRef {
|
|
218
104
|
let core = self.core.clone();
|
|
219
105
|
self.core
|