@effindomv2/fui-rs 0.1.8 → 0.1.10
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/package.json +1 -1
- package/src/bridge_callbacks.rs +1 -0
- package/src/controls/appearance.rs +200 -0
- package/src/controls/button.rs +48 -122
- package/src/controls/checkbox.rs +27 -3
- package/src/controls/combobox.rs +61 -23
- package/src/controls/context_menu.rs +156 -256
- package/src/controls/control_template_set.rs +2 -3
- package/src/controls/control_tokens.rs +76 -0
- package/src/controls/dialog.rs +80 -78
- package/src/controls/dropdown.rs +46 -5
- package/src/controls/form.rs +6 -0
- package/src/controls/internal/button_presenter.rs +21 -20
- package/src/controls/internal/pressable_labeled_control.rs +11 -11
- package/src/controls/internal/text_input_core.rs +40 -22
- package/src/controls/internal/text_input_presenter.rs +29 -23
- package/src/controls/mod.rs +7 -2
- package/src/controls/nav_link.rs +25 -19
- package/src/controls/popup.rs +24 -40
- package/src/controls/progress_bar.rs +80 -109
- package/src/controls/radio_button.rs +27 -3
- package/src/controls/radio_group.rs +6 -0
- package/src/controls/slider.rs +38 -14
- package/src/controls/switch.rs +27 -3
- package/src/controls/tests.rs +796 -56
- package/src/controls/text_area.rs +12 -2
- package/src/controls/text_input.rs +19 -3
- package/src/lib.rs +44 -38
- package/src/node/core.rs +5 -0
- package/src/node/flex_box.rs +248 -2
- package/src/node/grid.rs +5 -0
- package/src/node/mod.rs +48 -0
- package/src/node/presenter_host_style.rs +177 -0
- package/src/node/scroll_view.rs +3 -0
- package/src/node/text_node.rs +42 -0
- package/src/popup_presenter.rs +32 -0
package/src/node/mod.rs
CHANGED
|
@@ -24,6 +24,7 @@ mod flex_box;
|
|
|
24
24
|
mod grid;
|
|
25
25
|
mod helpers;
|
|
26
26
|
mod image;
|
|
27
|
+
mod presenter_host_style;
|
|
27
28
|
mod scroll_bar;
|
|
28
29
|
mod scroll_box;
|
|
29
30
|
mod scroll_state;
|
|
@@ -45,6 +46,8 @@ pub use helpers::{
|
|
|
45
46
|
scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Length,
|
|
46
47
|
};
|
|
47
48
|
pub use image::ImageNode;
|
|
49
|
+
pub(crate) use presenter_host_style::HostStyleLayers;
|
|
50
|
+
pub use presenter_host_style::{Corners, EdgeInsets, PresenterHostStyle, Shadow};
|
|
48
51
|
pub use scroll_bar::{ScrollBar, ScrollBarVisibility};
|
|
49
52
|
pub use scroll_box::ScrollBox;
|
|
50
53
|
pub use scroll_state::ScrollState;
|
|
@@ -170,6 +173,11 @@ pub trait FlexBoxSurface: HasFlexBoxRoot {
|
|
|
170
173
|
self
|
|
171
174
|
}
|
|
172
175
|
|
|
176
|
+
fn clear_padding(&self) -> &Self {
|
|
177
|
+
self.flex_box_root().clear_padding();
|
|
178
|
+
self
|
|
179
|
+
}
|
|
180
|
+
|
|
173
181
|
fn margin(&self, left: f32, top: f32, right: f32, bottom: f32) -> &Self {
|
|
174
182
|
self.flex_box_root().margin(left, top, right, bottom);
|
|
175
183
|
self
|
|
@@ -180,6 +188,11 @@ pub trait FlexBoxSurface: HasFlexBoxRoot {
|
|
|
180
188
|
self
|
|
181
189
|
}
|
|
182
190
|
|
|
191
|
+
fn clear_corners(&self) -> &Self {
|
|
192
|
+
self.flex_box_root().clear_corners();
|
|
193
|
+
self
|
|
194
|
+
}
|
|
195
|
+
|
|
183
196
|
fn corners(&self, tl: f32, tr: f32, br: f32, bl: f32) -> &Self {
|
|
184
197
|
self.flex_box_root().corners(tl, tr, br, bl);
|
|
185
198
|
self
|
|
@@ -195,16 +208,31 @@ pub trait FlexBoxSurface: HasFlexBoxRoot {
|
|
|
195
208
|
self
|
|
196
209
|
}
|
|
197
210
|
|
|
211
|
+
fn clear_border(&self) -> &Self {
|
|
212
|
+
self.flex_box_root().clear_border();
|
|
213
|
+
self
|
|
214
|
+
}
|
|
215
|
+
|
|
198
216
|
fn bg_color(&self, color: u32) -> &Self {
|
|
199
217
|
self.flex_box_root().bg_color(color);
|
|
200
218
|
self
|
|
201
219
|
}
|
|
202
220
|
|
|
221
|
+
fn clear_bg_color(&self) -> &Self {
|
|
222
|
+
self.flex_box_root().clear_bg_color();
|
|
223
|
+
self
|
|
224
|
+
}
|
|
225
|
+
|
|
203
226
|
fn opacity(&self, value: f32) -> &Self {
|
|
204
227
|
self.flex_box_root().opacity(value);
|
|
205
228
|
self
|
|
206
229
|
}
|
|
207
230
|
|
|
231
|
+
fn clear_opacity(&self) -> &Self {
|
|
232
|
+
self.flex_box_root().clear_opacity();
|
|
233
|
+
self
|
|
234
|
+
}
|
|
235
|
+
|
|
208
236
|
fn blur(&self, sigma: f32) -> &Self {
|
|
209
237
|
self.flex_box_root().blur(sigma);
|
|
210
238
|
self
|
|
@@ -223,6 +251,11 @@ pub trait FlexBoxSurface: HasFlexBoxRoot {
|
|
|
223
251
|
self
|
|
224
252
|
}
|
|
225
253
|
|
|
254
|
+
fn clear_drop_shadow(&self) -> &Self {
|
|
255
|
+
self.flex_box_root().clear_drop_shadow();
|
|
256
|
+
self
|
|
257
|
+
}
|
|
258
|
+
|
|
226
259
|
fn background_blur(&self, sigma: f32) -> &Self {
|
|
227
260
|
self.flex_box_root().background_blur(sigma);
|
|
228
261
|
self
|
|
@@ -270,11 +303,21 @@ pub trait FlexBoxSurface: HasFlexBoxRoot {
|
|
|
270
303
|
self
|
|
271
304
|
}
|
|
272
305
|
|
|
306
|
+
fn clear_justify_content(&self) -> &Self {
|
|
307
|
+
self.flex_box_root().clear_justify_content();
|
|
308
|
+
self
|
|
309
|
+
}
|
|
310
|
+
|
|
273
311
|
fn align_items(&self, align: AlignItems) -> &Self {
|
|
274
312
|
self.flex_box_root().align_items(align);
|
|
275
313
|
self
|
|
276
314
|
}
|
|
277
315
|
|
|
316
|
+
fn clear_align_items(&self) -> &Self {
|
|
317
|
+
self.flex_box_root().clear_align_items();
|
|
318
|
+
self
|
|
319
|
+
}
|
|
320
|
+
|
|
278
321
|
fn align_self(&self, align: AlignSelf) -> &Self {
|
|
279
322
|
self.flex_box_root().align_self(align);
|
|
280
323
|
self
|
|
@@ -305,6 +348,11 @@ pub trait FlexBoxSurface: HasFlexBoxRoot {
|
|
|
305
348
|
self
|
|
306
349
|
}
|
|
307
350
|
|
|
351
|
+
fn clear_cursor(&self) -> &Self {
|
|
352
|
+
self.flex_box_root().clear_cursor();
|
|
353
|
+
self
|
|
354
|
+
}
|
|
355
|
+
|
|
308
356
|
fn visibility(&self, visibility: Visibility) -> &Self {
|
|
309
357
|
self.flex_box_root().visibility(visibility);
|
|
310
358
|
self
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
use crate::ffi::{AlignItems, CursorStyle, FlexDirection, JustifyContent};
|
|
2
|
+
use crate::node::Border;
|
|
3
|
+
|
|
4
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
5
|
+
pub struct EdgeInsets {
|
|
6
|
+
pub left: f32,
|
|
7
|
+
pub top: f32,
|
|
8
|
+
pub right: f32,
|
|
9
|
+
pub bottom: f32,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
impl EdgeInsets {
|
|
13
|
+
pub const fn new(left: f32, top: f32, right: f32, bottom: f32) -> Self {
|
|
14
|
+
Self {
|
|
15
|
+
left,
|
|
16
|
+
top,
|
|
17
|
+
right,
|
|
18
|
+
bottom,
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
pub const fn all(value: f32) -> Self {
|
|
23
|
+
Self::new(value, value, value, value)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
28
|
+
pub struct Corners {
|
|
29
|
+
pub top_left: f32,
|
|
30
|
+
pub top_right: f32,
|
|
31
|
+
pub bottom_right: f32,
|
|
32
|
+
pub bottom_left: f32,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
impl Corners {
|
|
36
|
+
pub const fn new(top_left: f32, top_right: f32, bottom_right: f32, bottom_left: f32) -> Self {
|
|
37
|
+
Self {
|
|
38
|
+
top_left,
|
|
39
|
+
top_right,
|
|
40
|
+
bottom_right,
|
|
41
|
+
bottom_left,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub const fn all(value: f32) -> Self {
|
|
46
|
+
Self::new(value, value, value, value)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
51
|
+
pub struct Shadow {
|
|
52
|
+
pub color: u32,
|
|
53
|
+
pub offset_x: f32,
|
|
54
|
+
pub offset_y: f32,
|
|
55
|
+
pub blur_sigma: f32,
|
|
56
|
+
pub spread: f32,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
impl Shadow {
|
|
60
|
+
pub fn new(color: u32, offset_x: f32, offset_y: f32, blur_sigma: f32, spread: f32) -> Self {
|
|
61
|
+
Self {
|
|
62
|
+
color,
|
|
63
|
+
offset_x,
|
|
64
|
+
offset_y,
|
|
65
|
+
blur_sigma: blur_sigma.max(0.0),
|
|
66
|
+
spread,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
|
72
|
+
pub struct PresenterHostStyle {
|
|
73
|
+
pub flex_direction: Option<FlexDirection>,
|
|
74
|
+
pub justify_content: Option<JustifyContent>,
|
|
75
|
+
pub align_items: Option<AlignItems>,
|
|
76
|
+
pub background: Option<u32>,
|
|
77
|
+
pub padding: Option<EdgeInsets>,
|
|
78
|
+
pub corners: Option<Corners>,
|
|
79
|
+
pub border: Option<Border>,
|
|
80
|
+
pub shadow: Option<Shadow>,
|
|
81
|
+
pub cursor: Option<CursorStyle>,
|
|
82
|
+
pub opacity: Option<f32>,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
impl PresenterHostStyle {
|
|
86
|
+
pub const fn new() -> Self {
|
|
87
|
+
Self {
|
|
88
|
+
flex_direction: None,
|
|
89
|
+
justify_content: None,
|
|
90
|
+
align_items: None,
|
|
91
|
+
background: None,
|
|
92
|
+
padding: None,
|
|
93
|
+
corners: None,
|
|
94
|
+
border: None,
|
|
95
|
+
shadow: None,
|
|
96
|
+
cursor: None,
|
|
97
|
+
opacity: None,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub fn flex_direction(mut self, value: FlexDirection) -> Self {
|
|
102
|
+
self.flex_direction = Some(value);
|
|
103
|
+
self
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
pub fn justify_content(mut self, value: JustifyContent) -> Self {
|
|
107
|
+
self.justify_content = Some(value);
|
|
108
|
+
self
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pub fn align_items(mut self, value: AlignItems) -> Self {
|
|
112
|
+
self.align_items = Some(value);
|
|
113
|
+
self
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
pub fn background(mut self, value: u32) -> Self {
|
|
117
|
+
self.background = Some(value);
|
|
118
|
+
self
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pub fn padding(mut self, value: EdgeInsets) -> Self {
|
|
122
|
+
self.padding = Some(value);
|
|
123
|
+
self
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub fn corners(mut self, value: Corners) -> Self {
|
|
127
|
+
self.corners = Some(value);
|
|
128
|
+
self
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
pub fn border(mut self, value: Border) -> Self {
|
|
132
|
+
self.border = Some(value);
|
|
133
|
+
self
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
pub fn shadow(mut self, value: Shadow) -> Self {
|
|
137
|
+
self.shadow = Some(value);
|
|
138
|
+
self
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
pub fn cursor(mut self, value: CursorStyle) -> Self {
|
|
142
|
+
self.cursor = Some(value);
|
|
143
|
+
self
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
pub fn opacity(mut self, value: f32) -> Self {
|
|
147
|
+
self.opacity = Some(value.clamp(0.0, 1.0));
|
|
148
|
+
self
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
pub(crate) fn overlay(self, fallback: Self) -> Self {
|
|
152
|
+
Self {
|
|
153
|
+
flex_direction: self.flex_direction.or(fallback.flex_direction),
|
|
154
|
+
justify_content: self.justify_content.or(fallback.justify_content),
|
|
155
|
+
align_items: self.align_items.or(fallback.align_items),
|
|
156
|
+
background: self.background.or(fallback.background),
|
|
157
|
+
padding: self.padding.or(fallback.padding),
|
|
158
|
+
corners: self.corners.or(fallback.corners),
|
|
159
|
+
border: self.border.or(fallback.border),
|
|
160
|
+
shadow: self.shadow.or(fallback.shadow),
|
|
161
|
+
cursor: self.cursor.or(fallback.cursor),
|
|
162
|
+
opacity: self.opacity.or(fallback.opacity),
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#[derive(Clone, Copy, Debug, Default)]
|
|
168
|
+
pub(crate) struct HostStyleLayers {
|
|
169
|
+
pub local: PresenterHostStyle,
|
|
170
|
+
pub presenter: PresenterHostStyle,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
impl HostStyleLayers {
|
|
174
|
+
pub fn resolved(self) -> PresenterHostStyle {
|
|
175
|
+
self.local.overlay(self.presenter)
|
|
176
|
+
}
|
|
177
|
+
}
|
package/src/node/scroll_view.rs
CHANGED
|
@@ -249,6 +249,9 @@ impl ScrollView {
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
pub fn focusable(&self, enabled: bool, tab_index: i32) -> &Self {
|
|
252
|
+
if enabled {
|
|
253
|
+
self.retained_node_ref().require_interactive();
|
|
254
|
+
}
|
|
252
255
|
let mut core = self.core.borrow_mut();
|
|
253
256
|
core.behavior.focusable = Some((enabled, tab_index));
|
|
254
257
|
let interactive = core.behavior.enabled && core.behavior.inherited_enabled;
|
package/src/node/text_node.rs
CHANGED
|
@@ -177,6 +177,10 @@ impl TextNode {
|
|
|
177
177
|
self
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
pub(crate) fn configured_text_color(&self) -> Option<u32> {
|
|
181
|
+
self.props.borrow().text_color
|
|
182
|
+
}
|
|
183
|
+
|
|
180
184
|
pub fn style_runs(&self, words: Vec<u32>) -> &Self {
|
|
181
185
|
{
|
|
182
186
|
let mut props = self.props.borrow_mut();
|
|
@@ -418,6 +422,9 @@ impl TextNode {
|
|
|
418
422
|
}
|
|
419
423
|
|
|
420
424
|
pub fn focusable(&self, enabled: bool, tab_index: i32) -> &Self {
|
|
425
|
+
if enabled {
|
|
426
|
+
self.retained_node_ref().require_interactive();
|
|
427
|
+
}
|
|
421
428
|
let mut core = self.core.borrow_mut();
|
|
422
429
|
core.behavior.focusable = Some((enabled, tab_index));
|
|
423
430
|
let interactive = core.behavior.enabled && core.behavior.inherited_enabled;
|
|
@@ -648,6 +655,9 @@ impl Node for TextNode {
|
|
|
648
655
|
}
|
|
649
656
|
|
|
650
657
|
fn build_self(&self) {
|
|
658
|
+
if self.props.borrow().has_font {
|
|
659
|
+
self.resolve_font_id();
|
|
660
|
+
}
|
|
651
661
|
apply_text_props(
|
|
652
662
|
self.handle(),
|
|
653
663
|
&self.props.borrow(),
|
|
@@ -655,3 +665,35 @@ impl Node for TextNode {
|
|
|
655
665
|
);
|
|
656
666
|
}
|
|
657
667
|
}
|
|
668
|
+
|
|
669
|
+
#[cfg(test)]
|
|
670
|
+
mod tests {
|
|
671
|
+
use super::*;
|
|
672
|
+
use crate::ffi::{self, Call};
|
|
673
|
+
use crate::Application;
|
|
674
|
+
|
|
675
|
+
#[test]
|
|
676
|
+
fn prebuild_font_family_weight_and_style_are_resolved_during_build() {
|
|
677
|
+
ffi::test::reset();
|
|
678
|
+
let theme = theme::current_theme();
|
|
679
|
+
let label = TextCore::new("Bold before build");
|
|
680
|
+
label
|
|
681
|
+
.font_family(theme.fonts.body_family)
|
|
682
|
+
.font_weight(FontWeight::Bold)
|
|
683
|
+
.font_style(FontStyle::Normal)
|
|
684
|
+
.font_size(17.0);
|
|
685
|
+
|
|
686
|
+
Application::mount(label.clone());
|
|
687
|
+
let handle = label.handle().raw();
|
|
688
|
+
let calls = ffi::test::take_calls();
|
|
689
|
+
assert!(calls.iter().any(|call| matches!(
|
|
690
|
+
call,
|
|
691
|
+
Call::SetFont {
|
|
692
|
+
handle: call_handle,
|
|
693
|
+
font_id: 2,
|
|
694
|
+
size,
|
|
695
|
+
} if *call_handle == handle && (*size - 17.0).abs() < f32::EPSILON
|
|
696
|
+
)));
|
|
697
|
+
Application::unmount();
|
|
698
|
+
}
|
|
699
|
+
}
|
package/src/popup_presenter.rs
CHANGED
|
@@ -322,6 +322,38 @@ impl PopupPresenter {
|
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
impl PopupPresenterEventTarget {
|
|
325
|
+
pub(crate) fn is_open(&self) -> bool {
|
|
326
|
+
self.state.borrow().open
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
pub(crate) fn surface_x(&self) -> f32 {
|
|
330
|
+
self.state.borrow().surface_x
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
pub(crate) fn surface_y(&self) -> f32 {
|
|
334
|
+
self.state.borrow().surface_y
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
pub(crate) fn backdrop_color(&self, color: u32) {
|
|
338
|
+
self.state.borrow_mut().backdrop_color = color;
|
|
339
|
+
self.apply_backdrop_style();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
pub(crate) fn background_blur(&self, sigma: f32) {
|
|
343
|
+
self.state.borrow_mut().background_blur_sigma = sigma.max(0.0);
|
|
344
|
+
self.apply_backdrop_style();
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
fn apply_backdrop_style(&self) {
|
|
348
|
+
let Some(overlay) = self.overlay_node.upgrade() else {
|
|
349
|
+
return;
|
|
350
|
+
};
|
|
351
|
+
let state = *self.state.borrow();
|
|
352
|
+
overlay
|
|
353
|
+
.bg_color(state.backdrop_color)
|
|
354
|
+
.background_blur(state.background_blur_sigma);
|
|
355
|
+
}
|
|
356
|
+
|
|
325
357
|
pub(crate) fn hide(&self) {
|
|
326
358
|
let Some(root) = self.root.upgrade() else {
|
|
327
359
|
return;
|