@effindomv2/fui-rs 0.1.3
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/COMMERCIAL.md +7 -0
- package/Cargo.toml +34 -0
- package/LICENSE.md +9 -0
- package/README.md +88 -0
- package/package.json +54 -0
- package/scripts/build.sh +227 -0
- package/scripts/check-runtime-dependency.sh +41 -0
- package/scripts/framework-host-services.ts +40 -0
- package/scripts/generate-host-events.ts +17 -0
- package/scripts/generate-host-services.ts +28 -0
- package/scripts/hostgen/common.ts +73 -0
- package/scripts/hostgen/registry.ts +159 -0
- package/scripts/hostgen/rust-host-events.ts +171 -0
- package/scripts/hostgen/rust-host-services.ts +257 -0
- package/src/animation.rs +625 -0
- package/src/app.rs +324 -0
- package/src/assets.rs +572 -0
- package/src/bindings/mod.rs +1 -0
- package/src/bindings/ui.rs +705 -0
- package/src/bitmap.rs +317 -0
- package/src/bridge_callbacks.rs +242 -0
- package/src/context_menu_manager.rs +332 -0
- package/src/controls/anti_selection_area.rs +54 -0
- package/src/controls/button.rs +542 -0
- package/src/controls/checkbox.rs +372 -0
- package/src/controls/combobox.rs +1574 -0
- package/src/controls/context_menu.rs +1367 -0
- package/src/controls/control_template_set.rs +46 -0
- package/src/controls/control_tokens.rs +596 -0
- package/src/controls/dialog.rs +590 -0
- package/src/controls/dropdown.rs +1010 -0
- package/src/controls/form.rs +229 -0
- package/src/controls/internal/button_presenter.rs +142 -0
- package/src/controls/internal/checkbox_indicator_presenter.rs +210 -0
- package/src/controls/internal/dropdown_chevron_presenter.rs +134 -0
- package/src/controls/internal/dropdown_field_presenter.rs +269 -0
- package/src/controls/internal/dropdown_option_row_presenter.rs +184 -0
- package/src/controls/internal/mod.rs +13 -0
- package/src/controls/internal/pressable_indicator_presenter.rs +26 -0
- package/src/controls/internal/pressable_labeled_control.rs +492 -0
- package/src/controls/internal/radio_indicator_presenter.rs +208 -0
- package/src/controls/internal/selectable_popup_list.rs +597 -0
- package/src/controls/internal/slider_presenter.rs +282 -0
- package/src/controls/internal/switch_indicator_presenter.rs +235 -0
- package/src/controls/internal/text_input_core.rs +1074 -0
- package/src/controls/internal/text_input_presenter.rs +108 -0
- package/src/controls/mod.rs +235 -0
- package/src/controls/nav_link.rs +395 -0
- package/src/controls/popup.rs +191 -0
- package/src/controls/progress_bar.rs +287 -0
- package/src/controls/radio_button.rs +348 -0
- package/src/controls/radio_group.rs +283 -0
- package/src/controls/selection_area.rs +82 -0
- package/src/controls/shared.rs +68 -0
- package/src/controls/slider.rs +701 -0
- package/src/controls/switch.rs +293 -0
- package/src/controls/templating.rs +49 -0
- package/src/controls/tests.rs +3905 -0
- package/src/controls/text_area.rs +207 -0
- package/src/controls/text_input.rs +192 -0
- package/src/debug.rs +146 -0
- package/src/drag_drop.rs +424 -0
- package/src/drag_gesture.rs +258 -0
- package/src/drawing.rs +385 -0
- package/src/event.rs +1603 -0
- package/src/external_drop.rs +467 -0
- package/src/fetch.rs +500 -0
- package/src/ffi.rs +3542 -0
- package/src/file.rs +1677 -0
- package/src/focus_adorner.rs +307 -0
- package/src/focus_visibility.rs +121 -0
- package/src/frame_scheduler.rs +159 -0
- package/src/frame_signal.rs +64 -0
- package/src/generated/ffi.rs +798 -0
- package/src/generated/framework_host_services.rs +74 -0
- package/src/generated/mod.rs +2 -0
- package/src/host_services.rs +162 -0
- package/src/image_sampling.rs +78 -0
- package/src/keyboard_scroll.rs +137 -0
- package/src/keyboard_scroll_tracker.rs +385 -0
- package/src/lib.rs +547 -0
- package/src/logger.rs +56 -0
- package/src/mobile_text_selection_toolbar.rs +1034 -0
- package/src/navigation.rs +48 -0
- package/src/node/core.rs +2210 -0
- package/src/node/custom_drawable.rs +149 -0
- package/src/node/flex_box.rs +874 -0
- package/src/node/grid.rs +304 -0
- package/src/node/helpers.rs +442 -0
- package/src/node/image.rs +506 -0
- package/src/node/mod.rs +315 -0
- package/src/node/scroll_bar.rs +845 -0
- package/src/node/scroll_box.rs +514 -0
- package/src/node/scroll_state.rs +121 -0
- package/src/node/scroll_view.rs +557 -0
- package/src/node/svg_node.rs +474 -0
- package/src/node/text_node.rs +633 -0
- package/src/node/virtual_list.rs +678 -0
- package/src/panic_hook.rs +36 -0
- package/src/persisted.rs +274 -0
- package/src/platform.rs +556 -0
- package/src/popup_presenter.rs +344 -0
- package/src/selection_handle_adorner.rs +838 -0
- package/src/signal.rs +134 -0
- package/src/text.rs +1065 -0
- package/src/theme.rs +571 -0
- package/src/timers.rs +106 -0
- package/src/tool_tip.rs +167 -0
- package/src/tool_tip_manager.rs +691 -0
- package/src/transitions.rs +41 -0
- package/src/typography.rs +520 -0
- package/src/viewport.rs +108 -0
- package/src/worker.rs +308 -0
- package/src/worker_job.rs +82 -0
- package/src/worker_runtime.rs +172 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
use crate::controls::{DropdownColors, DropdownSizing};
|
|
2
|
+
use crate::ffi::{AlignItems, FlexDirection, JustifyContent, TextVerticalAlign, Unit};
|
|
3
|
+
use crate::node::{flex_box, text, FlexBox, TextNode};
|
|
4
|
+
use crate::theme::Theme;
|
|
5
|
+
use std::rc::Rc;
|
|
6
|
+
|
|
7
|
+
const DEFAULT_CHEVRON_BOX_SIZE: f32 = 16.0;
|
|
8
|
+
const DEFAULT_FIELD_PADDING_X: f32 = 16.0;
|
|
9
|
+
const DEFAULT_FIELD_FONT_SIZE: f32 = 16.0;
|
|
10
|
+
const DEFAULT_FIELD_HEIGHT: f32 = 32.0;
|
|
11
|
+
|
|
12
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
13
|
+
pub struct DropdownFieldMetrics {
|
|
14
|
+
pub height: f32,
|
|
15
|
+
pub font_size: f32,
|
|
16
|
+
pub chevron_box_size: f32,
|
|
17
|
+
pub padding_left: f32,
|
|
18
|
+
pub padding_top: f32,
|
|
19
|
+
pub padding_right: f32,
|
|
20
|
+
pub padding_bottom: f32,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl DropdownFieldMetrics {
|
|
24
|
+
pub const fn new(
|
|
25
|
+
height: f32,
|
|
26
|
+
font_size: f32,
|
|
27
|
+
chevron_box_size: f32,
|
|
28
|
+
padding_left: f32,
|
|
29
|
+
padding_top: f32,
|
|
30
|
+
padding_right: f32,
|
|
31
|
+
padding_bottom: f32,
|
|
32
|
+
) -> Self {
|
|
33
|
+
Self {
|
|
34
|
+
height,
|
|
35
|
+
font_size,
|
|
36
|
+
chevron_box_size,
|
|
37
|
+
padding_left,
|
|
38
|
+
padding_top,
|
|
39
|
+
padding_right,
|
|
40
|
+
padding_bottom,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub const DEFAULT_DROPDOWN_FIELD_METRICS: DropdownFieldMetrics = DropdownFieldMetrics::new(
|
|
46
|
+
DEFAULT_FIELD_HEIGHT,
|
|
47
|
+
DEFAULT_FIELD_FONT_SIZE,
|
|
48
|
+
DEFAULT_CHEVRON_BOX_SIZE,
|
|
49
|
+
DEFAULT_FIELD_PADDING_X,
|
|
50
|
+
0.0,
|
|
51
|
+
DEFAULT_FIELD_PADDING_X,
|
|
52
|
+
0.0,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
fn resolve_field_metrics(sizing: Option<DropdownSizing>) -> DropdownFieldMetrics {
|
|
56
|
+
let Some(sizing) = sizing else {
|
|
57
|
+
return DEFAULT_DROPDOWN_FIELD_METRICS;
|
|
58
|
+
};
|
|
59
|
+
if !sizing.has_field_height() && !sizing.has_field_font_size() && !sizing.has_chevron_box_size()
|
|
60
|
+
{
|
|
61
|
+
return DEFAULT_DROPDOWN_FIELD_METRICS;
|
|
62
|
+
}
|
|
63
|
+
let font_size = if sizing.has_field_font_size() {
|
|
64
|
+
sizing.field_font_size_px()
|
|
65
|
+
} else {
|
|
66
|
+
DEFAULT_DROPDOWN_FIELD_METRICS.font_size
|
|
67
|
+
};
|
|
68
|
+
let chevron_box_size = if sizing.has_chevron_box_size() {
|
|
69
|
+
sizing.chevron_box_size_px()
|
|
70
|
+
} else {
|
|
71
|
+
DEFAULT_DROPDOWN_FIELD_METRICS.chevron_box_size
|
|
72
|
+
};
|
|
73
|
+
let content_height = font_size.max(chevron_box_size);
|
|
74
|
+
let height = if sizing.has_field_height() {
|
|
75
|
+
sizing.field_height_px()
|
|
76
|
+
} else {
|
|
77
|
+
DEFAULT_DROPDOWN_FIELD_METRICS.height.max(content_height)
|
|
78
|
+
};
|
|
79
|
+
DropdownFieldMetrics::new(
|
|
80
|
+
height,
|
|
81
|
+
font_size,
|
|
82
|
+
chevron_box_size,
|
|
83
|
+
DEFAULT_FIELD_PADDING_X,
|
|
84
|
+
0.0,
|
|
85
|
+
DEFAULT_FIELD_PADDING_X,
|
|
86
|
+
0.0,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
91
|
+
pub struct DropdownFieldVisualState {
|
|
92
|
+
pub open: bool,
|
|
93
|
+
pub focused: bool,
|
|
94
|
+
pub enabled: bool,
|
|
95
|
+
pub pressed: bool,
|
|
96
|
+
pub selected_label: String,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
impl DropdownFieldVisualState {
|
|
100
|
+
pub fn new(
|
|
101
|
+
open: bool,
|
|
102
|
+
focused: bool,
|
|
103
|
+
enabled: bool,
|
|
104
|
+
pressed: bool,
|
|
105
|
+
selected_label: impl Into<String>,
|
|
106
|
+
) -> Self {
|
|
107
|
+
Self {
|
|
108
|
+
open,
|
|
109
|
+
focused,
|
|
110
|
+
enabled,
|
|
111
|
+
pressed,
|
|
112
|
+
selected_label: selected_label.into(),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
pub trait DropdownFieldPresenter {
|
|
118
|
+
fn root(&self) -> FlexBox;
|
|
119
|
+
fn value_host(&self) -> FlexBox;
|
|
120
|
+
fn value_node(&self) -> TextNode;
|
|
121
|
+
fn chevron_host(&self) -> FlexBox;
|
|
122
|
+
fn metrics(&self) -> DropdownFieldMetrics;
|
|
123
|
+
fn apply(&self, theme: Theme, state: &DropdownFieldVisualState, colors: Option<DropdownColors>);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub trait DropdownFieldTemplate {
|
|
127
|
+
fn create(&self, sizing: Option<DropdownSizing>) -> Rc<dyn DropdownFieldPresenter>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#[derive(Clone)]
|
|
131
|
+
pub struct DefaultDropdownFieldPresenter {
|
|
132
|
+
root: FlexBox,
|
|
133
|
+
value_host: FlexBox,
|
|
134
|
+
value_node: TextNode,
|
|
135
|
+
chevron_host: FlexBox,
|
|
136
|
+
metrics: DropdownFieldMetrics,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
impl DefaultDropdownFieldPresenter {
|
|
140
|
+
pub fn new(metrics: DropdownFieldMetrics) -> Self {
|
|
141
|
+
let theme = crate::theme::current_theme();
|
|
142
|
+
let value_node = text("");
|
|
143
|
+
value_node
|
|
144
|
+
.selectable(false, theme.colors.selection)
|
|
145
|
+
.fill_size()
|
|
146
|
+
.text_limits(0, 1)
|
|
147
|
+
.wrapping(false);
|
|
148
|
+
value_node
|
|
149
|
+
.text_overflow_fade(true, false)
|
|
150
|
+
.text_vertical_align(TextVerticalAlign::Center);
|
|
151
|
+
let value_host = flex_box();
|
|
152
|
+
value_host.fill_size().child(&value_node);
|
|
153
|
+
let chevron_host = flex_box();
|
|
154
|
+
chevron_host
|
|
155
|
+
.width(metrics.chevron_box_size, Unit::Pixel)
|
|
156
|
+
.height(metrics.chevron_box_size, Unit::Pixel)
|
|
157
|
+
.align_items(AlignItems::Center)
|
|
158
|
+
.justify_content(JustifyContent::Center);
|
|
159
|
+
let root = flex_box();
|
|
160
|
+
root.flex_direction(FlexDirection::Row)
|
|
161
|
+
.align_items(AlignItems::Center)
|
|
162
|
+
.child(&value_host)
|
|
163
|
+
.child(&chevron_host);
|
|
164
|
+
Self {
|
|
165
|
+
root,
|
|
166
|
+
value_host,
|
|
167
|
+
value_node: value_node.clone(),
|
|
168
|
+
chevron_host,
|
|
169
|
+
metrics,
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
impl DropdownFieldPresenter for DefaultDropdownFieldPresenter {
|
|
175
|
+
fn root(&self) -> FlexBox {
|
|
176
|
+
self.root.clone()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
fn value_host(&self) -> FlexBox {
|
|
180
|
+
self.value_host.clone()
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
fn value_node(&self) -> TextNode {
|
|
184
|
+
self.value_node.clone()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
fn chevron_host(&self) -> FlexBox {
|
|
188
|
+
self.chevron_host.clone()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fn metrics(&self) -> DropdownFieldMetrics {
|
|
192
|
+
self.metrics
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
fn apply(
|
|
196
|
+
&self,
|
|
197
|
+
theme: Theme,
|
|
198
|
+
state: &DropdownFieldVisualState,
|
|
199
|
+
colors: Option<DropdownColors>,
|
|
200
|
+
) {
|
|
201
|
+
let metrics = self.metrics;
|
|
202
|
+
let content_height = metrics
|
|
203
|
+
.font_size
|
|
204
|
+
.max(metrics.height - metrics.padding_top - metrics.padding_bottom);
|
|
205
|
+
let bg = if colors.is_some_and(|colors| colors.has_background()) {
|
|
206
|
+
colors.unwrap().background_color()
|
|
207
|
+
} else if state.pressed && state.enabled {
|
|
208
|
+
theme.colors.background
|
|
209
|
+
} else {
|
|
210
|
+
theme.colors.surface
|
|
211
|
+
};
|
|
212
|
+
let border_color = colors
|
|
213
|
+
.filter(|colors| colors.has_border())
|
|
214
|
+
.map(|colors| colors.border_color())
|
|
215
|
+
.unwrap_or(theme.colors.border);
|
|
216
|
+
self.root
|
|
217
|
+
.flex_direction(FlexDirection::Row)
|
|
218
|
+
.align_items(AlignItems::Center)
|
|
219
|
+
.height(metrics.height, Unit::Pixel)
|
|
220
|
+
.corner_radius(theme.spacing.sm)
|
|
221
|
+
.border(2.0, border_color)
|
|
222
|
+
.padding(
|
|
223
|
+
metrics.padding_left,
|
|
224
|
+
metrics.padding_top,
|
|
225
|
+
metrics.padding_right,
|
|
226
|
+
metrics.padding_bottom,
|
|
227
|
+
)
|
|
228
|
+
.bg_color(bg);
|
|
229
|
+
self.value_host.fill_size();
|
|
230
|
+
let text_color = if !state.enabled {
|
|
231
|
+
theme.colors.text_muted
|
|
232
|
+
} else {
|
|
233
|
+
colors
|
|
234
|
+
.filter(|colors| colors.has_text_primary())
|
|
235
|
+
.map(|colors| colors.text_primary_color())
|
|
236
|
+
.unwrap_or(theme.colors.text_primary)
|
|
237
|
+
};
|
|
238
|
+
self.value_node
|
|
239
|
+
.font_family(theme.fonts.body_family.clone())
|
|
240
|
+
.font_size(metrics.font_size)
|
|
241
|
+
.line_height(content_height)
|
|
242
|
+
.text_color(text_color);
|
|
243
|
+
self.chevron_host
|
|
244
|
+
.width(metrics.chevron_box_size, Unit::Pixel)
|
|
245
|
+
.height(metrics.chevron_box_size, Unit::Pixel)
|
|
246
|
+
.align_items(AlignItems::Center)
|
|
247
|
+
.justify_content(JustifyContent::Center);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
#[derive(Clone, Copy, Debug, Default)]
|
|
252
|
+
pub struct DefaultDropdownFieldTemplate;
|
|
253
|
+
|
|
254
|
+
impl DropdownFieldTemplate for DefaultDropdownFieldTemplate {
|
|
255
|
+
fn create(&self, sizing: Option<DropdownSizing>) -> Rc<dyn DropdownFieldPresenter> {
|
|
256
|
+
create_default_dropdown_field_presenter(sizing)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
pub const DEFAULT_DROPDOWN_FIELD_TEMPLATE: DefaultDropdownFieldTemplate =
|
|
261
|
+
DefaultDropdownFieldTemplate;
|
|
262
|
+
|
|
263
|
+
pub fn create_default_dropdown_field_presenter(
|
|
264
|
+
sizing: Option<DropdownSizing>,
|
|
265
|
+
) -> Rc<dyn DropdownFieldPresenter> {
|
|
266
|
+
Rc::new(DefaultDropdownFieldPresenter::new(resolve_field_metrics(
|
|
267
|
+
sizing,
|
|
268
|
+
)))
|
|
269
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
use crate::controls::{DropdownColors, DropdownSizing};
|
|
2
|
+
use crate::ffi::{AlignItems, TextVerticalAlign};
|
|
3
|
+
use crate::node::{flex_box, text, FlexBox, TextNode};
|
|
4
|
+
use crate::theme::Theme;
|
|
5
|
+
use std::rc::Rc;
|
|
6
|
+
|
|
7
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
8
|
+
pub struct DropdownOptionRowMetrics {
|
|
9
|
+
pub height: f32,
|
|
10
|
+
pub padding_left: f32,
|
|
11
|
+
pub padding_right: f32,
|
|
12
|
+
pub font_size: f32,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
impl DropdownOptionRowMetrics {
|
|
16
|
+
pub const fn new(height: f32, padding_left: f32, padding_right: f32, font_size: f32) -> Self {
|
|
17
|
+
Self {
|
|
18
|
+
height,
|
|
19
|
+
padding_left,
|
|
20
|
+
padding_right,
|
|
21
|
+
font_size,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pub const DEFAULT_DROPDOWN_OPTION_ROW_METRICS: DropdownOptionRowMetrics =
|
|
27
|
+
DropdownOptionRowMetrics::new(34.0, 10.0, 10.0, 16.0);
|
|
28
|
+
|
|
29
|
+
fn resolve_option_row_metrics(sizing: Option<DropdownSizing>) -> DropdownOptionRowMetrics {
|
|
30
|
+
let Some(sizing) = sizing else {
|
|
31
|
+
return DEFAULT_DROPDOWN_OPTION_ROW_METRICS;
|
|
32
|
+
};
|
|
33
|
+
if !sizing.has_option_height() && !sizing.has_option_font_size() {
|
|
34
|
+
return DEFAULT_DROPDOWN_OPTION_ROW_METRICS;
|
|
35
|
+
}
|
|
36
|
+
let font_size = if sizing.has_option_font_size() {
|
|
37
|
+
sizing.option_font_size_px()
|
|
38
|
+
} else {
|
|
39
|
+
DEFAULT_DROPDOWN_OPTION_ROW_METRICS.font_size
|
|
40
|
+
};
|
|
41
|
+
let height = if sizing.has_option_height() {
|
|
42
|
+
sizing.option_height_px()
|
|
43
|
+
} else {
|
|
44
|
+
DEFAULT_DROPDOWN_OPTION_ROW_METRICS.height
|
|
45
|
+
};
|
|
46
|
+
DropdownOptionRowMetrics::new(
|
|
47
|
+
height,
|
|
48
|
+
DEFAULT_DROPDOWN_OPTION_ROW_METRICS.padding_left,
|
|
49
|
+
DEFAULT_DROPDOWN_OPTION_ROW_METRICS.padding_right,
|
|
50
|
+
font_size,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
55
|
+
pub struct DropdownOptionRowVisualState {
|
|
56
|
+
pub highlighted: bool,
|
|
57
|
+
pub selected: bool,
|
|
58
|
+
pub enabled: bool,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
impl DropdownOptionRowVisualState {
|
|
62
|
+
pub const fn new(highlighted: bool, selected: bool, enabled: bool) -> Self {
|
|
63
|
+
Self {
|
|
64
|
+
highlighted,
|
|
65
|
+
selected,
|
|
66
|
+
enabled,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub trait DropdownOptionRowPresenter {
|
|
72
|
+
fn root(&self) -> FlexBox;
|
|
73
|
+
fn label_node(&self) -> TextNode;
|
|
74
|
+
fn metrics(&self) -> DropdownOptionRowMetrics;
|
|
75
|
+
fn apply(
|
|
76
|
+
&self,
|
|
77
|
+
theme: Theme,
|
|
78
|
+
state: DropdownOptionRowVisualState,
|
|
79
|
+
colors: Option<DropdownColors>,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
pub trait DropdownOptionRowTemplate {
|
|
84
|
+
fn create(&self, sizing: Option<DropdownSizing>) -> Rc<dyn DropdownOptionRowPresenter>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[derive(Clone)]
|
|
88
|
+
pub struct DefaultDropdownOptionRowPresenter {
|
|
89
|
+
root: FlexBox,
|
|
90
|
+
label_node: TextNode,
|
|
91
|
+
metrics: DropdownOptionRowMetrics,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
impl DefaultDropdownOptionRowPresenter {
|
|
95
|
+
pub fn new(metrics: DropdownOptionRowMetrics) -> Self {
|
|
96
|
+
let theme = crate::theme::current_theme();
|
|
97
|
+
let label_node = text("");
|
|
98
|
+
label_node
|
|
99
|
+
.selectable(false, theme.colors.selection)
|
|
100
|
+
.fill_size()
|
|
101
|
+
.text_limits(0, 1)
|
|
102
|
+
.wrapping(false);
|
|
103
|
+
label_node
|
|
104
|
+
.text_overflow_fade(true, false)
|
|
105
|
+
.text_vertical_align(TextVerticalAlign::Center);
|
|
106
|
+
let root = flex_box();
|
|
107
|
+
root.fill_size()
|
|
108
|
+
.align_items(AlignItems::Center)
|
|
109
|
+
.child(&label_node);
|
|
110
|
+
Self {
|
|
111
|
+
root,
|
|
112
|
+
label_node: label_node.clone(),
|
|
113
|
+
metrics,
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
impl DropdownOptionRowPresenter for DefaultDropdownOptionRowPresenter {
|
|
119
|
+
fn root(&self) -> FlexBox {
|
|
120
|
+
self.root.clone()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fn label_node(&self) -> TextNode {
|
|
124
|
+
self.label_node.clone()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
fn metrics(&self) -> DropdownOptionRowMetrics {
|
|
128
|
+
self.metrics
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fn apply(
|
|
132
|
+
&self,
|
|
133
|
+
theme: Theme,
|
|
134
|
+
state: DropdownOptionRowVisualState,
|
|
135
|
+
colors: Option<DropdownColors>,
|
|
136
|
+
) {
|
|
137
|
+
let metrics = self.metrics;
|
|
138
|
+
self.root
|
|
139
|
+
.padding(metrics.padding_left, 0.0, metrics.padding_right, 0.0)
|
|
140
|
+
.corner_radius(theme.spacing.xs)
|
|
141
|
+
.bg_color(if state.highlighted {
|
|
142
|
+
theme.context_menu.item.hover_background
|
|
143
|
+
} else {
|
|
144
|
+
0x00000000
|
|
145
|
+
});
|
|
146
|
+
let label_color = if !state.enabled {
|
|
147
|
+
theme.colors.text_muted
|
|
148
|
+
} else if state.selected {
|
|
149
|
+
colors
|
|
150
|
+
.filter(|colors| colors.has_accent())
|
|
151
|
+
.map(|colors| colors.accent_color())
|
|
152
|
+
.unwrap_or(theme.colors.accent)
|
|
153
|
+
} else {
|
|
154
|
+
colors
|
|
155
|
+
.filter(|colors| colors.has_text_primary())
|
|
156
|
+
.map(|colors| colors.text_primary_color())
|
|
157
|
+
.unwrap_or(theme.colors.text_primary)
|
|
158
|
+
};
|
|
159
|
+
self.label_node
|
|
160
|
+
.font_family(theme.fonts.body_family.clone())
|
|
161
|
+
.font_size(metrics.font_size)
|
|
162
|
+
.text_color(label_color);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
#[derive(Clone, Copy, Debug, Default)]
|
|
167
|
+
pub struct DefaultDropdownOptionRowTemplate;
|
|
168
|
+
|
|
169
|
+
impl DropdownOptionRowTemplate for DefaultDropdownOptionRowTemplate {
|
|
170
|
+
fn create(&self, sizing: Option<DropdownSizing>) -> Rc<dyn DropdownOptionRowPresenter> {
|
|
171
|
+
create_default_dropdown_option_row_presenter(sizing)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
pub const DEFAULT_DROPDOWN_OPTION_ROW_TEMPLATE: DefaultDropdownOptionRowTemplate =
|
|
176
|
+
DefaultDropdownOptionRowTemplate;
|
|
177
|
+
|
|
178
|
+
pub fn create_default_dropdown_option_row_presenter(
|
|
179
|
+
sizing: Option<DropdownSizing>,
|
|
180
|
+
) -> Rc<dyn DropdownOptionRowPresenter> {
|
|
181
|
+
Rc::new(DefaultDropdownOptionRowPresenter::new(
|
|
182
|
+
resolve_option_row_metrics(sizing),
|
|
183
|
+
))
|
|
184
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
pub(crate) mod button_presenter;
|
|
2
|
+
pub(crate) mod checkbox_indicator_presenter;
|
|
3
|
+
pub(crate) mod dropdown_chevron_presenter;
|
|
4
|
+
pub(crate) mod dropdown_field_presenter;
|
|
5
|
+
pub(crate) mod dropdown_option_row_presenter;
|
|
6
|
+
pub(crate) mod pressable_indicator_presenter;
|
|
7
|
+
pub(crate) mod pressable_labeled_control;
|
|
8
|
+
pub(crate) mod radio_indicator_presenter;
|
|
9
|
+
pub(crate) mod selectable_popup_list;
|
|
10
|
+
pub(crate) mod slider_presenter;
|
|
11
|
+
pub(crate) mod switch_indicator_presenter;
|
|
12
|
+
pub(crate) mod text_input_core;
|
|
13
|
+
pub(crate) mod text_input_presenter;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
use crate::node::FlexBox;
|
|
2
|
+
|
|
3
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
4
|
+
pub struct PressableIndicatorMetrics {
|
|
5
|
+
pub width: f32,
|
|
6
|
+
pub height: f32,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
impl PressableIndicatorMetrics {
|
|
10
|
+
pub const fn new(width: f32, height: f32) -> Self {
|
|
11
|
+
Self { width, height }
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
16
|
+
pub struct PressableIndicatorVisualState {
|
|
17
|
+
pub hovered: bool,
|
|
18
|
+
pub pressed: bool,
|
|
19
|
+
pub focused: bool,
|
|
20
|
+
pub enabled: bool,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub trait PressableIndicatorPresenter {
|
|
24
|
+
fn root(&self) -> FlexBox;
|
|
25
|
+
fn metrics(&self) -> PressableIndicatorMetrics;
|
|
26
|
+
}
|