@effindomv2/fui-rs 0.1.7 → 0.1.9
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 +15 -11
- 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 +2 -0
- package/src/node/flex_box.rs +245 -2
- package/src/node/grid.rs +5 -0
- package/src/node/helpers.rs +6 -3
- package/src/node/mod.rs +48 -0
- package/src/node/presenter_host_style.rs +177 -0
- package/src/node/text_node.rs +35 -0
- package/src/popup_presenter.rs +32 -0
|
@@ -87,6 +87,44 @@ impl SliderSizing {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
|
91
|
+
pub struct ProgressBarSizing {
|
|
92
|
+
length: f32,
|
|
93
|
+
thickness: f32,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
impl ProgressBarSizing {
|
|
97
|
+
pub fn new() -> Self {
|
|
98
|
+
Self::default()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub fn length(mut self, value: f32) -> Self {
|
|
102
|
+
self.length = sanitize_positive("ProgressBarSizing", "length", value);
|
|
103
|
+
self
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
pub fn thickness(mut self, value: f32) -> Self {
|
|
107
|
+
self.thickness = sanitize_positive("ProgressBarSizing", "thickness", value);
|
|
108
|
+
self
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pub fn has_length(&self) -> bool {
|
|
112
|
+
self.length > 0.0
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
pub fn has_thickness(&self) -> bool {
|
|
116
|
+
self.thickness > 0.0
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
pub fn length_px(&self) -> f32 {
|
|
120
|
+
self.length
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
pub fn thickness_px(&self) -> f32 {
|
|
124
|
+
self.thickness
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
90
128
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
|
91
129
|
pub struct DropdownSizing {
|
|
92
130
|
field_font_size: f32,
|
|
@@ -407,6 +445,44 @@ impl SliderColors {
|
|
|
407
445
|
}
|
|
408
446
|
}
|
|
409
447
|
|
|
448
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
449
|
+
pub struct ProgressBarColors {
|
|
450
|
+
track: Option<u32>,
|
|
451
|
+
fill: Option<u32>,
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
impl ProgressBarColors {
|
|
455
|
+
pub fn new() -> Self {
|
|
456
|
+
Self::default()
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
pub fn track(mut self, color: u32) -> Self {
|
|
460
|
+
self.track = Some(color);
|
|
461
|
+
self
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
pub fn fill(mut self, color: u32) -> Self {
|
|
465
|
+
self.fill = Some(color);
|
|
466
|
+
self
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
pub fn has_track(&self) -> bool {
|
|
470
|
+
self.track.is_some()
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
pub fn track_color(&self) -> u32 {
|
|
474
|
+
self.track.unwrap_or(0)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
pub fn has_fill(&self) -> bool {
|
|
478
|
+
self.fill.is_some()
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
pub fn fill_color(&self) -> u32 {
|
|
482
|
+
self.fill.unwrap_or(0)
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
410
486
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
411
487
|
pub struct DropdownColors {
|
|
412
488
|
pub(crate) background: Option<u32>,
|
package/src/controls/dialog.rs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use super::DialogAppearance;
|
|
1
2
|
use super::{Button, Form};
|
|
2
3
|
use crate::app;
|
|
3
4
|
use crate::bindings::ui;
|
|
@@ -5,7 +6,6 @@ use crate::ffi::{
|
|
|
5
6
|
AlignItems, BorderStyle, FlexDirection, JustifyContent, PositionType, SemanticRole, Unit,
|
|
6
7
|
};
|
|
7
8
|
use crate::node::{flex_box, portal, Border, FlexBox, Node, NodeRef, TextNode, WeakFlexBox};
|
|
8
|
-
use crate::signal::SubscriptionGuard;
|
|
9
9
|
use crate::theme::{current_theme, subscribe, Theme};
|
|
10
10
|
use std::cell::RefCell;
|
|
11
11
|
use std::rc::Rc;
|
|
@@ -40,7 +40,6 @@ pub struct Dialog {
|
|
|
40
40
|
card: FlexBox,
|
|
41
41
|
overlay: FlexBox,
|
|
42
42
|
state: Rc<RefCell<DialogState>>,
|
|
43
|
-
theme_guard: Rc<RefCell<Option<SubscriptionGuard>>>,
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
#[derive(Clone)]
|
|
@@ -69,7 +68,12 @@ struct DialogState {
|
|
|
69
68
|
card_border_width_value: f32,
|
|
70
69
|
card_border_color_value: u32,
|
|
71
70
|
card_border_style_value: BorderStyle,
|
|
72
|
-
|
|
71
|
+
card_border_dash_on_value: f32,
|
|
72
|
+
card_border_dash_off_value: f32,
|
|
73
|
+
card_corner_top_left_value: f32,
|
|
74
|
+
card_corner_top_right_value: f32,
|
|
75
|
+
card_corner_bottom_right_value: f32,
|
|
76
|
+
card_corner_bottom_left_value: f32,
|
|
73
77
|
backdrop_color_overridden: bool,
|
|
74
78
|
shadow_overridden: bool,
|
|
75
79
|
card_background_overridden: bool,
|
|
@@ -96,7 +100,12 @@ impl DialogState {
|
|
|
96
100
|
card_border_width_value: 1.0,
|
|
97
101
|
card_border_color_value: theme.colors.border,
|
|
98
102
|
card_border_style_value: BorderStyle::Solid,
|
|
99
|
-
|
|
103
|
+
card_border_dash_on_value: 0.0,
|
|
104
|
+
card_border_dash_off_value: 0.0,
|
|
105
|
+
card_corner_top_left_value: theme.spacing.md,
|
|
106
|
+
card_corner_top_right_value: theme.spacing.md,
|
|
107
|
+
card_corner_bottom_right_value: theme.spacing.md,
|
|
108
|
+
card_corner_bottom_left_value: theme.spacing.md,
|
|
100
109
|
backdrop_color_overridden: false,
|
|
101
110
|
shadow_overridden: false,
|
|
102
111
|
card_background_overridden: false,
|
|
@@ -184,7 +193,6 @@ impl Dialog {
|
|
|
184
193
|
.align_items(AlignItems::Center)
|
|
185
194
|
.child(&card);
|
|
186
195
|
let state = Rc::new(RefCell::new(DialogState::from_theme(theme)));
|
|
187
|
-
let theme_guard = Rc::new(RefCell::new(None));
|
|
188
196
|
|
|
189
197
|
root.position_type(PositionType::Absolute)
|
|
190
198
|
.position(0.0, 0.0)
|
|
@@ -203,7 +211,6 @@ impl Dialog {
|
|
|
203
211
|
card,
|
|
204
212
|
overlay,
|
|
205
213
|
state,
|
|
206
|
-
theme_guard,
|
|
207
214
|
};
|
|
208
215
|
dialog.content(title, body);
|
|
209
216
|
dialog.bind_events();
|
|
@@ -265,79 +272,51 @@ impl Dialog {
|
|
|
265
272
|
self.cancel_button.clone()
|
|
266
273
|
}
|
|
267
274
|
|
|
268
|
-
pub fn
|
|
275
|
+
pub fn appearance(&self, appearance: DialogAppearance) -> &Self {
|
|
269
276
|
let mut state = self.state.borrow_mut();
|
|
270
|
-
|
|
271
|
-
state.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
pub fn background_blur(&self, sigma: f32) -> &Self {
|
|
278
|
-
self.state.borrow_mut().dialog_background_blur_sigma_value = sigma.max(0.0);
|
|
279
|
-
self.apply_theme();
|
|
280
|
-
self
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
pub fn card_shadow(
|
|
284
|
-
&self,
|
|
285
|
-
color: u32,
|
|
286
|
-
offset_x: f32,
|
|
287
|
-
offset_y: f32,
|
|
288
|
-
blur_sigma: f32,
|
|
289
|
-
spread: f32,
|
|
290
|
-
) -> &Self {
|
|
291
|
-
let mut state = self.state.borrow_mut();
|
|
292
|
-
state.shadow_overridden = true;
|
|
293
|
-
state.shadow_color_value = color;
|
|
294
|
-
state.shadow_offset_x_value = offset_x;
|
|
295
|
-
state.shadow_offset_y_value = offset_y;
|
|
296
|
-
state.shadow_blur_sigma_value = blur_sigma;
|
|
297
|
-
state.shadow_spread_value = spread;
|
|
298
|
-
drop(state);
|
|
299
|
-
self.apply_theme();
|
|
300
|
-
self
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
pub fn card_color(&self, color: u32) -> &Self {
|
|
304
|
-
let mut state = self.state.borrow_mut();
|
|
305
|
-
state.card_background_overridden = true;
|
|
306
|
-
state.card_background_color_value = color;
|
|
307
|
-
drop(state);
|
|
308
|
-
self.apply_theme();
|
|
309
|
-
self
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
pub fn card_border(&self, width: f32, color: u32) -> &Self {
|
|
313
|
-
let mut state = self.state.borrow_mut();
|
|
314
|
-
state.card_border_overridden = true;
|
|
315
|
-
state.card_border_width_value = width;
|
|
316
|
-
state.card_border_color_value = color;
|
|
317
|
-
state.card_border_style_value = BorderStyle::Solid;
|
|
318
|
-
drop(state);
|
|
319
|
-
self.apply_theme();
|
|
320
|
-
self
|
|
321
|
-
}
|
|
277
|
+
let backdrop = appearance.backdrop.unwrap_or_default();
|
|
278
|
+
state.backdrop_color_overridden = backdrop.color.is_some();
|
|
279
|
+
if let Some(color) = backdrop.color {
|
|
280
|
+
state.backdrop_color_value = color;
|
|
281
|
+
}
|
|
282
|
+
state.dialog_background_blur_sigma_value = backdrop.blur.unwrap_or(DIALOG_BACKGROUND_BLUR);
|
|
322
283
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
state.
|
|
284
|
+
let card = appearance.card.unwrap_or_default();
|
|
285
|
+
state.card_background_overridden = card.background.is_some();
|
|
286
|
+
if let Some(color) = card.background {
|
|
287
|
+
state.card_background_color_value = color;
|
|
288
|
+
}
|
|
289
|
+
state.card_border_overridden = card.border.is_some();
|
|
290
|
+
if let Some(border) = card.border {
|
|
291
|
+
state.card_border_width_value = border.width;
|
|
292
|
+
state.card_border_color_value = border.color;
|
|
293
|
+
state.card_border_style_value = border.style;
|
|
294
|
+
state.card_border_dash_on_value = border.dash_on;
|
|
295
|
+
state.card_border_dash_off_value = border.dash_off;
|
|
296
|
+
}
|
|
297
|
+
state.card_corner_radius_overridden = card.corners.is_some();
|
|
298
|
+
if let Some(corners) = card.corners {
|
|
299
|
+
state.card_corner_top_left_value = corners.top_left;
|
|
300
|
+
state.card_corner_top_right_value = corners.top_right;
|
|
301
|
+
state.card_corner_bottom_right_value = corners.bottom_right;
|
|
302
|
+
state.card_corner_bottom_left_value = corners.bottom_left;
|
|
303
|
+
}
|
|
304
|
+
state.shadow_overridden = card.shadow.is_some();
|
|
305
|
+
if let Some(shadow) = card.shadow {
|
|
306
|
+
state.shadow_color_value = shadow.color;
|
|
307
|
+
state.shadow_offset_x_value = shadow.offset_x;
|
|
308
|
+
state.shadow_offset_y_value = shadow.offset_y;
|
|
309
|
+
state.shadow_blur_sigma_value = shadow.blur_sigma;
|
|
310
|
+
state.shadow_spread_value = shadow.spread;
|
|
311
|
+
}
|
|
329
312
|
drop(state);
|
|
313
|
+
self.event_target().handle_theme_changed(current_theme());
|
|
330
314
|
self.apply_theme();
|
|
331
315
|
self
|
|
332
316
|
}
|
|
333
317
|
|
|
334
|
-
pub fn
|
|
335
|
-
|
|
336
|
-
state.card_corner_radius_overridden = true;
|
|
337
|
-
state.card_corner_radius_value = radius;
|
|
338
|
-
drop(state);
|
|
339
|
-
self.apply_theme();
|
|
340
|
-
self
|
|
318
|
+
pub fn clear_appearance(&self) -> &Self {
|
|
319
|
+
self.appearance(DialogAppearance::new())
|
|
341
320
|
}
|
|
342
321
|
|
|
343
322
|
pub fn content(&self, title: impl Into<String>, body: impl Into<String>) -> &Self {
|
|
@@ -401,10 +380,13 @@ impl Dialog {
|
|
|
401
380
|
let event_target = self.event_target();
|
|
402
381
|
let title = self.title_node.clone();
|
|
403
382
|
let body = self.body_node.clone();
|
|
404
|
-
|
|
383
|
+
let guard = subscribe(move |theme| {
|
|
405
384
|
event_target.handle_theme_changed(theme);
|
|
406
385
|
event_target.apply_theme(&title, &body);
|
|
407
|
-
})
|
|
386
|
+
});
|
|
387
|
+
self.root
|
|
388
|
+
.retained_node_ref()
|
|
389
|
+
.retain_attachment(Rc::new(guard));
|
|
408
390
|
}
|
|
409
391
|
|
|
410
392
|
fn apply_theme(&self) {
|
|
@@ -428,6 +410,10 @@ impl Node for Dialog {
|
|
|
428
410
|
self.root.retained_node_ref()
|
|
429
411
|
}
|
|
430
412
|
|
|
413
|
+
fn retained_owner_attachment(&self) -> Option<Rc<dyn std::any::Any>> {
|
|
414
|
+
Some(Rc::new(self.clone()))
|
|
415
|
+
}
|
|
416
|
+
|
|
431
417
|
fn build_self(&self) {
|
|
432
418
|
self.apply_theme();
|
|
433
419
|
self.root.build_self();
|
|
@@ -442,6 +428,12 @@ impl Node for Dialog {
|
|
|
442
428
|
}
|
|
443
429
|
}
|
|
444
430
|
|
|
431
|
+
impl crate::node::HasFlexBoxRoot for Dialog {
|
|
432
|
+
fn flex_box_root(&self) -> &FlexBox {
|
|
433
|
+
&self.root
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
445
437
|
impl DialogEventTarget {
|
|
446
438
|
fn hide(&self) {
|
|
447
439
|
let Some(root) = self.root.upgrade() else {
|
|
@@ -524,9 +516,14 @@ impl DialogEventTarget {
|
|
|
524
516
|
state.card_border_width_value = 1.0;
|
|
525
517
|
state.card_border_color_value = theme.colors.border;
|
|
526
518
|
state.card_border_style_value = BorderStyle::Solid;
|
|
519
|
+
state.card_border_dash_on_value = 0.0;
|
|
520
|
+
state.card_border_dash_off_value = 0.0;
|
|
527
521
|
}
|
|
528
522
|
if !state.card_corner_radius_overridden {
|
|
529
|
-
state.
|
|
523
|
+
state.card_corner_top_left_value = theme.spacing.md;
|
|
524
|
+
state.card_corner_top_right_value = theme.spacing.md;
|
|
525
|
+
state.card_corner_bottom_right_value = theme.spacing.md;
|
|
526
|
+
state.card_corner_bottom_left_value = theme.spacing.md;
|
|
530
527
|
}
|
|
531
528
|
}
|
|
532
529
|
|
|
@@ -540,13 +537,18 @@ impl DialogEventTarget {
|
|
|
540
537
|
}
|
|
541
538
|
if let Some(card) = self.card.upgrade() {
|
|
542
539
|
card.bg_color(state.card_background_color_value)
|
|
543
|
-
.
|
|
540
|
+
.corners(
|
|
541
|
+
state.card_corner_top_left_value,
|
|
542
|
+
state.card_corner_top_right_value,
|
|
543
|
+
state.card_corner_bottom_right_value,
|
|
544
|
+
state.card_corner_bottom_left_value,
|
|
545
|
+
)
|
|
544
546
|
.border_config(Border {
|
|
545
547
|
width: state.card_border_width_value,
|
|
546
548
|
color: state.card_border_color_value,
|
|
547
549
|
style: state.card_border_style_value,
|
|
548
|
-
dash_on:
|
|
549
|
-
dash_off:
|
|
550
|
+
dash_on: state.card_border_dash_on_value,
|
|
551
|
+
dash_off: state.card_border_dash_off_value,
|
|
550
552
|
})
|
|
551
553
|
.drop_shadow(
|
|
552
554
|
state.shadow_color_value,
|
package/src/controls/dropdown.rs
CHANGED
|
@@ -238,6 +238,7 @@ impl Dropdown {
|
|
|
238
238
|
});
|
|
239
239
|
*shared.self_weak.borrow_mut() = Rc::downgrade(&shared);
|
|
240
240
|
*shared_slot.borrow_mut() = Some(Rc::downgrade(&shared));
|
|
241
|
+
root.retained_node_ref().retain_attachment(shared.clone());
|
|
241
242
|
|
|
242
243
|
popup_list.popup_presenter.overlay_node().on_click({
|
|
243
244
|
let weak_shared = Rc::downgrade(&shared);
|
|
@@ -470,7 +471,15 @@ impl Dropdown {
|
|
|
470
471
|
self
|
|
471
472
|
}
|
|
472
473
|
|
|
473
|
-
pub fn sizing(&self, sizing:
|
|
474
|
+
pub fn sizing(&self, sizing: DropdownSizing) -> &Self {
|
|
475
|
+
self.set_sizing(Some(sizing))
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
pub fn clear_sizing(&self) -> &Self {
|
|
479
|
+
self.set_sizing(None)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
fn set_sizing(&self, sizing: Option<DropdownSizing>) -> &Self {
|
|
474
483
|
self.shared.close();
|
|
475
484
|
self.shared.sizing_value.set(sizing);
|
|
476
485
|
if self.shared.uses_default_field_presenter() {
|
|
@@ -506,14 +515,30 @@ impl Dropdown {
|
|
|
506
515
|
self
|
|
507
516
|
}
|
|
508
517
|
|
|
509
|
-
pub fn colors(&self, colors:
|
|
518
|
+
pub fn colors(&self, colors: DropdownColors) -> &Self {
|
|
519
|
+
self.set_colors(Some(colors))
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
pub fn clear_colors(&self) -> &Self {
|
|
523
|
+
self.set_colors(None)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
fn set_colors(&self, colors: Option<DropdownColors>) -> &Self {
|
|
510
527
|
self.shared.colors_value.set(colors);
|
|
511
528
|
self.shared.popup_list.colors(colors);
|
|
512
529
|
self.shared.handle_theme_changed();
|
|
513
530
|
self
|
|
514
531
|
}
|
|
515
532
|
|
|
516
|
-
pub fn field_template(&self, template:
|
|
533
|
+
pub fn field_template(&self, template: Rc<dyn DropdownFieldTemplate>) -> &Self {
|
|
534
|
+
self.set_field_template(Some(template))
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
pub fn clear_field_template(&self) -> &Self {
|
|
538
|
+
self.set_field_template(None)
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
fn set_field_template(&self, template: Option<Rc<dyn DropdownFieldTemplate>>) -> &Self {
|
|
517
542
|
self.shared.close();
|
|
518
543
|
*self.shared.field_template_value.borrow_mut() = template.clone();
|
|
519
544
|
let next_field_presenter = create_field_presenter(template, self.shared.sizing_value.get());
|
|
@@ -528,7 +553,15 @@ impl Dropdown {
|
|
|
528
553
|
self
|
|
529
554
|
}
|
|
530
555
|
|
|
531
|
-
pub fn chevron_template(&self, template:
|
|
556
|
+
pub fn chevron_template(&self, template: Rc<dyn DropdownChevronTemplate>) -> &Self {
|
|
557
|
+
self.set_chevron_template(Some(template))
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
pub fn clear_chevron_template(&self) -> &Self {
|
|
561
|
+
self.set_chevron_template(None)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
fn set_chevron_template(&self, template: Option<Rc<dyn DropdownChevronTemplate>>) -> &Self {
|
|
532
565
|
self.shared.close();
|
|
533
566
|
*self.shared.chevron_template_value.borrow_mut() = template.clone();
|
|
534
567
|
let previous_presenter = self.shared.chevron_presenter.borrow().clone();
|
|
@@ -549,7 +582,15 @@ impl Dropdown {
|
|
|
549
582
|
self
|
|
550
583
|
}
|
|
551
584
|
|
|
552
|
-
pub fn option_row_template(
|
|
585
|
+
pub fn option_row_template(&self, template: Rc<dyn DropdownOptionRowTemplate>) -> &Self {
|
|
586
|
+
self.set_option_row_template(Some(template))
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
pub fn clear_option_row_template(&self) -> &Self {
|
|
590
|
+
self.set_option_row_template(None)
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
fn set_option_row_template(
|
|
553
594
|
&self,
|
|
554
595
|
template: Option<Rc<dyn DropdownOptionRowTemplate>>,
|
|
555
596
|
) -> &Self {
|
package/src/controls/form.rs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
use crate::controls::ButtonColors;
|
|
2
2
|
use crate::ffi::{AlignItems, FlexDirection, JustifyContent};
|
|
3
|
-
use crate::node::{
|
|
3
|
+
use crate::node::{
|
|
4
|
+
flex_box, Border, Corners, EdgeInsets, FlexBox, PresenterHostStyle, Shadow, TextCore,
|
|
5
|
+
};
|
|
4
6
|
use crate::theme::Theme;
|
|
5
7
|
use crate::{FontStyle, FontWeight};
|
|
6
8
|
use std::rc::Rc;
|
|
@@ -16,13 +18,12 @@ pub struct ButtonVisualState {
|
|
|
16
18
|
pub trait ButtonPresenter {
|
|
17
19
|
fn content_root(&self) -> FlexBox;
|
|
18
20
|
fn label_node(&self) -> TextCore;
|
|
19
|
-
fn
|
|
21
|
+
fn present(
|
|
20
22
|
&self,
|
|
21
|
-
host: &FlexBox,
|
|
22
23
|
theme: Theme,
|
|
23
24
|
state: ButtonVisualState,
|
|
24
25
|
colors: Option<ButtonColors>,
|
|
25
|
-
);
|
|
26
|
+
) -> PresenterHostStyle;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
pub trait ButtonTemplate {
|
|
@@ -60,13 +61,12 @@ impl ButtonPresenter for DefaultButtonPresenter {
|
|
|
60
61
|
self.label_node.clone()
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
fn
|
|
64
|
+
fn present(
|
|
64
65
|
&self,
|
|
65
|
-
host: &FlexBox,
|
|
66
66
|
theme: Theme,
|
|
67
67
|
state: ButtonVisualState,
|
|
68
68
|
colors: Option<ButtonColors>,
|
|
69
|
-
) {
|
|
69
|
+
) -> PresenterHostStyle {
|
|
70
70
|
let background = if !state.enabled {
|
|
71
71
|
colors
|
|
72
72
|
.and_then(|colors| colors.background)
|
|
@@ -100,19 +100,6 @@ impl ButtonPresenter for DefaultButtonPresenter {
|
|
|
100
100
|
.and_then(|colors| colors.text_primary)
|
|
101
101
|
.unwrap_or(theme.colors.text_on_accent)
|
|
102
102
|
};
|
|
103
|
-
host.flex_direction(FlexDirection::Row)
|
|
104
|
-
.justify_content(JustifyContent::Center)
|
|
105
|
-
.align_items(AlignItems::Center)
|
|
106
|
-
.corner_radius(theme.spacing.sm)
|
|
107
|
-
.border(1.0, border)
|
|
108
|
-
.padding(
|
|
109
|
-
theme.spacing.md,
|
|
110
|
-
theme.spacing.sm,
|
|
111
|
-
theme.spacing.md,
|
|
112
|
-
theme.spacing.sm,
|
|
113
|
-
)
|
|
114
|
-
.drop_shadow(0x00000000, 0.0, 0.0, 0.0, 0.0)
|
|
115
|
-
.bg_color(background);
|
|
116
103
|
self.content_root
|
|
117
104
|
.flex_direction(FlexDirection::Row)
|
|
118
105
|
.align_items(AlignItems::Center)
|
|
@@ -123,6 +110,20 @@ impl ButtonPresenter for DefaultButtonPresenter {
|
|
|
123
110
|
.font_style(FontStyle::Normal)
|
|
124
111
|
.font_size(theme.fonts.size_body)
|
|
125
112
|
.text_color(text_color);
|
|
113
|
+
PresenterHostStyle::new()
|
|
114
|
+
.flex_direction(FlexDirection::Row)
|
|
115
|
+
.justify_content(JustifyContent::Center)
|
|
116
|
+
.align_items(AlignItems::Center)
|
|
117
|
+
.corners(Corners::all(theme.spacing.sm))
|
|
118
|
+
.border(Border::solid(1.0, border))
|
|
119
|
+
.padding(EdgeInsets::new(
|
|
120
|
+
theme.spacing.md,
|
|
121
|
+
theme.spacing.sm,
|
|
122
|
+
theme.spacing.md,
|
|
123
|
+
theme.spacing.sm,
|
|
124
|
+
))
|
|
125
|
+
.shadow(Shadow::new(0x00000000, 0.0, 0.0, 0.0, 0.0))
|
|
126
|
+
.background(background)
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
|
|
@@ -4,7 +4,6 @@ use crate::ffi::{
|
|
|
4
4
|
AlignItems, CursorStyle, FlexDirection, KeyEventType, PointerEventType, SemanticRole, Unit,
|
|
5
5
|
};
|
|
6
6
|
use crate::node::{flex_box, FlexBox, Node, TextCore, WeakFlexBox};
|
|
7
|
-
use crate::signal::SubscriptionGuard;
|
|
8
7
|
use crate::theme::{current_theme, subscribe};
|
|
9
8
|
use crate::{focus_adorner, focus_visibility};
|
|
10
9
|
use std::cell::{Cell, RefCell};
|
|
@@ -44,8 +43,6 @@ pub(crate) struct PressableLabeledControl {
|
|
|
44
43
|
activation: Rc<RefCell<Option<ActivationCallback>>>,
|
|
45
44
|
state_changed: Rc<RefCell<Option<StateCallback>>>,
|
|
46
45
|
key_handler: Rc<RefCell<Option<KeyCallback>>>,
|
|
47
|
-
theme_guard: Rc<RefCell<Option<SubscriptionGuard>>>,
|
|
48
|
-
focus_visibility_guard: Rc<RefCell<Option<SubscriptionGuard>>>,
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
impl PressableLabeledControl {
|
|
@@ -87,8 +84,6 @@ impl PressableLabeledControl {
|
|
|
87
84
|
activation: Rc::new(RefCell::new(None)),
|
|
88
85
|
state_changed: Rc::new(RefCell::new(None)),
|
|
89
86
|
key_handler: Rc::new(RefCell::new(None)),
|
|
90
|
-
theme_guard: Rc::new(RefCell::new(None)),
|
|
91
|
-
focus_visibility_guard: Rc::new(RefCell::new(None)),
|
|
92
87
|
};
|
|
93
88
|
control.install_handlers();
|
|
94
89
|
control.install_theme_subscription();
|
|
@@ -246,17 +241,22 @@ impl PressableLabeledControl {
|
|
|
246
241
|
|
|
247
242
|
fn install_theme_subscription(&self) {
|
|
248
243
|
let target = self.event_target();
|
|
249
|
-
|
|
244
|
+
let theme_guard = subscribe(move |_theme| {
|
|
250
245
|
target.sync_base_theme();
|
|
251
246
|
target.notify_state_changed();
|
|
252
247
|
target.sync_focus_chrome();
|
|
253
|
-
})
|
|
248
|
+
});
|
|
249
|
+
self.root
|
|
250
|
+
.retained_node_ref()
|
|
251
|
+
.retain_attachment(Rc::new(theme_guard));
|
|
254
252
|
|
|
255
253
|
let target = self.event_target();
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
254
|
+
let focus_guard = focus_visibility::subscribe(move |_visible| {
|
|
255
|
+
target.sync_focus_chrome();
|
|
256
|
+
});
|
|
257
|
+
self.root
|
|
258
|
+
.retained_node_ref()
|
|
259
|
+
.retain_attachment(Rc::new(focus_guard));
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
fn event_target(&self) -> PressableLabeledControlEventTarget {
|