@effindomv2/fui-rs 0.1.23 → 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 +444 -64
- 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/Cargo.toml
CHANGED
package/README.md
CHANGED
|
@@ -186,6 +186,18 @@ calls.
|
|
|
186
186
|
Retained controls are cheap clone handles. Cloning a control gives another Rust
|
|
187
187
|
handle to the same retained UI object.
|
|
188
188
|
|
|
189
|
+
FUI-RS maps retained inheritance to capability traits. `Node` supplies the
|
|
190
|
+
universal retained/event surface; FlexBox-derived visuals additionally expose
|
|
191
|
+
`LayoutSurface`, `BoxStyleSurface`, `FlexLayoutSurface`, and
|
|
192
|
+
`ChildContainerSurface`. `TextSurface` covers `Text` and `RichText`, while
|
|
193
|
+
`TextEditorSurface` covers `TextInput` and `TextArea`.
|
|
194
|
+
|
|
195
|
+
Use `on_pointer_click(...)` for raw routed pointer input. Use
|
|
196
|
+
`on_pointer_double_click(...)` and `on_pointer_triple_click(...)` for exact raw
|
|
197
|
+
multi-click gestures. `Button`, `Checkbox`, `RadioButton`, and `Switch` expose
|
|
198
|
+
count-free `on_click(...)` semantic activation for supported pointer and
|
|
199
|
+
keyboard input.
|
|
200
|
+
|
|
189
201
|
## License
|
|
190
202
|
|
|
191
203
|
AGPL-3.0-only, or commercial license. See [COMMERCIAL.md](COMMERCIAL.md).
|
package/package.json
CHANGED
|
@@ -11,24 +11,6 @@ impl AntiSelectionArea {
|
|
|
11
11
|
root.selection_area_barrier(true);
|
|
12
12
|
Self { root }
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
pub fn child<T: Node>(&self, node: &T) -> &Self {
|
|
16
|
-
self.root.child(node);
|
|
17
|
-
self
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub fn children<I, C>(&self, nodes: I) -> &Self
|
|
21
|
-
where
|
|
22
|
-
I: IntoIterator<Item = C>,
|
|
23
|
-
C: Into<Child>,
|
|
24
|
-
{
|
|
25
|
-
for node in nodes {
|
|
26
|
-
self.root
|
|
27
|
-
.retained_node_ref()
|
|
28
|
-
.append_child_ref(&node.into().node_ref);
|
|
29
|
-
}
|
|
30
|
-
self
|
|
31
|
-
}
|
|
32
14
|
}
|
|
33
15
|
|
|
34
16
|
impl Default for AntiSelectionArea {
|
package/src/controls/button.rs
CHANGED
|
@@ -3,7 +3,7 @@ use super::internal::button_presenter::{
|
|
|
3
3
|
};
|
|
4
4
|
use super::*;
|
|
5
5
|
use crate::ffi::CursorStyle;
|
|
6
|
-
use crate::node::{
|
|
6
|
+
use crate::node::{TextNode, WeakFlexBox};
|
|
7
7
|
use crate::theme::subscribe;
|
|
8
8
|
use crate::{focus_adorner, focus_visibility};
|
|
9
9
|
use std::rc::Rc;
|
|
@@ -12,12 +12,10 @@ use std::rc::Rc;
|
|
|
12
12
|
pub struct Button {
|
|
13
13
|
root: FlexBox,
|
|
14
14
|
presenter: Rc<RefCell<Rc<dyn ButtonPresenter>>>,
|
|
15
|
-
label: Rc<RefCell<
|
|
15
|
+
label: Rc<RefCell<TextNode>>,
|
|
16
16
|
template: Rc<RefCell<Option<Rc<dyn ButtonTemplate>>>>,
|
|
17
17
|
label_value: Rc<RefCell<String>>,
|
|
18
18
|
click: Rc<RefCell<Option<ClickCallback>>>,
|
|
19
|
-
double_click: Rc<RefCell<Option<ClickCallback>>>,
|
|
20
|
-
triple_click: Rc<RefCell<Option<ClickCallback>>>,
|
|
21
19
|
hovered_state: Rc<Cell<bool>>,
|
|
22
20
|
pressed_state: Rc<Cell<bool>>,
|
|
23
21
|
focused_state: Rc<Cell<bool>>,
|
|
@@ -49,8 +47,6 @@ impl Button {
|
|
|
49
47
|
template: Rc::new(RefCell::new(None)),
|
|
50
48
|
label_value: Rc::new(RefCell::new(label.clone())),
|
|
51
49
|
click: Rc::new(RefCell::new(None)),
|
|
52
|
-
double_click: Rc::new(RefCell::new(None)),
|
|
53
|
-
triple_click: Rc::new(RefCell::new(None)),
|
|
54
50
|
hovered_state: Rc::new(Cell::new(false)),
|
|
55
51
|
pressed_state: Rc::new(Cell::new(false)),
|
|
56
52
|
focused_state: Rc::new(Cell::new(false)),
|
|
@@ -94,13 +90,8 @@ impl Button {
|
|
|
94
90
|
});
|
|
95
91
|
|
|
96
92
|
let event_target = self.event_target();
|
|
97
|
-
self.root.
|
|
98
|
-
|
|
99
|
-
&event_target.click,
|
|
100
|
-
&event_target.double_click,
|
|
101
|
-
&event_target.triple_click,
|
|
102
|
-
event.click_count.max(1),
|
|
103
|
-
);
|
|
93
|
+
self.root.on_pointer_click(move |event| {
|
|
94
|
+
fire_click_callback(&event_target.click);
|
|
104
95
|
event.handled = true;
|
|
105
96
|
});
|
|
106
97
|
let event_target = self.event_target();
|
|
@@ -126,12 +117,7 @@ impl Button {
|
|
|
126
117
|
if armed.as_deref() == Some(event.key.as_str()) {
|
|
127
118
|
*event_target.keyboard_armed_key.borrow_mut() = None;
|
|
128
119
|
event_target.end_press();
|
|
129
|
-
|
|
130
|
-
&event_target.click,
|
|
131
|
-
&event_target.double_click,
|
|
132
|
-
&event_target.triple_click,
|
|
133
|
-
1,
|
|
134
|
-
);
|
|
120
|
+
fire_click_callback(&event_target.click);
|
|
135
121
|
event.handled = true;
|
|
136
122
|
}
|
|
137
123
|
});
|
|
@@ -185,21 +171,6 @@ impl Button {
|
|
|
185
171
|
self
|
|
186
172
|
}
|
|
187
173
|
|
|
188
|
-
pub fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
|
|
189
|
-
*self.click.borrow_mut() = Some(Rc::new(handler));
|
|
190
|
-
self
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
pub fn on_double_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
|
|
194
|
-
*self.double_click.borrow_mut() = Some(Rc::new(handler));
|
|
195
|
-
self
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
pub fn on_triple_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
|
|
199
|
-
*self.triple_click.borrow_mut() = Some(Rc::new(handler));
|
|
200
|
-
self
|
|
201
|
-
}
|
|
202
|
-
|
|
203
174
|
pub fn enabled(&self, enabled: bool) -> &Self {
|
|
204
175
|
self.root.enabled(enabled);
|
|
205
176
|
if !enabled {
|
|
@@ -255,8 +226,6 @@ impl Button {
|
|
|
255
226
|
template: self.template.clone(),
|
|
256
227
|
label_value: self.label_value.clone(),
|
|
257
228
|
click: self.click.clone(),
|
|
258
|
-
double_click: self.double_click.clone(),
|
|
259
|
-
triple_click: self.triple_click.clone(),
|
|
260
229
|
hovered_state: self.hovered_state.clone(),
|
|
261
230
|
pressed_state: self.pressed_state.clone(),
|
|
262
231
|
focused_state: self.focused_state.clone(),
|
|
@@ -283,7 +252,7 @@ impl Button {
|
|
|
283
252
|
self.sync_visual_state();
|
|
284
253
|
self.sync_focus_chrome();
|
|
285
254
|
if activate {
|
|
286
|
-
|
|
255
|
+
fire_click_callback(&self.click);
|
|
287
256
|
}
|
|
288
257
|
}
|
|
289
258
|
|
|
@@ -331,6 +300,13 @@ impl Button {
|
|
|
331
300
|
}
|
|
332
301
|
}
|
|
333
302
|
|
|
303
|
+
impl Clickable for Button {
|
|
304
|
+
fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
|
|
305
|
+
*self.click.borrow_mut() = Some(Rc::new(handler));
|
|
306
|
+
self
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
334
310
|
impl Node for Button {
|
|
335
311
|
fn retained_node_ref(&self) -> NodeRef {
|
|
336
312
|
self.root.retained_node_ref()
|
|
@@ -450,12 +426,10 @@ fn create_button_presenter(template: Option<Rc<dyn ButtonTemplate>>) -> Rc<dyn B
|
|
|
450
426
|
struct ButtonEventTarget {
|
|
451
427
|
weak_root: WeakFlexBox,
|
|
452
428
|
presenter: Rc<RefCell<Rc<dyn ButtonPresenter>>>,
|
|
453
|
-
label: Rc<RefCell<
|
|
429
|
+
label: Rc<RefCell<TextNode>>,
|
|
454
430
|
template: Rc<RefCell<Option<Rc<dyn ButtonTemplate>>>>,
|
|
455
431
|
label_value: Rc<RefCell<String>>,
|
|
456
432
|
click: Rc<RefCell<Option<ClickCallback>>>,
|
|
457
|
-
double_click: Rc<RefCell<Option<ClickCallback>>>,
|
|
458
|
-
triple_click: Rc<RefCell<Option<ClickCallback>>>,
|
|
459
433
|
hovered_state: Rc<Cell<bool>>,
|
|
460
434
|
pressed_state: Rc<Cell<bool>>,
|
|
461
435
|
focused_state: Rc<Cell<bool>>,
|
|
@@ -475,8 +449,6 @@ impl ButtonEventTarget {
|
|
|
475
449
|
template: self.template.clone(),
|
|
476
450
|
label_value: self.label_value.clone(),
|
|
477
451
|
click: self.click.clone(),
|
|
478
|
-
double_click: self.double_click.clone(),
|
|
479
|
-
triple_click: self.triple_click.clone(),
|
|
480
452
|
hovered_state: self.hovered_state.clone(),
|
|
481
453
|
pressed_state: self.pressed_state.clone(),
|
|
482
454
|
focused_state: self.focused_state.clone(),
|
package/src/controls/checkbox.rs
CHANGED
|
@@ -289,6 +289,13 @@ impl Checkbox {
|
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
impl Clickable for Checkbox {
|
|
293
|
+
fn on_click(&self, handler: impl Fn(ClickEventArgs) + 'static) -> &Self {
|
|
294
|
+
self.base.on_click(handler);
|
|
295
|
+
self
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
292
299
|
impl LabeledControlTextStyle for Checkbox {
|
|
293
300
|
fn set_label_font_family(&self, family: crate::FontFamily) {
|
|
294
301
|
self.base.font_family(family);
|
package/src/controls/combobox.rs
CHANGED
|
@@ -10,7 +10,7 @@ use super::internal::selectable_popup_list::{
|
|
|
10
10
|
use super::internal::text_input_presenter::{
|
|
11
11
|
TextInputPresenter, TextInputTemplate, TextInputVisualState,
|
|
12
12
|
};
|
|
13
|
-
use super::{DropdownColors, DropdownSizing, TextInput, TextInputColors};
|
|
13
|
+
use super::{DropdownColors, DropdownSizing, TextEditorSurface, TextInput, TextInputColors};
|
|
14
14
|
use crate::bindings::ui;
|
|
15
15
|
use crate::event::{self, TextChangedEventArgs};
|
|
16
16
|
use crate::ffi::{
|
|
@@ -20,7 +20,8 @@ use crate::focus_adorner;
|
|
|
20
20
|
use crate::focus_visibility;
|
|
21
21
|
use crate::logger;
|
|
22
22
|
use crate::node::{
|
|
23
|
-
row,
|
|
23
|
+
row, BoxStyleSurface, FlexBox, HasFlexBoxRoot, LayoutSurface, Node, NodeRef, TextNode,
|
|
24
|
+
WeakFlexBox,
|
|
24
25
|
};
|
|
25
26
|
use crate::signal::SubscriptionGuard;
|
|
26
27
|
use crate::theme::{current_theme, subscribe, Theme};
|
|
@@ -88,12 +89,12 @@ fn resolve_text_input_colors(
|
|
|
88
89
|
|
|
89
90
|
#[derive(Clone, Default)]
|
|
90
91
|
struct ComboBoxEditorPresenter {
|
|
91
|
-
editor_host: RefCell<Option<
|
|
92
|
+
editor_host: RefCell<Option<TextNode>>,
|
|
92
93
|
placeholder_host: RefCell<Option<FlexBox>>,
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
impl TextInputPresenter for ComboBoxEditorPresenter {
|
|
96
|
-
fn bind(&self, editor_host:
|
|
97
|
+
fn bind(&self, editor_host: TextNode, placeholder_host: FlexBox) {
|
|
97
98
|
*self.editor_host.borrow_mut() = Some(editor_host);
|
|
98
99
|
*self.placeholder_host.borrow_mut() = Some(placeholder_host);
|
|
99
100
|
}
|
|
@@ -401,7 +402,7 @@ impl ComboBox {
|
|
|
401
402
|
root.retained_node_ref().retain_attachment(shared.clone());
|
|
402
403
|
shared.rebuild_filtered_indices();
|
|
403
404
|
|
|
404
|
-
popup_list.popup_presenter.overlay_node().
|
|
405
|
+
popup_list.popup_presenter.overlay_node().on_pointer_click({
|
|
405
406
|
let weak_shared = Rc::downgrade(&shared);
|
|
406
407
|
move |_event| {
|
|
407
408
|
if let Some(shared) = weak_shared.upgrade() {
|
|
@@ -589,7 +590,7 @@ impl ComboBox {
|
|
|
589
590
|
self.shared.editor.editor_node().editor_command_keys(true);
|
|
590
591
|
|
|
591
592
|
let weak_shared = Rc::downgrade(&self.shared);
|
|
592
|
-
self.shared.chevron_host.
|
|
593
|
+
self.shared.chevron_host.on_pointer_click(move |event| {
|
|
593
594
|
let Some(shared) = weak_shared.upgrade() else {
|
|
594
595
|
return;
|
|
595
596
|
};
|
|
@@ -8,8 +8,8 @@ use crate::ffi::{
|
|
|
8
8
|
use crate::logger::warn;
|
|
9
9
|
use crate::navigation;
|
|
10
10
|
use crate::node::{
|
|
11
|
-
column, flex_box, grid, portal, Border, FlexBox, Grid, GridTrack,
|
|
12
|
-
WeakFlexBox,
|
|
11
|
+
column, flex_box, grid, portal, Border, BoxStyleSurface, FlexBox, Grid, GridTrack,
|
|
12
|
+
LayoutSurface, Node, NodeRef, TextNode, ThemeBindable, WeakFlexBox,
|
|
13
13
|
};
|
|
14
14
|
use crate::popup_presenter::{PopupPresenter, PopupPresenterEventTarget};
|
|
15
15
|
use crate::theme::{current_theme, subscribe, Theme};
|
|
@@ -816,8 +816,8 @@ impl ContextMenuEventTarget {
|
|
|
816
816
|
return;
|
|
817
817
|
};
|
|
818
818
|
let state = self.state.borrow();
|
|
819
|
+
Grid::shared_size_scope(&panel, true);
|
|
819
820
|
panel
|
|
820
|
-
.shared_size_scope(true)
|
|
821
821
|
.width(state.menu_width, Unit::Pixel)
|
|
822
822
|
.bg_color(state.panel_background_color)
|
|
823
823
|
.background_blur(state.panel_background_blur_sigma)
|
|
@@ -968,9 +968,9 @@ impl ContextMenu {
|
|
|
968
968
|
let theme = current_theme();
|
|
969
969
|
let root = portal();
|
|
970
970
|
let panel = column();
|
|
971
|
+
panel.position_type(crate::ffi::PositionType::Absolute);
|
|
972
|
+
Grid::shared_size_scope(&panel, true);
|
|
971
973
|
panel
|
|
972
|
-
.position_type(crate::ffi::PositionType::Absolute)
|
|
973
|
-
.shared_size_scope(true)
|
|
974
974
|
.width(MENU_WIDTH, Unit::Pixel)
|
|
975
975
|
.padding(4.0, 4.0, 4.0, 4.0)
|
|
976
976
|
.border(1.0, theme.context_menu.panel_border_color);
|
|
@@ -1265,3 +1265,36 @@ impl crate::node::HasFlexBoxRoot for ContextMenu {
|
|
|
1265
1265
|
&self.root
|
|
1266
1266
|
}
|
|
1267
1267
|
}
|
|
1268
|
+
|
|
1269
|
+
impl ThemeBindable for ContextMenu {
|
|
1270
|
+
fn theme_binding_node(&self) -> NodeRef {
|
|
1271
|
+
self.root.retained_node_ref()
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
|
|
1275
|
+
let root = self.root.downgrade();
|
|
1276
|
+
let panel = self.panel.downgrade();
|
|
1277
|
+
let popup_presenter = self.popup_presenter.downgrade();
|
|
1278
|
+
let items = Rc::downgrade(&self.items);
|
|
1279
|
+
let entries = self.entries.clone();
|
|
1280
|
+
let separators = self.separators.clone();
|
|
1281
|
+
let current_items = Rc::downgrade(&self.current_items);
|
|
1282
|
+
let current_item_tops = Rc::downgrade(&self.current_item_tops);
|
|
1283
|
+
let current_item_heights = Rc::downgrade(&self.current_item_heights);
|
|
1284
|
+
let state = Rc::downgrade(&self.state);
|
|
1285
|
+
Box::new(move || {
|
|
1286
|
+
Some(Self {
|
|
1287
|
+
root: root.upgrade()?,
|
|
1288
|
+
panel: panel.upgrade()?,
|
|
1289
|
+
popup_presenter: popup_presenter.upgrade()?,
|
|
1290
|
+
items: items.upgrade()?,
|
|
1291
|
+
entries: entries.clone(),
|
|
1292
|
+
separators: separators.clone(),
|
|
1293
|
+
current_items: current_items.upgrade()?,
|
|
1294
|
+
current_item_tops: current_item_tops.upgrade()?,
|
|
1295
|
+
current_item_heights: current_item_heights.upgrade()?,
|
|
1296
|
+
state: state.upgrade()?,
|
|
1297
|
+
})
|
|
1298
|
+
})
|
|
1299
|
+
}
|
|
1300
|
+
}
|
package/src/controls/dialog.rs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
use super::DialogAppearance;
|
|
2
|
-
use super::{Button, Form};
|
|
2
|
+
use super::{Button, Clickable, Form};
|
|
3
3
|
use crate::app;
|
|
4
4
|
use crate::bindings::ui;
|
|
5
5
|
use crate::ffi::{
|
|
6
6
|
AlignItems, BorderStyle, FlexDirection, JustifyContent, PositionType, SemanticRole, Unit,
|
|
7
7
|
};
|
|
8
|
-
use crate::node::{
|
|
8
|
+
use crate::node::{
|
|
9
|
+
flex_box, portal, Border, ChildContainerSurface, FlexBox, Node, NodeRef, TextNode,
|
|
10
|
+
ThemeBindable, WeakFlexBox,
|
|
11
|
+
};
|
|
9
12
|
use crate::theme::{current_theme, subscribe, Theme};
|
|
10
13
|
use std::cell::RefCell;
|
|
11
14
|
use std::rc::Rc;
|
|
@@ -363,7 +366,7 @@ impl Dialog {
|
|
|
363
366
|
});
|
|
364
367
|
|
|
365
368
|
let event_target = self.event_target();
|
|
366
|
-
self.overlay.
|
|
369
|
+
self.overlay.on_pointer_click(move |event| {
|
|
367
370
|
event_target.handle_backdrop_click(event);
|
|
368
371
|
});
|
|
369
372
|
|
|
@@ -434,6 +437,41 @@ impl crate::node::HasFlexBoxRoot for Dialog {
|
|
|
434
437
|
}
|
|
435
438
|
}
|
|
436
439
|
|
|
440
|
+
impl ThemeBindable for Dialog {
|
|
441
|
+
fn theme_binding_node(&self) -> NodeRef {
|
|
442
|
+
self.root.retained_node_ref()
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
|
|
446
|
+
let root = self.root.downgrade();
|
|
447
|
+
let title_node = self.title_node.clone();
|
|
448
|
+
let body_node = self.body_node.clone();
|
|
449
|
+
let content_host = self.content_host.clone();
|
|
450
|
+
let accept_button = self.accept_button.clone();
|
|
451
|
+
let cancel_button = self.cancel_button.clone();
|
|
452
|
+
let buttons_row = self._buttons_row.clone();
|
|
453
|
+
let form = self.form.clone();
|
|
454
|
+
let card = self.card.clone();
|
|
455
|
+
let overlay = self.overlay.clone();
|
|
456
|
+
let state = self.state.clone();
|
|
457
|
+
Box::new(move || {
|
|
458
|
+
Some(Self {
|
|
459
|
+
root: root.upgrade()?,
|
|
460
|
+
title_node: title_node.clone(),
|
|
461
|
+
body_node: body_node.clone(),
|
|
462
|
+
content_host: content_host.clone(),
|
|
463
|
+
accept_button: accept_button.clone(),
|
|
464
|
+
cancel_button: cancel_button.clone(),
|
|
465
|
+
_buttons_row: buttons_row.clone(),
|
|
466
|
+
form: form.clone(),
|
|
467
|
+
card: card.clone(),
|
|
468
|
+
overlay: overlay.clone(),
|
|
469
|
+
state: state.clone(),
|
|
470
|
+
})
|
|
471
|
+
})
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
437
475
|
impl DialogEventTarget {
|
|
438
476
|
fn hide(&self) {
|
|
439
477
|
let Some(root) = self.root.upgrade() else {
|
package/src/controls/dropdown.rs
CHANGED
|
@@ -18,7 +18,7 @@ use crate::ffi::{AlignItems, CursorStyle, FlexDirection, KeyEventType, NodeType,
|
|
|
18
18
|
use crate::focus_adorner;
|
|
19
19
|
use crate::focus_visibility;
|
|
20
20
|
use crate::logger;
|
|
21
|
-
use crate::node::{row,
|
|
21
|
+
use crate::node::{row, BoxStyleSurface, FlexBox, HasFlexBoxRoot, Node, NodeRef, WeakFlexBox};
|
|
22
22
|
use crate::persisted::{persisted_value_adapter, PersistedInt32Codec};
|
|
23
23
|
use crate::signal::SubscriptionGuard;
|
|
24
24
|
use crate::theme::{current_theme, subscribe};
|
|
@@ -243,7 +243,7 @@ impl Dropdown {
|
|
|
243
243
|
*shared_slot.borrow_mut() = Some(Rc::downgrade(&shared));
|
|
244
244
|
root.retained_node_ref().retain_attachment(shared.clone());
|
|
245
245
|
|
|
246
|
-
popup_list.popup_presenter.overlay_node().
|
|
246
|
+
popup_list.popup_presenter.overlay_node().on_pointer_click({
|
|
247
247
|
let weak_shared = Rc::downgrade(&shared);
|
|
248
248
|
move |_event| {
|
|
249
249
|
if let Some(shared) = weak_shared.upgrade() {
|
package/src/controls/form.rs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use super::Button;
|
|
2
2
|
use crate::event;
|
|
3
3
|
use crate::ffi::{FlexDirection, KeyEventType, SemanticRole};
|
|
4
|
-
use crate::node::{flex_box,
|
|
4
|
+
use crate::node::{flex_box, FlexBox, Node, NodeRef, ThemeBindable};
|
|
5
5
|
use std::any::Any;
|
|
6
6
|
use std::cell::{Cell, RefCell};
|
|
7
7
|
use std::rc::Rc;
|
|
@@ -61,25 +61,6 @@ impl Form {
|
|
|
61
61
|
self
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
pub fn child<T: Node>(&self, node: &T) -> &Self {
|
|
65
|
-
self.shared.root.child(node);
|
|
66
|
-
self
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
pub fn children<I, C>(&self, nodes: I) -> &Self
|
|
70
|
-
where
|
|
71
|
-
I: IntoIterator<Item = C>,
|
|
72
|
-
C: Into<Child>,
|
|
73
|
-
{
|
|
74
|
-
for node in nodes {
|
|
75
|
-
self.shared
|
|
76
|
-
.root
|
|
77
|
-
.retained_node_ref()
|
|
78
|
-
.append_child_ref(&node.into().node_ref);
|
|
79
|
-
}
|
|
80
|
-
self
|
|
81
|
-
}
|
|
82
|
-
|
|
83
64
|
pub fn activate(&self) {
|
|
84
65
|
if self.shared.key_filter_token.get() != 0
|
|
85
66
|
|| (self.shared.default_button.borrow().is_none()
|
|
@@ -233,3 +214,18 @@ impl crate::node::HasFlexBoxRoot for Form {
|
|
|
233
214
|
&self.shared.root
|
|
234
215
|
}
|
|
235
216
|
}
|
|
217
|
+
|
|
218
|
+
impl ThemeBindable for Form {
|
|
219
|
+
fn theme_binding_node(&self) -> NodeRef {
|
|
220
|
+
self.shared.root.retained_node_ref()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
|
|
224
|
+
let shared = Rc::downgrade(&self.shared);
|
|
225
|
+
Box::new(move || {
|
|
226
|
+
Some(Self {
|
|
227
|
+
shared: shared.upgrade()?,
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use crate::controls::ButtonColors;
|
|
2
2
|
use crate::ffi::{AlignItems, FlexDirection, JustifyContent};
|
|
3
3
|
use crate::node::{
|
|
4
|
-
flex_box, Border, Corners, EdgeInsets, FlexBox, PresenterHostStyle, Shadow,
|
|
4
|
+
flex_box, Border, Corners, EdgeInsets, FlexBox, PresenterHostStyle, Shadow, TextNode,
|
|
5
5
|
};
|
|
6
6
|
use crate::theme::Theme;
|
|
7
7
|
use crate::{FontStyle, FontWeight};
|
|
@@ -17,7 +17,7 @@ pub struct ButtonVisualState {
|
|
|
17
17
|
|
|
18
18
|
pub trait ButtonPresenter {
|
|
19
19
|
fn content_root(&self) -> FlexBox;
|
|
20
|
-
fn label_node(&self) ->
|
|
20
|
+
fn label_node(&self) -> TextNode;
|
|
21
21
|
fn present(
|
|
22
22
|
&self,
|
|
23
23
|
theme: Theme,
|
|
@@ -33,12 +33,12 @@ pub trait ButtonTemplate {
|
|
|
33
33
|
#[derive(Clone)]
|
|
34
34
|
pub struct DefaultButtonPresenter {
|
|
35
35
|
content_root: FlexBox,
|
|
36
|
-
label_node:
|
|
36
|
+
label_node: TextNode,
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
impl DefaultButtonPresenter {
|
|
40
40
|
pub fn new() -> Self {
|
|
41
|
-
let label_node =
|
|
41
|
+
let label_node = TextNode::new_core("");
|
|
42
42
|
let content_root = flex_box();
|
|
43
43
|
content_root
|
|
44
44
|
.flex_direction(FlexDirection::Row)
|
|
@@ -57,7 +57,7 @@ impl ButtonPresenter for DefaultButtonPresenter {
|
|
|
57
57
|
self.content_root.clone()
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
fn label_node(&self) ->
|
|
60
|
+
fn label_node(&self) -> TextNode {
|
|
61
61
|
self.label_node.clone()
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -3,7 +3,7 @@ use super::pressable_indicator_presenter::{
|
|
|
3
3
|
};
|
|
4
4
|
use crate::controls::{LabeledControlColors, LabeledControlSizing};
|
|
5
5
|
use crate::ffi::{AlignItems, JustifyContent, SemanticCheckedState, Unit};
|
|
6
|
-
use crate::node::{flex_box, svg, FlexBox, SvgNode};
|
|
6
|
+
use crate::node::{flex_box, svg, BoxStyleSurface, FlexBox, SvgNode};
|
|
7
7
|
use crate::theme::Theme;
|
|
8
8
|
use std::rc::Rc;
|
|
9
9
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
use crate::controls::LabeledControlColors;
|
|
1
|
+
use crate::controls::{ClickCallback, ClickEventArgs, LabeledControlColors};
|
|
2
2
|
use crate::event::{FocusChangedEventArgs, KeyEventArgs, PointerEventArgs};
|
|
3
3
|
use crate::ffi::{
|
|
4
4
|
AlignItems, CursorStyle, FlexDirection, KeyEventType, PointerEventType, SemanticRole, Unit,
|
|
5
5
|
};
|
|
6
|
-
use crate::node::{flex_box, FlexBox, Node,
|
|
6
|
+
use crate::node::{flex_box, FlexBox, Node, TextNode, WeakFlexBox};
|
|
7
7
|
use crate::theme::{current_theme, subscribe};
|
|
8
8
|
use crate::{focus_adorner, focus_visibility};
|
|
9
9
|
use std::cell::{Cell, RefCell};
|
|
@@ -27,7 +27,7 @@ pub(crate) struct PressableLabeledControlState {
|
|
|
27
27
|
pub(crate) struct PressableLabeledControl {
|
|
28
28
|
root: FlexBox,
|
|
29
29
|
indicator_root: Rc<RefCell<FlexBox>>,
|
|
30
|
-
label_node:
|
|
30
|
+
label_node: TextNode,
|
|
31
31
|
gap_node: FlexBox,
|
|
32
32
|
label_host: FlexBox,
|
|
33
33
|
hovered_state: Rc<Cell<bool>>,
|
|
@@ -41,6 +41,7 @@ pub(crate) struct PressableLabeledControl {
|
|
|
41
41
|
label_text_color_override: Rc<Cell<Option<u32>>>,
|
|
42
42
|
colors_value: Rc<Cell<Option<LabeledControlColors>>>,
|
|
43
43
|
activation: Rc<RefCell<Option<ActivationCallback>>>,
|
|
44
|
+
click: Rc<RefCell<Option<ClickCallback>>>,
|
|
44
45
|
state_changed: Rc<RefCell<Option<StateCallback>>>,
|
|
45
46
|
key_handler: Rc<RefCell<Option<KeyCallback>>>,
|
|
46
47
|
}
|
|
@@ -49,7 +50,7 @@ impl PressableLabeledControl {
|
|
|
49
50
|
pub fn new(role: SemanticRole, label: impl Into<String>, indicator_root: FlexBox) -> Self {
|
|
50
51
|
let label = label.into();
|
|
51
52
|
let root = flex_box();
|
|
52
|
-
let label_node =
|
|
53
|
+
let label_node = TextNode::new_core(&label);
|
|
53
54
|
let gap_node = flex_box();
|
|
54
55
|
let label_host = flex_box();
|
|
55
56
|
label_host.child(&label_node);
|
|
@@ -82,6 +83,7 @@ impl PressableLabeledControl {
|
|
|
82
83
|
label_text_color_override: Rc::new(Cell::new(None)),
|
|
83
84
|
colors_value: Rc::new(Cell::new(None)),
|
|
84
85
|
activation: Rc::new(RefCell::new(None)),
|
|
86
|
+
click: Rc::new(RefCell::new(None)),
|
|
85
87
|
state_changed: Rc::new(RefCell::new(None)),
|
|
86
88
|
key_handler: Rc::new(RefCell::new(None)),
|
|
87
89
|
};
|
|
@@ -114,6 +116,7 @@ impl PressableLabeledControl {
|
|
|
114
116
|
label_text_color_override: self.label_text_color_override.clone(),
|
|
115
117
|
colors_value: self.colors_value.clone(),
|
|
116
118
|
activation: self.activation.clone(),
|
|
119
|
+
click: self.click.clone(),
|
|
117
120
|
state_changed: self.state_changed.clone(),
|
|
118
121
|
key_handler: self.key_handler.clone(),
|
|
119
122
|
}
|
|
@@ -133,6 +136,10 @@ impl PressableLabeledControl {
|
|
|
133
136
|
*self.activation.borrow_mut() = Some(Rc::new(callback));
|
|
134
137
|
}
|
|
135
138
|
|
|
139
|
+
pub(crate) fn on_click(&self, callback: impl Fn(ClickEventArgs) + 'static) {
|
|
140
|
+
*self.click.borrow_mut() = Some(Rc::new(callback));
|
|
141
|
+
}
|
|
142
|
+
|
|
136
143
|
pub(crate) fn set_state_changed(
|
|
137
144
|
&self,
|
|
138
145
|
callback: impl Fn(PressableLabeledControlState) + 'static,
|
|
@@ -298,6 +305,7 @@ impl PressableLabeledControl {
|
|
|
298
305
|
label_text_color_override: self.label_text_color_override.clone(),
|
|
299
306
|
colors_value: self.colors_value.clone(),
|
|
300
307
|
activation: self.activation.clone(),
|
|
308
|
+
click: self.click.clone(),
|
|
301
309
|
state_changed: self.state_changed.clone(),
|
|
302
310
|
key_handler: self.key_handler.clone(),
|
|
303
311
|
}
|
|
@@ -329,7 +337,7 @@ impl PressableLabeledControl {
|
|
|
329
337
|
pub(crate) struct WeakPressableLabeledControl {
|
|
330
338
|
root: WeakFlexBox,
|
|
331
339
|
indicator_root: Rc<RefCell<FlexBox>>,
|
|
332
|
-
label_node:
|
|
340
|
+
label_node: TextNode,
|
|
333
341
|
gap_node: FlexBox,
|
|
334
342
|
label_host: FlexBox,
|
|
335
343
|
hovered_state: Rc<Cell<bool>>,
|
|
@@ -343,6 +351,7 @@ pub(crate) struct WeakPressableLabeledControl {
|
|
|
343
351
|
label_text_color_override: Rc<Cell<Option<u32>>>,
|
|
344
352
|
colors_value: Rc<Cell<Option<LabeledControlColors>>>,
|
|
345
353
|
activation: Rc<RefCell<Option<ActivationCallback>>>,
|
|
354
|
+
click: Rc<RefCell<Option<ClickCallback>>>,
|
|
346
355
|
state_changed: Rc<RefCell<Option<StateCallback>>>,
|
|
347
356
|
key_handler: Rc<RefCell<Option<KeyCallback>>>,
|
|
348
357
|
}
|
|
@@ -366,6 +375,7 @@ impl WeakPressableLabeledControl {
|
|
|
366
375
|
label_text_color_override: self.label_text_color_override.clone(),
|
|
367
376
|
colors_value: self.colors_value.clone(),
|
|
368
377
|
activation: self.activation.clone(),
|
|
378
|
+
click: self.click.clone(),
|
|
369
379
|
state_changed: self.state_changed.clone(),
|
|
370
380
|
key_handler: self.key_handler.clone(),
|
|
371
381
|
})
|
|
@@ -375,7 +385,7 @@ impl WeakPressableLabeledControl {
|
|
|
375
385
|
#[allow(clippy::too_many_arguments)]
|
|
376
386
|
fn sync_base_theme_parts(
|
|
377
387
|
root: &FlexBox,
|
|
378
|
-
label_node: &
|
|
388
|
+
label_node: &TextNode,
|
|
379
389
|
gap_node: &FlexBox,
|
|
380
390
|
label_font_size_override: f32,
|
|
381
391
|
label_font_family_override: Option<crate::FontFamily>,
|
|
@@ -435,7 +445,7 @@ fn is_space_key(event: &KeyEventArgs) -> bool {
|
|
|
435
445
|
#[derive(Clone)]
|
|
436
446
|
struct PressableLabeledControlEventTarget {
|
|
437
447
|
weak_root: WeakFlexBox,
|
|
438
|
-
label_node:
|
|
448
|
+
label_node: TextNode,
|
|
439
449
|
gap_node: FlexBox,
|
|
440
450
|
hovered_state: Rc<Cell<bool>>,
|
|
441
451
|
pressed_state: Rc<Cell<bool>>,
|
|
@@ -448,6 +458,7 @@ struct PressableLabeledControlEventTarget {
|
|
|
448
458
|
label_text_color_override: Rc<Cell<Option<u32>>>,
|
|
449
459
|
colors_value: Rc<Cell<Option<LabeledControlColors>>>,
|
|
450
460
|
activation: Rc<RefCell<Option<ActivationCallback>>>,
|
|
461
|
+
click: Rc<RefCell<Option<ClickCallback>>>,
|
|
451
462
|
state_changed: Rc<RefCell<Option<StateCallback>>>,
|
|
452
463
|
key_handler: Rc<RefCell<Option<KeyCallback>>>,
|
|
453
464
|
}
|
|
@@ -489,6 +500,9 @@ impl PressableLabeledControlEventTarget {
|
|
|
489
500
|
if let Some(callback) = self.activation.borrow().clone() {
|
|
490
501
|
callback(self.snapshot_state());
|
|
491
502
|
}
|
|
503
|
+
if let Some(callback) = self.click.borrow().clone() {
|
|
504
|
+
callback(ClickEventArgs);
|
|
505
|
+
}
|
|
492
506
|
}
|
|
493
507
|
|
|
494
508
|
fn clear_pointer_state(&self) {
|
|
@@ -7,8 +7,8 @@ use crate::controls::{DropdownColors, DropdownSizing};
|
|
|
7
7
|
use crate::ffi::{CursorStyle, FlexDirection, HandleValue, PositionType, SemanticRole, Unit};
|
|
8
8
|
use crate::logger;
|
|
9
9
|
use crate::node::{
|
|
10
|
-
flex_box, portal, scroll_box, FlexBox,
|
|
11
|
-
ScrollBox,
|
|
10
|
+
flex_box, portal, scroll_box, ChildContainerSurface, FlexBox, LayoutSurface, Node, NodeHandle,
|
|
11
|
+
ScrollBarVisibility, ScrollBox,
|
|
12
12
|
};
|
|
13
13
|
use crate::popup_presenter::PopupPresenter;
|
|
14
14
|
use crate::theme::current_theme;
|