1use super::core::*;
2use super::*;
3
4pub type Length = (f32, Unit);
5
6pub fn flex_box() -> FlexBox {
7 FlexBox::default()
8}
9
10pub fn text(content: impl Into<String>) -> TextNode {
11 TextNode::new(content)
12}
13
14pub fn grid() -> Grid {
15 Grid::default()
16}
17
18pub fn image(texture_id: u32) -> ImageNode {
19 ImageNode::new(texture_id)
20}
21
22pub fn svg(svg_id: u32) -> SvgNode {
23 SvgNode::new(svg_id)
24}
25
26pub fn scroll_view() -> ScrollView {
27 ScrollView::new()
28}
29
30pub fn scroll_box() -> ScrollBox {
31 ScrollBox::new()
32}
33
34pub fn virtual_list(total_items: i32, item_height: f32) -> VirtualList<FlexBox> {
35 VirtualList::new(total_items, item_height)
36}
37
38pub fn row() -> FlexBox {
39 let root = FlexBox::default();
40 root.flex_direction(FlexDirection::Row);
41 root
42}
43
44pub fn column() -> FlexBox {
45 let root = FlexBox::default();
46 root.flex_direction(FlexDirection::Column);
47 root
48}
49
50pub fn portal() -> Portal {
51 let root = FlexBox::default();
52 root.clip_to_bounds(false).portal(true);
53 root
54}
55
56pub fn custom_drawable(handler: impl Fn(&mut DrawContext) + 'static) -> CustomDrawable {
57 CustomDrawable::new(handler)
58}
59
60pub fn viewport_width() -> f32 {
61 ui::get_viewport_width()
62}
63
64pub fn viewport_height() -> f32 {
65 ui::get_viewport_height()
66}
67
68pub fn px(value: f32) -> Length {
69 (value, Unit::Pixel)
70}
71
72pub fn pct(value: f32) -> Length {
73 (value, Unit::Percent)
74}
75
76pub fn auto() -> Length {
77 (0.0, Unit::Auto)
78}
79
80pub fn fill() -> Length {
81 (100.0, Unit::Percent)
82}
83
84pub(crate) fn apply_flex_box_props(
85 handle: NodeHandle,
86 props: &FlexBoxProps,
87 behavior: NodeBehavior,
88) {
89 ui::set_fill_width(handle.raw(), behavior.fill_width);
90 ui::set_fill_height(handle.raw(), behavior.fill_height);
91 if let Some(percent) = behavior.fill_width_percent {
92 ui::set_fill_width_percent(handle.raw(), percent);
93 }
94 if let Some(percent) = behavior.fill_height_percent {
95 ui::set_fill_height_percent(handle.raw(), percent);
96 }
97 if let Some((width, unit)) = props.width {
98 ui::set_width(handle.raw(), width, unit as u32);
99 }
100 if let Some((height, unit)) = props.height {
101 ui::set_height(handle.raw(), height, unit as u32);
102 }
103 if let Some((value, unit)) = props.min_width {
104 ui::set_min_width(handle.raw(), value, unit as u32);
105 }
106 if let Some((value, unit)) = props.max_width {
107 ui::set_max_width(handle.raw(), value, unit as u32);
108 }
109 if let Some((value, unit)) = props.min_height {
110 ui::set_min_height(handle.raw(), value, unit as u32);
111 }
112 if let Some((value, unit)) = props.max_height {
113 ui::set_max_height(handle.raw(), value, unit as u32);
114 }
115 if let Some(style) = props.box_style {
116 ui::set_box_style(
117 handle.raw(),
118 props.bg_color.unwrap_or(0),
119 style.radius_tl,
120 style.radius_tr,
121 style.radius_br,
122 style.radius_bl,
123 style.border_width,
124 style.border_color,
125 style.border_style as u32,
126 style.border_dash_on,
127 style.border_dash_off,
128 );
129 } else if let Some(color) = props.bg_color {
130 ui::set_bg_color(handle.raw(), color);
131 }
132 if let Some((left, top, right, bottom)) = props.padding {
133 ui::set_padding(handle.raw(), left, top, right, bottom);
134 }
135 if let Some(direction) = props.flex_direction {
136 ui::set_flex_direction(handle.raw(), direction as u32);
137 }
138 if props.opacity.is_some() || props.blur_sigma.is_some() {
139 ui::set_layer_effect(
140 handle.raw(),
141 props.opacity.unwrap_or(1.0),
142 props.blur_sigma.unwrap_or(0.0),
143 0,
144 );
145 }
146 if let Some(shadow) = props.drop_shadow {
147 ui::set_drop_shadow(
148 handle.raw(),
149 shadow.color,
150 shadow.offset_x,
151 shadow.offset_y,
152 shadow.blur_sigma,
153 shadow.spread,
154 );
155 }
156 if let Some(sigma) = props.background_blur_sigma {
157 ui::set_background_blur(handle.raw(), sigma);
158 }
159 if let Some(gradient) = props.linear_gradient.as_ref() {
160 ui::set_linear_gradient(
161 handle.raw(),
162 gradient.sx,
163 gradient.sy,
164 gradient.ex,
165 gradient.ey,
166 &gradient.offsets,
167 &gradient.colors,
168 );
169 }
170 apply_behavior(handle, behavior);
171}
172
173pub(crate) fn apply_text_props(handle: NodeHandle, props: &TextProps, behavior: NodeBehavior) {
174 ui::set_text(handle.raw(), &props.content);
175 ui::set_fill_width(handle.raw(), behavior.fill_width);
176 ui::set_fill_height(handle.raw(), behavior.fill_height);
177 if let Some(percent) = behavior.fill_width_percent {
178 ui::set_fill_width_percent(handle.raw(), percent);
179 }
180 if let Some(percent) = behavior.fill_height_percent {
181 ui::set_fill_height_percent(handle.raw(), percent);
182 }
183 apply_behavior(handle, behavior);
184 if let Some((width, unit)) = props.width {
185 ui::set_width(handle.raw(), width, unit as u32);
186 }
187 if let Some((height, unit)) = props.height {
188 ui::set_height(handle.raw(), height, unit as u32);
189 }
190 if let Some((value, unit)) = props.min_width {
191 ui::set_min_width(handle.raw(), value, unit as u32);
192 }
193 if let Some((value, unit)) = props.max_width {
194 ui::set_max_width(handle.raw(), value, unit as u32);
195 }
196 if let Some((value, unit)) = props.min_height {
197 ui::set_min_height(handle.raw(), value, unit as u32);
198 }
199 if let Some((value, unit)) = props.max_height {
200 ui::set_max_height(handle.raw(), value, unit as u32);
201 }
202 if props.has_font {
203 ui::set_font(handle.raw(), props.font_id, props.font_size);
204 }
205 if props.has_style_runs {
206 ui::set_text_style_runs(handle.raw(), &props.style_runs);
207 }
208 ui::set_text_color(
209 handle.raw(),
210 props
211 .text_color
212 .unwrap_or_else(|| crate::theme::current_theme().colors.text_primary),
213 );
214 if let Some(line_height) = props.line_height {
215 ui::set_line_height(handle.raw(), line_height);
216 }
217 if let Some(text_align) = props.text_align {
218 ui::set_text_align(handle.raw(), text_align as u32);
219 }
220 if let Some(text_vertical_align) = props.text_vertical_align {
221 ui::set_text_vertical_align(handle.raw(), text_vertical_align as u32);
222 }
223 if let Some((max_chars, max_lines)) = props.text_limits {
224 ui::set_text_limits(handle.raw(), max_chars, max_lines);
225 }
226 if let Some(wrapping) = props.wrapping {
227 ui::set_text_wrapping(handle.raw(), wrapping);
228 }
229 if let Some(overflow) = props.overflow {
230 ui::set_text_overflow(handle.raw(), overflow as u32);
231 }
232 if let Some((horizontal, vertical)) = props.overflow_fade {
233 ui::set_text_overflow_fade(handle.raw(), horizontal, vertical);
234 }
235 if let Some((selectable, selection_color)) = props.selectable {
236 ui::set_selectable(handle.raw(), selectable, selection_color);
237 }
238 if let Some(editable) = props.editable {
239 ui::set_editable(handle.raw(), editable);
240 }
241 if let Some(enabled) = props.editor_command_keys {
242 ui::set_editor_command_keys(handle.raw(), enabled);
243 }
244 if let Some(enabled) = props.editor_accepts_tab {
245 ui::set_editor_accepts_tab(handle.raw(), enabled);
246 }
247 if let Some(obscured) = props.obscured {
248 ui::set_text_obscured(handle.raw(), obscured);
249 }
250 if let Some(caret_color) = props.caret_color {
251 ui::set_caret_color(handle.raw(), caret_color);
252 }
253 if let Some((start, end)) = props.selection_range_bytes {
254 ui::set_text_selection_range(handle.raw(), start, end);
255 }
256}
257
258pub(crate) fn apply_grid_props(handle: NodeHandle, props: &GridProps) {
259 ui::grid_set_columns(handle.raw(), &props.columns, &props.column_types);
260 ui::grid_set_rows(handle.raw(), &props.rows, &props.row_types);
261 for (index, group) in &props.column_shared_size_groups {
262 ui::grid_set_column_shared_size_group(handle.raw(), *index, group);
263 }
264 for (index, group) in &props.row_shared_size_groups {
265 ui::grid_set_row_shared_size_group(handle.raw(), *index, group);
266 }
267}
268
269pub(crate) fn apply_image_props(handle: NodeHandle, props: &ImageProps) {
270 if let Some((left, top, right, bottom)) = props.image_nine {
271 ui::set_image_nine(
272 handle.raw(),
273 props.texture_id,
274 left,
275 top,
276 right,
277 bottom,
278 props.sampling_kind,
279 props.max_aniso,
280 );
281 } else {
282 ui::set_image(
283 handle.raw(),
284 props.texture_id,
285 props.object_fit as u32,
286 props.sampling_kind,
287 props.max_aniso,
288 );
289 }
290}
291
292pub(crate) fn apply_svg_props(handle: NodeHandle, props: &SvgProps) {
293 ui::set_svg(
294 handle.raw(),
295 props.svg_id,
296 props.tint_color,
297 props.sampling_kind,
298 props.max_aniso,
299 );
300}
301
302pub(crate) fn apply_scroll_view_props(
303 handle: NodeHandle,
304 props: &ScrollViewProps,
305 behavior: NodeBehavior,
306) {
307 ui::set_fill_width(handle.raw(), behavior.fill_width);
308 ui::set_fill_height(handle.raw(), behavior.fill_height);
309 if let Some(percent) = behavior.fill_width_percent {
310 ui::set_fill_width_percent(handle.raw(), percent);
311 }
312 if let Some(percent) = behavior.fill_height_percent {
313 ui::set_fill_height_percent(handle.raw(), percent);
314 }
315 if let Some((width, unit)) = props.width {
316 ui::set_width(handle.raw(), width, unit as u32);
317 }
318 if let Some((height, unit)) = props.height {
319 ui::set_height(handle.raw(), height, unit as u32);
320 }
321 ui::set_scroll_enabled(handle.raw(), props.enable_scroll_x, props.enable_scroll_y);
322 ui::set_smooth_scrolling(handle.raw(), props.smooth_scrolling);
323 if let Some(friction) = props.friction {
324 ui::set_scroll_friction(handle.raw(), friction);
325 }
326 if let Some((offset_x, offset_y)) = props.scroll_offset {
327 ui::set_scroll_offset(handle.raw(), offset_x, offset_y);
328 }
329 if let Some((content_width, content_height)) = props.content_size {
330 ui::set_scroll_content_size(handle.raw(), content_width, content_height);
331 }
332 apply_behavior(handle, behavior);
333}
334
335pub(crate) fn apply_behavior(handle: NodeHandle, behavior: NodeBehavior) {
336 let effective_enabled = behavior.enabled && behavior.inherited_enabled;
337 if let Some(node_id) = behavior.node_id.as_deref() {
338 ui::set_node_id(handle.raw(), node_id);
339 }
340 if let Some(role) = behavior.semantic_role {
341 ui::set_semantic_role(handle.raw(), role as u32);
342 }
343 if let Some(label) = behavior
344 .semantic_label
345 .as_deref()
346 .or(behavior.default_semantic_label.as_deref())
347 {
348 ui::set_semantic_label(handle.raw(), label);
349 }
350 if let Some(disabled) = behavior.semantic_disabled {
351 ui::set_semantic_disabled(handle.raw(), true, disabled);
352 }
353 if let Some(state) = behavior.semantic_checked {
354 ui::set_semantic_checked(handle.raw(), state as u32);
355 }
356 if let Some(selected) = behavior.semantic_selected {
357 ui::set_semantic_selected(handle.raw(), true, selected);
358 }
359 if let Some(expanded) = behavior.semantic_expanded {
360 ui::set_semantic_expanded(handle.raw(), true, expanded);
361 }
362 if let Some((value_now, value_min, value_max)) = behavior.semantic_value_range {
363 ui::set_semantic_value_range(handle.raw(), true, value_now, value_min, value_max);
364 }
365 if let Some(orientation) = behavior.semantic_orientation {
366 ui::set_semantic_orientation(handle.raw(), orientation as u32);
367 }
368 if let Some(visibility) = behavior.visibility {
369 ui::set_visibility(handle.raw(), visibility as u32);
370 }
371 ui::set_is_portal(handle.raw(), behavior.is_portal);
372 if let Some((value, unit)) = behavior.min_width {
373 ui::set_min_width(handle.raw(), value, unit as u32);
374 }
375 if let Some((value, unit)) = behavior.max_width {
376 ui::set_max_width(handle.raw(), value, unit as u32);
377 }
378 if let Some((value, unit)) = behavior.min_height {
379 ui::set_min_height(handle.raw(), value, unit as u32);
380 }
381 if let Some((value, unit)) = behavior.max_height {
382 ui::set_max_height(handle.raw(), value, unit as u32);
383 }
384 if let Some(basis) = behavior.flex_basis {
385 ui::set_flex_basis(handle.raw(), basis);
386 }
387 if let Some(justify) = behavior.justify_content {
388 ui::set_justify_content(handle.raw(), justify as u32);
389 }
390 if let Some(align) = behavior.align_items {
391 ui::set_align_items(handle.raw(), align as u32);
392 }
393 if let Some(align) = behavior.align_self {
394 ui::set_align_self(handle.raw(), align as u32);
395 }
396 if let Some((left, top, right, bottom)) = behavior.margin {
397 ui::set_margin(handle.raw(), left, top, right, bottom);
398 }
399 if let Some(position_type) = behavior.position_type {
400 ui::set_position_type(handle.raw(), position_type as u32);
401 }
402 if let Some((left, top, right, bottom)) = behavior.position {
403 ui::set_position(handle.raw(), left, top, right, bottom);
404 }
405 ui::set_is_shared_size_scope(handle.raw(), behavior.is_shared_size_scope);
406 ui::set_custom_drawable(handle.raw(), behavior.custom_drawable);
407 if let Some(wrap) = behavior.flex_wrap {
408 ui::set_flex_wrap(handle.raw(), wrap as u32);
409 }
410 if let Some(clip) = behavior.clip_to_bounds {
411 ui::set_clip_to_bounds(handle.raw(), clip);
412 }
413 if behavior.selection_area {
414 ui::set_selection_area(handle.raw(), true);
415 }
416 if behavior.selection_area_barrier {
417 ui::set_selection_area_barrier(handle.raw(), true);
418 }
419 if behavior.preserve_selection_on_pointer_down {
420 ui::set_preserve_selection_on_pointer_down(handle.raw(), true);
421 }
422 if let Some(scroll_handle) = behavior.scroll_proxy_target {
423 ui::set_scroll_proxy_target(handle.raw(), scroll_handle);
424 }
425 ui::set_interactive(handle.raw(), effective_enabled && behavior.interactive);
426 if let Some((enabled, tab_index)) = behavior.focusable {
427 ui::set_focusable(handle.raw(), effective_enabled && enabled, tab_index);
428 }
429 if behavior.track_semantic_disabled_from_enabled {
430 ui::set_semantic_disabled(handle.raw(), true, !effective_enabled);
431 }
432}