@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
|
@@ -12,11 +12,12 @@ use crate::ffi::{
|
|
|
12
12
|
CursorStyle, KeyEventType, KeyModifier, PositionType, SemanticRole, TextVerticalAlign, Unit,
|
|
13
13
|
};
|
|
14
14
|
use crate::node::{
|
|
15
|
-
flex_box,
|
|
16
|
-
ScrollBox,
|
|
15
|
+
flex_box, ChildContainerSurface, FlexBox, HasFlexBoxRoot, LayoutSurface, Node, NodeHandle,
|
|
16
|
+
ScrollBarVisibility, ScrollBox, TextNode,
|
|
17
17
|
};
|
|
18
18
|
use crate::persisted::{persisted_value_adapter, PersistedStringCodec};
|
|
19
19
|
use crate::signal::SubscriptionGuard;
|
|
20
|
+
use crate::text_indices::{scalar_count, scalar_to_byte};
|
|
20
21
|
use crate::theme::{current_theme, subscribe};
|
|
21
22
|
use crate::{focus_adorner, focus_visibility};
|
|
22
23
|
use std::cell::{Cell, RefCell};
|
|
@@ -77,39 +78,6 @@ fn create_presenter(
|
|
|
77
78
|
create_default_text_input_presenter()
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
fn char_count(text: &str) -> u32 {
|
|
81
|
-
text.chars().count() as u32
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
fn char_to_byte(text: &str, index: u32) -> u32 {
|
|
85
|
-
let target = min(index, char_count(text)) as usize;
|
|
86
|
-
if target == 0 {
|
|
87
|
-
return 0;
|
|
88
|
-
}
|
|
89
|
-
for (position, (byte, _)) in text.char_indices().enumerate() {
|
|
90
|
-
if position == target {
|
|
91
|
-
return byte as u32;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
text.len() as u32
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
fn byte_to_char(text: &str, byte_index: u32) -> u32 {
|
|
98
|
-
let target = min(byte_index as usize, text.len());
|
|
99
|
-
let mut count = 0;
|
|
100
|
-
for (byte, _) in text.char_indices() {
|
|
101
|
-
if byte >= target {
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
count += 1;
|
|
105
|
-
}
|
|
106
|
-
if target == text.len() {
|
|
107
|
-
text.chars().count() as u32
|
|
108
|
-
} else {
|
|
109
|
-
count
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
81
|
fn is_enabled(root: &FlexBox) -> bool {
|
|
114
82
|
root.retained_node_ref().is_enabled_for_routing()
|
|
115
83
|
}
|
|
@@ -118,9 +86,9 @@ pub struct TextInputCore {
|
|
|
118
86
|
self_weak: RefCell<Weak<TextInputCore>>,
|
|
119
87
|
profile: TextInputProfile,
|
|
120
88
|
root: FlexBox,
|
|
121
|
-
editor_text:
|
|
89
|
+
editor_text: TextNode,
|
|
122
90
|
editor_scroll_box: Option<ScrollBox>,
|
|
123
|
-
placeholder_text:
|
|
91
|
+
placeholder_text: TextNode,
|
|
124
92
|
placeholder_host: FlexBox,
|
|
125
93
|
placeholder_attached: Cell<bool>,
|
|
126
94
|
presenter: RefCell<Rc<dyn TextInputPresenter>>,
|
|
@@ -167,14 +135,14 @@ impl TextInputCore {
|
|
|
167
135
|
.reflect_semantic_disabled_from_enabled()
|
|
168
136
|
.selection_area_barrier(true);
|
|
169
137
|
|
|
170
|
-
let editor_text =
|
|
138
|
+
let editor_text = TextNode::new_core("");
|
|
171
139
|
editor_text
|
|
172
140
|
.semantic_role(SemanticRole::Textbox)
|
|
173
141
|
.reflect_semantic_disabled_from_enabled()
|
|
174
142
|
.focusable(true, 0)
|
|
175
143
|
.selectable(true)
|
|
176
144
|
.editable(true);
|
|
177
|
-
let placeholder_text =
|
|
145
|
+
let placeholder_text = TextNode::new_core("");
|
|
178
146
|
let placeholder_host = flex_box();
|
|
179
147
|
placeholder_host
|
|
180
148
|
.position_type(PositionType::Absolute)
|
|
@@ -333,16 +301,16 @@ impl TextInputCore {
|
|
|
333
301
|
|
|
334
302
|
pub fn selection_range(&self, start: u32, end: u32) -> &Self {
|
|
335
303
|
let text = self.text_value.borrow();
|
|
336
|
-
let start = min(start,
|
|
337
|
-
let end = min(end,
|
|
338
|
-
let start_bytes =
|
|
339
|
-
let end_bytes =
|
|
304
|
+
let start = min(start, scalar_count(&text));
|
|
305
|
+
let end = min(end, scalar_count(&text));
|
|
306
|
+
let start_bytes = scalar_to_byte(&text, start);
|
|
307
|
+
let end_bytes = scalar_to_byte(&text, end);
|
|
340
308
|
drop(text);
|
|
341
309
|
self.selection_start_chars.set(start);
|
|
342
310
|
self.selection_end_chars.set(end);
|
|
343
311
|
self.selection_start_bytes.set(start_bytes);
|
|
344
312
|
self.selection_end_bytes.set(end_bytes);
|
|
345
|
-
self.editor_text.selection_range(
|
|
313
|
+
self.editor_text.selection_range(start, end);
|
|
346
314
|
self
|
|
347
315
|
}
|
|
348
316
|
|
|
@@ -351,7 +319,7 @@ impl TextInputCore {
|
|
|
351
319
|
}
|
|
352
320
|
|
|
353
321
|
pub fn caret_to_end(&self) -> &Self {
|
|
354
|
-
let end =
|
|
322
|
+
let end = scalar_count(&self.text_value.borrow());
|
|
355
323
|
self.selection_range(end, end)
|
|
356
324
|
}
|
|
357
325
|
|
|
@@ -387,6 +355,11 @@ impl TextInputCore {
|
|
|
387
355
|
self
|
|
388
356
|
}
|
|
389
357
|
|
|
358
|
+
pub fn semantic_label(&self, label: impl Into<String>) -> &Self {
|
|
359
|
+
self.editor_text.semantic_label(label);
|
|
360
|
+
self
|
|
361
|
+
}
|
|
362
|
+
|
|
390
363
|
pub fn line_height(&self, value: f32) -> &Self {
|
|
391
364
|
self.editor_text.line_height(value);
|
|
392
365
|
self.placeholder_text.line_height(value);
|
|
@@ -463,16 +436,15 @@ impl TextInputCore {
|
|
|
463
436
|
self
|
|
464
437
|
}
|
|
465
438
|
|
|
466
|
-
pub fn
|
|
467
|
-
*self.focus_changed_callback.borrow_mut() = Some(
|
|
468
|
-
self
|
|
439
|
+
pub(crate) fn set_focus_changed_callback(&self, handler: Rc<dyn Fn(FocusChangedEventArgs)>) {
|
|
440
|
+
*self.focus_changed_callback.borrow_mut() = Some(handler);
|
|
469
441
|
}
|
|
470
442
|
|
|
471
443
|
pub fn focus_now(&self) -> &Self {
|
|
472
444
|
self.focus_editor();
|
|
473
445
|
self.editor_text.selection_range(
|
|
474
|
-
self.
|
|
475
|
-
self.
|
|
446
|
+
self.selection_start_chars.get(),
|
|
447
|
+
self.selection_end_chars.get(),
|
|
476
448
|
);
|
|
477
449
|
self
|
|
478
450
|
}
|
|
@@ -762,7 +734,7 @@ impl TextInputCore {
|
|
|
762
734
|
}
|
|
763
735
|
|
|
764
736
|
fn handle_editor_text_changed(&self) {
|
|
765
|
-
let value = self.editor_text.
|
|
737
|
+
let value = self.editor_text.content();
|
|
766
738
|
if *self.text_value.borrow() == value {
|
|
767
739
|
return;
|
|
768
740
|
}
|
|
@@ -779,13 +751,11 @@ impl TextInputCore {
|
|
|
779
751
|
}
|
|
780
752
|
|
|
781
753
|
fn handle_editor_selection_changed(&self, start: u32, end: u32) {
|
|
782
|
-
self.selection_start_bytes.set(start);
|
|
783
|
-
self.selection_end_bytes.set(end);
|
|
784
754
|
let text = self.text_value.borrow();
|
|
785
|
-
let start_chars =
|
|
786
|
-
let end_chars =
|
|
787
|
-
let start_bytes =
|
|
788
|
-
let end_bytes =
|
|
755
|
+
let start_chars = min(start, scalar_count(&text));
|
|
756
|
+
let end_chars = min(end, scalar_count(&text));
|
|
757
|
+
let start_bytes = scalar_to_byte(&text, start_chars);
|
|
758
|
+
let end_bytes = scalar_to_byte(&text, end_chars);
|
|
789
759
|
drop(text);
|
|
790
760
|
self.selection_start_bytes.set(start_bytes);
|
|
791
761
|
self.selection_end_bytes.set(end_bytes);
|
|
@@ -845,15 +815,15 @@ impl TextInputCore {
|
|
|
845
815
|
.selection_start_chars
|
|
846
816
|
.get()
|
|
847
817
|
.max(self.selection_end_chars.get());
|
|
848
|
-
let current_len =
|
|
849
|
-
let inserted_len =
|
|
818
|
+
let current_len = scalar_count(&text);
|
|
819
|
+
let inserted_len = scalar_count(inserted);
|
|
850
820
|
let replaced_len = end - start;
|
|
851
821
|
if current_len - replaced_len + inserted_len > self.max_chars_value.get() as u32 {
|
|
852
822
|
return;
|
|
853
823
|
}
|
|
854
824
|
|
|
855
|
-
let start_byte =
|
|
856
|
-
let end_byte =
|
|
825
|
+
let start_byte = scalar_to_byte(&text, start) as usize;
|
|
826
|
+
let end_byte = scalar_to_byte(&text, end) as usize;
|
|
857
827
|
let mut value =
|
|
858
828
|
String::with_capacity(text.len() - (end_byte - start_byte) + inserted.len());
|
|
859
829
|
value.push_str(&text[..start_byte]);
|
|
@@ -864,7 +834,7 @@ impl TextInputCore {
|
|
|
864
834
|
*self.text_value.borrow_mut() = value.clone();
|
|
865
835
|
let handle = self.editor_text.handle();
|
|
866
836
|
if handle != NodeHandle::INVALID {
|
|
867
|
-
let caret_byte =
|
|
837
|
+
let caret_byte = scalar_to_byte(&value, caret);
|
|
868
838
|
ui::replace_text_range(
|
|
869
839
|
handle.raw(),
|
|
870
840
|
start_byte as u32,
|
|
@@ -997,11 +967,11 @@ impl TextInputCore {
|
|
|
997
967
|
|
|
998
968
|
fn clamp_selection_to_text(&self) {
|
|
999
969
|
let text = self.text_value.borrow();
|
|
1000
|
-
let char_len =
|
|
970
|
+
let char_len = scalar_count(&text);
|
|
1001
971
|
let start_chars = min(self.selection_start_chars.get(), char_len);
|
|
1002
972
|
let end_chars = min(self.selection_end_chars.get(), char_len);
|
|
1003
|
-
let start_bytes =
|
|
1004
|
-
let end_bytes =
|
|
973
|
+
let start_bytes = scalar_to_byte(&text, start_chars);
|
|
974
|
+
let end_bytes = scalar_to_byte(&text, end_chars);
|
|
1005
975
|
drop(text);
|
|
1006
976
|
self.selection_start_chars.set(start_chars);
|
|
1007
977
|
self.selection_end_chars.set(end_chars);
|
|
@@ -1079,12 +1049,12 @@ impl TextInputCore {
|
|
|
1079
1049
|
self.root.build();
|
|
1080
1050
|
self.sync_browser_input_metadata();
|
|
1081
1051
|
self.editor_text.selection_range(
|
|
1082
|
-
self.
|
|
1083
|
-
self.
|
|
1052
|
+
self.selection_start_chars.get(),
|
|
1053
|
+
self.selection_end_chars.get(),
|
|
1084
1054
|
);
|
|
1085
1055
|
}
|
|
1086
1056
|
|
|
1087
|
-
pub(crate) fn editor_node(&self) ->
|
|
1057
|
+
pub(crate) fn editor_node(&self) -> TextNode {
|
|
1088
1058
|
self.editor_text.clone()
|
|
1089
1059
|
}
|
|
1090
1060
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use crate::controls::TextInputColors;
|
|
2
2
|
use crate::ffi::{CursorStyle, Unit};
|
|
3
|
-
use crate::node::{Border, Corners, EdgeInsets, FlexBox, PresenterHostStyle,
|
|
3
|
+
use crate::node::{Border, Corners, EdgeInsets, FlexBox, PresenterHostStyle, TextNode};
|
|
4
4
|
use crate::theme::Theme;
|
|
5
5
|
use std::cell::RefCell;
|
|
6
6
|
use std::rc::Rc;
|
|
@@ -13,7 +13,7 @@ pub struct TextInputVisualState {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
pub trait TextInputPresenter {
|
|
16
|
-
fn bind(&self, editor_host:
|
|
16
|
+
fn bind(&self, editor_host: TextNode, placeholder_host: FlexBox);
|
|
17
17
|
fn present(
|
|
18
18
|
&self,
|
|
19
19
|
theme: Theme,
|
|
@@ -28,7 +28,7 @@ pub trait TextInputTemplate {
|
|
|
28
28
|
|
|
29
29
|
#[derive(Clone, Default)]
|
|
30
30
|
pub struct DefaultTextInputPresenter {
|
|
31
|
-
editor_host: RefCell<Option<
|
|
31
|
+
editor_host: RefCell<Option<TextNode>>,
|
|
32
32
|
placeholder_host: RefCell<Option<FlexBox>>,
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -39,7 +39,7 @@ impl DefaultTextInputPresenter {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
impl TextInputPresenter for DefaultTextInputPresenter {
|
|
42
|
-
fn bind(&self, editor_host:
|
|
42
|
+
fn bind(&self, editor_host: TextNode, placeholder_host: FlexBox) {
|
|
43
43
|
*self.editor_host.borrow_mut() = Some(editor_host);
|
|
44
44
|
*self.placeholder_host.borrow_mut() = Some(placeholder_host);
|
|
45
45
|
}
|
package/src/controls/mod.rs
CHANGED
|
@@ -5,8 +5,7 @@ use crate::ffi::{
|
|
|
5
5
|
SemanticCheckedState, SemanticRole, Unit,
|
|
6
6
|
};
|
|
7
7
|
use crate::node::{
|
|
8
|
-
flex_box, row,
|
|
9
|
-
WeakNodeRef,
|
|
8
|
+
flex_box, row, FlexBox, HasFlexBoxRoot, Node, NodeRef, TextNode, ThemeBindable, WeakNodeRef,
|
|
10
9
|
};
|
|
11
10
|
use crate::theme::{current_theme, subscribe};
|
|
12
11
|
use std::cell::{Cell, RefCell};
|
|
@@ -19,8 +18,14 @@ use radio_group::WeakRadioGroupEventTarget;
|
|
|
19
18
|
pub(crate) use shared::*;
|
|
20
19
|
|
|
21
20
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
22
|
-
pub struct ClickEventArgs
|
|
23
|
-
|
|
21
|
+
pub struct ClickEventArgs;
|
|
22
|
+
|
|
23
|
+
/// Semantic click activation for controls whose primary action can be invoked
|
|
24
|
+
/// by pointer, keyboard, or another supported activation source.
|
|
25
|
+
///
|
|
26
|
+
/// Use [`Node::on_pointer_click`] when raw routed pointer data is required.
|
|
27
|
+
pub trait Clickable: Sized {
|
|
28
|
+
fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
@@ -129,6 +134,7 @@ pub mod templating;
|
|
|
129
134
|
#[cfg(test)]
|
|
130
135
|
mod tests;
|
|
131
136
|
pub mod text_area;
|
|
137
|
+
mod text_editor_surface;
|
|
132
138
|
pub mod text_input;
|
|
133
139
|
|
|
134
140
|
pub use anti_selection_area::AntiSelectionArea;
|
|
@@ -185,6 +191,7 @@ pub use templating::{
|
|
|
185
191
|
DEFAULT_SLIDER_TEMPLATE, DEFAULT_SWITCH_INDICATOR_TEMPLATE, DEFAULT_TEXT_INPUT_TEMPLATE,
|
|
186
192
|
};
|
|
187
193
|
pub use text_area::TextArea;
|
|
194
|
+
pub use text_editor_surface::TextEditorSurface;
|
|
188
195
|
pub use text_input::TextInput;
|
|
189
196
|
|
|
190
197
|
pub fn button(label: impl Into<String>) -> Button {
|
package/src/controls/popup.rs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use super::*;
|
|
2
2
|
use crate::ffi::{FlexDirection, PositionType, Unit};
|
|
3
|
-
use crate::node::
|
|
3
|
+
use crate::node::portal;
|
|
4
4
|
use crate::popup_presenter::{PopupPlacement, PopupPresenter};
|
|
5
5
|
use std::cell::Cell;
|
|
6
6
|
|
|
@@ -37,7 +37,7 @@ impl Popup {
|
|
|
37
37
|
presenter
|
|
38
38
|
.overlay_node()
|
|
39
39
|
.interactive(true)
|
|
40
|
-
.
|
|
40
|
+
.on_pointer_click(move |_event| {
|
|
41
41
|
if dismiss_flag.get() {
|
|
42
42
|
presenter_target.hide();
|
|
43
43
|
}
|
|
@@ -55,6 +55,8 @@ impl Popup {
|
|
|
55
55
|
self.presenter.is_open()
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/// Returns the presented content panel. Inherited `child`/`children` calls
|
|
59
|
+
/// are routed here rather than into the portal's overlay root.
|
|
58
60
|
pub fn surface(&self) -> FlexBox {
|
|
59
61
|
self.surface_node.clone()
|
|
60
62
|
}
|
|
@@ -91,24 +93,6 @@ impl Popup {
|
|
|
91
93
|
self
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
pub fn child<T: Node>(&self, node: &T) -> &Self {
|
|
95
|
-
self.surface_node.child(node);
|
|
96
|
-
self
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
pub fn children<I, C>(&self, nodes: I) -> &Self
|
|
100
|
-
where
|
|
101
|
-
I: IntoIterator<Item = C>,
|
|
102
|
-
C: Into<Child>,
|
|
103
|
-
{
|
|
104
|
-
for node in nodes {
|
|
105
|
-
self.surface_node
|
|
106
|
-
.retained_node_ref()
|
|
107
|
-
.append_child_ref(&node.into().node_ref);
|
|
108
|
-
}
|
|
109
|
-
self
|
|
110
|
-
}
|
|
111
|
-
|
|
112
96
|
fn sync_appearance(&self) {
|
|
113
97
|
let appearance = self.appearance_value.borrow().clone().unwrap_or_default();
|
|
114
98
|
let panel = appearance.panel.unwrap_or_default();
|
|
@@ -172,4 +156,35 @@ impl crate::node::HasFlexBoxRoot for Popup {
|
|
|
172
156
|
fn flex_box_root(&self) -> &FlexBox {
|
|
173
157
|
&self.root
|
|
174
158
|
}
|
|
159
|
+
|
|
160
|
+
fn append_flex_box_surface_child(&self, child: NodeRef) {
|
|
161
|
+
self.surface_node
|
|
162
|
+
.retained_node_ref()
|
|
163
|
+
.append_child_ref(&child);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
impl crate::node::ThemeBindable for Popup {
|
|
168
|
+
fn theme_binding_node(&self) -> NodeRef {
|
|
169
|
+
self.root.retained_node_ref()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
|
|
173
|
+
let root = self.root.downgrade();
|
|
174
|
+
let surface_node = self.surface_node.downgrade();
|
|
175
|
+
let presenter = self.presenter.downgrade();
|
|
176
|
+
let dismiss_on_backdrop_click = Rc::downgrade(&self.dismiss_on_backdrop_click);
|
|
177
|
+
// Appearance state does not own the portal root. Keep it alive with the
|
|
178
|
+
// retained theme binding so a dropped wrapper remains reconstructible.
|
|
179
|
+
let appearance_value = self.appearance_value.clone();
|
|
180
|
+
Box::new(move || {
|
|
181
|
+
Some(Self {
|
|
182
|
+
root: root.upgrade()?,
|
|
183
|
+
surface_node: surface_node.upgrade()?,
|
|
184
|
+
presenter: presenter.upgrade()?,
|
|
185
|
+
dismiss_on_backdrop_click: dismiss_on_backdrop_click.upgrade()?,
|
|
186
|
+
appearance_value: appearance_value.clone(),
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
}
|
|
175
190
|
}
|
|
@@ -221,6 +221,13 @@ impl RadioButton {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
impl Clickable for RadioButton {
|
|
225
|
+
fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
|
|
226
|
+
self.base.on_click(handler);
|
|
227
|
+
self
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
224
231
|
impl LabeledControlTextStyle for RadioButton {
|
|
225
232
|
fn set_label_font_family(&self, family: crate::FontFamily) {
|
|
226
233
|
self.base.font_family(family);
|
|
@@ -286,4 +286,21 @@ impl crate::node::HasFlexBoxRoot for RadioGroup {
|
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
+
impl crate::node::ThemeBindable for RadioGroup {
|
|
290
|
+
fn theme_binding_node(&self) -> NodeRef {
|
|
291
|
+
self.root.retained_node_ref()
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
|
|
295
|
+
let root = self.root.downgrade();
|
|
296
|
+
let event_target = Rc::downgrade(&self.event_target);
|
|
297
|
+
Box::new(move || {
|
|
298
|
+
Some(Self {
|
|
299
|
+
root: root.upgrade()?,
|
|
300
|
+
event_target: event_target.upgrade()?,
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
289
306
|
pub(crate) type WeakRadioGroupEventTarget = Weak<RadioGroupEventTarget>;
|
|
@@ -27,24 +27,6 @@ impl SelectionArea {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
pub fn child<T: Node>(&self, node: &T) -> &Self {
|
|
31
|
-
self.root.child(node);
|
|
32
|
-
self
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
pub fn children<I, C>(&self, nodes: I) -> &Self
|
|
36
|
-
where
|
|
37
|
-
I: IntoIterator<Item = C>,
|
|
38
|
-
C: Into<Child>,
|
|
39
|
-
{
|
|
40
|
-
for node in nodes {
|
|
41
|
-
self.root
|
|
42
|
-
.retained_node_ref()
|
|
43
|
-
.append_child_ref(&node.into().node_ref);
|
|
44
|
-
}
|
|
45
|
-
self
|
|
46
|
-
}
|
|
47
|
-
|
|
48
30
|
pub fn selected_text(&self) -> String {
|
|
49
31
|
self.selected_text_signal.borrow().get()
|
|
50
32
|
}
|
package/src/controls/shared.rs
CHANGED
|
@@ -20,24 +20,9 @@ pub(crate) fn is_activation_key(event: &KeyEventArgs) -> bool {
|
|
|
20
20
|
event.key == "Enter" || event.key == " " || event.key == "Space" || event.key == "Spacebar"
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
pub(crate) fn
|
|
24
|
-
click: &Rc<RefCell<Option<ClickCallback>>>,
|
|
25
|
-
double_click: &Rc<RefCell<Option<ClickCallback>>>,
|
|
26
|
-
triple_click: &Rc<RefCell<Option<ClickCallback>>>,
|
|
27
|
-
click_count: i32,
|
|
28
|
-
) {
|
|
29
|
-
let args = ClickEventArgs { click_count };
|
|
23
|
+
pub(crate) fn fire_click_callback(click: &Rc<RefCell<Option<ClickCallback>>>) {
|
|
30
24
|
if let Some(callback) = click.borrow().clone() {
|
|
31
|
-
callback(
|
|
32
|
-
}
|
|
33
|
-
if click_count == 3 {
|
|
34
|
-
if let Some(callback) = triple_click.borrow().clone() {
|
|
35
|
-
callback(args);
|
|
36
|
-
}
|
|
37
|
-
} else if click_count == 2 {
|
|
38
|
-
if let Some(callback) = double_click.borrow().clone() {
|
|
39
|
-
callback(args);
|
|
40
|
-
}
|
|
25
|
+
callback(ClickEventArgs);
|
|
41
26
|
}
|
|
42
27
|
}
|
|
43
28
|
|
package/src/controls/switch.rs
CHANGED
|
@@ -212,6 +212,13 @@ impl Switch {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
impl Clickable for Switch {
|
|
216
|
+
fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
|
|
217
|
+
self.base.on_click(handler);
|
|
218
|
+
self
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
215
222
|
impl LabeledControlTextStyle for Switch {
|
|
216
223
|
fn set_label_font_family(&self, family: crate::FontFamily) {
|
|
217
224
|
self.base.font_family(family);
|