1use super::core::*;
2use super::*;
3use crate::animation::{animate_color, animate_float, Animation};
4use crate::transitions::NodeTransitions;
5
6#[derive(Default)]
7pub(crate) struct FlexBoxAnimations {
8 pub(crate) opacity: Option<Animation>,
9 pub(crate) background_color: Option<Animation>,
10}
11
12#[derive(Clone)]
13pub struct FlexBox {
14 pub(crate) core: Rc<RefCell<NodeCore>>,
15 pub(crate) props: Rc<RefCell<FlexBoxProps>>,
16 pub(crate) active_animations: Rc<RefCell<FlexBoxAnimations>>,
17 pub(crate) host_style_layers: Rc<RefCell<HostStyleLayers>>,
18}
19
20impl Default for FlexBox {
21 fn default() -> Self {
22 let mut core = NodeCore::new(NodeKind::FlexBox);
23 core.behavior.clip_to_bounds = Some(true);
24 Self {
25 core: Rc::new(RefCell::new(core)),
26 props: Rc::new(RefCell::new(FlexBoxProps::default())),
27 active_animations: Rc::new(RefCell::new(FlexBoxAnimations::default())),
28 host_style_layers: Rc::new(RefCell::new(HostStyleLayers::default())),
29 }
30 }
31}
32
33impl Node for FlexBox {
34 fn retained_node_ref(&self) -> NodeRef {
35 NodeRef::from_node(self.core.clone(), self.clone())
36 }
37
38 fn build_self(&self) {
39 let props = self.props.borrow().clone();
40 let behavior = self.core.borrow().behavior.clone();
41 apply_flex_box_props(self.handle(), &props, behavior);
42 }
43}
44
45#[derive(Clone, Copy, Debug, PartialEq)]
46pub struct Border {
47 pub width: f32,
48 pub color: u32,
49 pub style: BorderStyle,
50 pub dash_on: f32,
51 pub dash_off: f32,
52}
53
54impl Border {
55 pub fn solid(width: f32, color: u32) -> Self {
56 Self {
57 width,
58 color,
59 style: BorderStyle::Solid,
60 dash_on: 0.0,
61 dash_off: 0.0,
62 }
63 }
64
65 pub fn dashed(width: f32, color: u32, dash_on: f32, dash_off: f32) -> Self {
66 Self {
67 width,
68 color,
69 style: BorderStyle::Dashed,
70 dash_on,
71 dash_off,
72 }
73 }
74
75 pub fn dotted(width: f32, color: u32, dash_on: f32, dash_off: f32) -> Self {
76 Self {
77 width,
78 color,
79 style: BorderStyle::Dotted,
80 dash_on,
81 dash_off,
82 }
83 }
84}
85
86#[derive(Clone, Copy, Debug, PartialEq)]
87pub struct GradientStop {
88 pub offset: f32,
89 pub color: u32,
90}
91
92impl GradientStop {
93 pub fn new(offset: f32, color: u32) -> Self {
94 Self { offset, color }
95 }
96}
97
98impl FlexBox {
99 pub(crate) fn downgrade(&self) -> WeakFlexBox {
100 WeakFlexBox {
101 core: Rc::downgrade(&self.core),
102 props: Rc::downgrade(&self.props),
103 active_animations: Rc::downgrade(&self.active_animations),
104 host_style_layers: Rc::downgrade(&self.host_style_layers),
105 }
106 }
107
108 pub fn key(&self, _key: u64) -> &Self {
109 self
110 }
111
112 pub fn width(&self, width: f32, unit: Unit) -> &Self {
113 self.props.borrow_mut().width = Some((width, unit));
114 {
115 let mut core = self.core.borrow_mut();
116 core.behavior.fill_width = false;
117 core.behavior.fill_width_percent = None;
118 }
119 if self.has_built_handle() {
120 ui::set_width(self.handle().raw(), width, unit as u32);
121 self.notify_retained_layout_mutation();
122 }
123 self
124 }
125
126 pub fn width_len(&self, length: Length) -> &Self {
127 let (width, unit) = length;
128 self.width(width, unit)
129 }
130
131 pub fn height(&self, height: f32, unit: Unit) -> &Self {
132 self.props.borrow_mut().height = Some((height, unit));
133 {
134 let mut core = self.core.borrow_mut();
135 core.behavior.fill_height = false;
136 core.behavior.fill_height_percent = None;
137 }
138 if self.has_built_handle() {
139 ui::set_height(self.handle().raw(), height, unit as u32);
140 self.notify_retained_layout_mutation();
141 }
142 self
143 }
144
145 pub fn height_len(&self, length: Length) -> &Self {
146 let (height, unit) = length;
147 self.height(height, unit)
148 }
149
150 pub fn fill_width(&self) -> &Self {
151 self.props.borrow_mut().width = None;
152 {
153 let mut core = self.core.borrow_mut();
154 core.behavior.fill_width = true;
155 core.behavior.fill_width_percent = None;
156 }
157 if self.has_built_handle() {
158 ui::set_fill_width(self.handle().raw(), true);
159 self.notify_retained_layout_mutation();
160 }
161 self
162 }
163
164 pub fn fill_height(&self) -> &Self {
165 self.props.borrow_mut().height = None;
166 {
167 let mut core = self.core.borrow_mut();
168 core.behavior.fill_height = true;
169 core.behavior.fill_height_percent = None;
170 }
171 if self.has_built_handle() {
172 ui::set_fill_height(self.handle().raw(), true);
173 self.notify_retained_layout_mutation();
174 }
175 self
176 }
177
178 pub fn fill_size(&self) -> &Self {
179 self.fill_width();
180 self.fill_height();
181 self
182 }
183
184 pub fn fill_width_percent(&self, percent: f32) -> &Self {
185 self.props.borrow_mut().width = None;
186 {
187 let mut core = self.core.borrow_mut();
188 core.behavior.fill_width = false;
189 core.behavior.fill_width_percent = Some(percent);
190 }
191 if self.has_built_handle() {
192 ui::set_fill_width_percent(self.handle().raw(), percent);
193 self.notify_retained_layout_mutation();
194 }
195 self
196 }
197
198 pub fn fill_height_percent(&self, percent: f32) -> &Self {
199 self.props.borrow_mut().height = None;
200 {
201 let mut core = self.core.borrow_mut();
202 core.behavior.fill_height = false;
203 core.behavior.fill_height_percent = Some(percent);
204 }
205 if self.has_built_handle() {
206 ui::set_fill_height_percent(self.handle().raw(), percent);
207 self.notify_retained_layout_mutation();
208 }
209 self
210 }
211
212 pub fn bg_color(&self, color: u32) -> &Self {
213 self.host_style_layers.borrow_mut().local.background = Some(color);
214 self.set_effective_background_color(color)
215 }
216
217 fn set_effective_background_color(&self, color: u32) -> &Self {
218 self.cancel_background_color_transition();
219 if self.should_animate_background_color(color) {
220 let timing = {
221 self.props
222 .borrow()
223 .transitions
224 .as_ref()
225 .and_then(NodeTransitions::background_color_timing)
226 };
227 if let Some(timing) = timing {
228 let weak = self.downgrade();
229 let from = self.current_background_color();
230 let animation = animate_color(from, color, timing, move |value| {
231 if let Some(node) = weak.upgrade() {
232 node.apply_animated_background_color(value);
233 }
234 });
235 self.active_animations.borrow_mut().background_color = Some(animation);
236 return self;
237 }
238 }
239 self.apply_animated_background_color(color);
240 self
241 }
242
243 pub fn padding(&self, left: f32, top: f32, right: f32, bottom: f32) -> &Self {
244 self.host_style_layers.borrow_mut().local.padding =
245 Some(EdgeInsets::new(left, top, right, bottom));
246 self.props.borrow_mut().padding = Some((left, top, right, bottom));
247 if self.has_built_handle() {
248 ui::set_padding(self.handle().raw(), left, top, right, bottom);
249 self.notify_retained_layout_mutation();
250 }
251 self
252 }
253
254 pub fn flex_direction(&self, direction: FlexDirection) -> &Self {
255 self.host_style_layers.borrow_mut().local.flex_direction = Some(direction);
256 self.props.borrow_mut().flex_direction = Some(direction);
257 if self.has_built_handle() {
258 ui::set_flex_direction(self.handle().raw(), direction as u32);
259 self.notify_retained_layout_mutation();
260 }
261 self
262 }
263
264 pub fn corner_radius(&self, radius: f32) -> &Self {
265 self.corners(radius, radius, radius, radius)
266 }
267
268 pub fn corners(&self, tl: f32, tr: f32, br: f32, bl: f32) -> &Self {
269 self.host_style_layers.borrow_mut().local.corners = Some(Corners::new(tl, tr, br, bl));
270 let existing = self.props.borrow().box_style.unwrap_or(BoxStyle {
271 radius_tl: 0.0,
272 radius_tr: 0.0,
273 radius_br: 0.0,
274 radius_bl: 0.0,
275 border_width: 0.0,
276 border_color: 0,
277 border_style: BorderStyle::Solid,
278 border_dash_on: 0.0,
279 border_dash_off: 0.0,
280 });
281 self.props.borrow_mut().box_style = Some(BoxStyle {
282 radius_tl: tl,
283 radius_tr: tr,
284 radius_br: br,
285 radius_bl: bl,
286 ..existing
287 });
288 if self.has_built_handle() {
289 self.build_self();
290 self.notify_retained_mutation();
291 }
292 self
293 }
294
295 pub fn border(&self, width: f32, color: u32) -> &Self {
296 self.border_config(Border::solid(width, color))
297 }
298
299 pub fn border_config(&self, border: Border) -> &Self {
300 self.host_style_layers.borrow_mut().local.border = Some(border);
301 let existing = self.props.borrow().box_style.unwrap_or(BoxStyle {
302 radius_tl: 0.0,
303 radius_tr: 0.0,
304 radius_br: 0.0,
305 radius_bl: 0.0,
306 border_width: 0.0,
307 border_color: 0,
308 border_style: BorderStyle::Solid,
309 border_dash_on: 0.0,
310 border_dash_off: 0.0,
311 });
312 self.props.borrow_mut().box_style = Some(BoxStyle {
313 border_width: border.width,
314 border_color: border.color,
315 border_style: border.style,
316 border_dash_on: border.dash_on,
317 border_dash_off: border.dash_off,
318 ..existing
319 });
320 if self.has_built_handle() {
321 self.build_self();
322 self.notify_retained_mutation();
323 }
324 self
325 }
326
327 pub fn opacity(&self, value: f32) -> &Self {
328 let value = value.clamp(0.0, 1.0);
329 self.host_style_layers.borrow_mut().local.opacity = Some(value);
330 self.set_effective_opacity(value)
331 }
332
333 fn set_effective_opacity(&self, value: f32) -> &Self {
334 self.cancel_opacity_transition();
335 if self.should_animate_opacity(value) {
336 let timing = {
337 self.props
338 .borrow()
339 .transitions
340 .as_ref()
341 .and_then(NodeTransitions::opacity_timing)
342 };
343 if let Some(timing) = timing {
344 let weak = self.downgrade();
345 let from = self.current_opacity();
346 let animation = animate_float(from, value, timing, move |next| {
347 if let Some(node) = weak.upgrade() {
348 node.apply_animated_opacity(next);
349 }
350 });
351 self.active_animations.borrow_mut().opacity = Some(animation);
352 return self;
353 }
354 }
355 self.apply_animated_opacity(value);
356 self
357 }
358
359 pub fn transitions(&self, transitions: Option<NodeTransitions>) -> &Self {
360 self.props.borrow_mut().transitions = transitions;
361 self
362 }
363
364 pub fn blur(&self, sigma: f32) -> &Self {
365 self.props.borrow_mut().blur_sigma = Some(sigma.max(0.0));
366 if self.has_built_handle() {
367 self.build_self();
368 self.notify_retained_mutation();
369 }
370 self
371 }
372
373 pub fn drop_shadow(
374 &self,
375 color: u32,
376 offset_x: f32,
377 offset_y: f32,
378 blur_sigma: f32,
379 spread: f32,
380 ) -> &Self {
381 self.host_style_layers.borrow_mut().local.shadow =
382 Some(Shadow::new(color, offset_x, offset_y, blur_sigma, spread));
383 self.props.borrow_mut().drop_shadow = Some(DropShadow {
384 color,
385 offset_x,
386 offset_y,
387 blur_sigma: blur_sigma.max(0.0),
388 spread,
389 });
390 if self.has_built_handle() {
391 self.build_self();
392 self.notify_retained_mutation();
393 }
394 self
395 }
396
397 pub fn background_blur(&self, sigma: f32) -> &Self {
398 self.props.borrow_mut().background_blur_sigma = Some(sigma.max(0.0));
399 if self.has_built_handle() {
400 self.build_self();
401 self.notify_retained_mutation();
402 }
403 self
404 }
405
406 pub fn linear_gradient(
407 &self,
408 sx: f32,
409 sy: f32,
410 ex: f32,
411 ey: f32,
412 offsets: Vec<f32>,
413 colors: Vec<u32>,
414 ) -> &Self {
415 self.props.borrow_mut().linear_gradient = Some(LinearGradient {
416 sx,
417 sy,
418 ex,
419 ey,
420 offsets,
421 colors,
422 });
423 if self.has_built_handle() {
424 self.build_self();
425 self.notify_retained_mutation();
426 }
427 self
428 }
429
430 pub fn linear_gradient_stops(
431 &self,
432 sx: f32,
433 sy: f32,
434 ex: f32,
435 ey: f32,
436 stops: Vec<GradientStop>,
437 ) -> &Self {
438 let mut offsets = Vec::with_capacity(stops.len());
439 let mut colors = Vec::with_capacity(stops.len());
440 for stop in stops {
441 offsets.push(stop.offset);
442 colors.push(stop.color);
443 }
444 self.linear_gradient(sx, sy, ex, ey, offsets, colors)
445 }
446
447 pub fn interactive(&self, interactive: bool) -> &Self {
448 let mut core = self.core.borrow_mut();
449 core.behavior.interactive = interactive;
450 let enabled = core.behavior.enabled && core.behavior.inherited_enabled;
451 let has_built_handle = core.handle != NodeHandle::INVALID;
452 drop(core);
453 if has_built_handle {
454 ui::set_interactive(self.handle().raw(), enabled && interactive);
455 self.notify_retained_mutation();
456 }
457 self
458 }
459
460 pub fn enabled(&self, enabled: bool) -> &Self {
461 self.retained_node_ref().set_own_enabled(enabled);
462 self
463 }
464
465 pub(crate) fn reflect_semantic_disabled_from_enabled(&self) -> &Self {
466 let mut core = self.core.borrow_mut();
467 core.behavior.track_semantic_disabled_from_enabled = true;
468 let enabled = core.behavior.enabled && core.behavior.inherited_enabled;
469 let has_built_handle = core.handle != NodeHandle::INVALID;
470 drop(core);
471 if has_built_handle {
472 ui::set_semantic_disabled(self.handle().raw(), true, !enabled);
473 self.notify_retained_mutation();
474 }
475 self
476 }
477
478 pub fn focusable(&self, enabled: bool, tab_index: i32) -> &Self {
479 Node::focusable(self, enabled, tab_index);
480 self
481 }
482
483 pub fn cursor(&self, style: CursorStyle) -> &Self {
484 self.host_style_layers.borrow_mut().local.cursor = Some(style);
485 self.core.borrow_mut().behavior.cursor = Some(style);
486 crate::event::handle_cursor_style_changed(self.handle());
487 self
488 }
489
490 fn current_background_color(&self) -> u32 {
491 self.props.borrow().bg_color.unwrap_or(0)
492 }
493
494 fn current_opacity(&self) -> f32 {
495 self.props.borrow().opacity.unwrap_or(1.0)
496 }
497
498 fn apply_animated_background_color(&self, color: u32) {
499 self.props.borrow_mut().bg_color = Some(color);
500 if self.has_built_handle() {
501 ui::set_bg_color(self.handle().raw(), color);
502 self.notify_retained_mutation();
503 }
504 }
505
506 fn apply_animated_opacity(&self, value: f32) {
507 let value = value.clamp(0.0, 1.0);
508 self.props.borrow_mut().opacity = Some(value);
509 if self.has_built_handle() {
510 ui::set_layer_effect(
511 self.handle().raw(),
512 value,
513 self.props.borrow().blur_sigma.unwrap_or(0.0),
514 0,
515 );
516 self.notify_retained_mutation();
517 }
518 }
519
520 fn should_animate_opacity(&self, next: f32) -> bool {
521 self.has_built_handle()
522 && self
523 .props
524 .borrow()
525 .transitions
526 .as_ref()
527 .and_then(NodeTransitions::opacity_timing)
528 .is_some()
529 && (self.current_opacity() - next).abs() > f32::EPSILON
530 }
531
532 fn should_animate_background_color(&self, next: u32) -> bool {
533 self.has_built_handle()
534 && self
535 .props
536 .borrow()
537 .transitions
538 .as_ref()
539 .and_then(NodeTransitions::background_color_timing)
540 .is_some()
541 && self.current_background_color() != next
542 }
543
544 fn cancel_opacity_transition(&self) {
545 if let Some(animation) = self.active_animations.borrow_mut().opacity.take() {
546 animation.cancel();
547 }
548 }
549
550 fn cancel_background_color_transition(&self) {
551 if let Some(animation) = self.active_animations.borrow_mut().background_color.take() {
552 animation.cancel();
553 }
554 }
555
556 pub fn node_id(&self, node_id: impl Into<String>) -> &Self {
557 let node_id = node_id.into();
558 self.core.borrow_mut().behavior.node_id = Some(node_id.clone());
559 if self.has_built_handle() {
560 ui::set_node_id(self.handle().raw(), &node_id);
561 self.notify_retained_mutation();
562 }
563 self
564 }
565
566 pub fn semantic_role(&self, role: SemanticRole) -> &Self {
567 self.core.borrow_mut().behavior.semantic_role = Some(role);
568 if self.has_built_handle() {
569 ui::set_semantic_role(self.handle().raw(), role as u32);
570 self.notify_retained_mutation();
571 }
572 self
573 }
574
575 pub fn semantic_label(&self, label: impl Into<String>) -> &Self {
576 let label = label.into();
577 self.core.borrow_mut().behavior.semantic_label = Some(label.clone());
578 if self.has_built_handle() {
579 ui::set_semantic_label(self.handle().raw(), &label);
580 self.notify_retained_mutation();
581 }
582 self
583 }
584
585 pub(crate) fn default_semantic_label(&self, label: impl Into<String>) -> &Self {
586 let label = label.into();
587 let should_emit = {
588 let mut core = self.core.borrow_mut();
589 core.behavior.default_semantic_label = Some(label.clone());
590 core.behavior.semantic_label.is_none()
591 };
592 if should_emit && self.has_built_handle() {
593 ui::set_semantic_label(self.handle().raw(), &label);
594 self.notify_retained_mutation();
595 }
596 self
597 }
598
599 pub fn semantic_disabled(&self, disabled: bool) -> &Self {
600 Node::semantic_disabled(self, disabled);
601 self
602 }
603
604 pub fn semantic_checked(&self, state: SemanticCheckedState) -> &Self {
605 Node::semantic_checked(self, state);
606 self
607 }
608
609 pub fn semantic_selected(&self, selected: bool) -> &Self {
610 Node::semantic_selected(self, selected);
611 self
612 }
613
614 pub fn semantic_value_range(&self, value_now: f32, value_min: f32, value_max: f32) -> &Self {
615 Node::semantic_value_range(self, value_now, value_min, value_max);
616 self
617 }
618
619 pub fn semantic_orientation(&self, orientation: Orientation) -> &Self {
620 Node::semantic_orientation(self, orientation);
621 self
622 }
623
624 pub fn request_semantic_announcement(&self) -> &Self {
625 Node::request_semantic_announcement(self);
626 self
627 }
628
629 pub fn visibility(&self, visibility: Visibility) -> &Self {
630 Node::visibility(self, visibility);
631 self
632 }
633
634 pub fn portal(&self, is_portal: bool) -> &Self {
635 self.core.borrow_mut().behavior.is_portal = is_portal;
636 if self.has_built_handle() {
637 ui::set_is_portal(self.handle().raw(), is_portal);
638 self.notify_retained_mutation();
639 }
640 self
641 }
642
643 pub fn min_width(&self, value: f32, unit: Unit) -> &Self {
644 self.core.borrow_mut().behavior.min_width = Some((value, unit));
645 if self.has_built_handle() {
646 ui::set_min_width(self.handle().raw(), value, unit as u32);
647 self.notify_retained_layout_mutation();
648 }
649 self
650 }
651
652 pub fn min_width_len(&self, length: Length) -> &Self {
653 let (value, unit) = length;
654 self.min_width(value, unit)
655 }
656
657 pub fn max_width(&self, value: f32, unit: Unit) -> &Self {
658 self.core.borrow_mut().behavior.max_width = Some((value, unit));
659 if self.has_built_handle() {
660 ui::set_max_width(self.handle().raw(), value, unit as u32);
661 self.notify_retained_layout_mutation();
662 }
663 self
664 }
665
666 pub fn max_width_len(&self, length: Length) -> &Self {
667 let (value, unit) = length;
668 self.max_width(value, unit)
669 }
670
671 pub fn min_height(&self, value: f32, unit: Unit) -> &Self {
672 self.core.borrow_mut().behavior.min_height = Some((value, unit));
673 if self.has_built_handle() {
674 ui::set_min_height(self.handle().raw(), value, unit as u32);
675 self.notify_retained_layout_mutation();
676 }
677 self
678 }
679
680 pub fn min_height_len(&self, length: Length) -> &Self {
681 let (value, unit) = length;
682 self.min_height(value, unit)
683 }
684
685 pub fn max_height(&self, value: f32, unit: Unit) -> &Self {
686 self.core.borrow_mut().behavior.max_height = Some((value, unit));
687 if self.has_built_handle() {
688 ui::set_max_height(self.handle().raw(), value, unit as u32);
689 self.notify_retained_layout_mutation();
690 }
691 self
692 }
693
694 pub fn max_height_len(&self, length: Length) -> &Self {
695 let (value, unit) = length;
696 self.max_height(value, unit)
697 }
698
699 pub fn flex_basis(&self, basis: f32) -> &Self {
700 self.core.borrow_mut().behavior.flex_basis = Some(basis);
701 if self.has_built_handle() {
702 ui::set_flex_basis(self.handle().raw(), basis);
703 self.notify_retained_layout_mutation();
704 }
705 self
706 }
707
708 pub fn justify_content(&self, justify: JustifyContent) -> &Self {
709 self.host_style_layers.borrow_mut().local.justify_content = Some(justify);
710 self.core.borrow_mut().behavior.justify_content = Some(justify);
711 if self.has_built_handle() {
712 ui::set_justify_content(self.handle().raw(), justify as u32);
713 self.notify_retained_mutation();
714 }
715 self
716 }
717
718 pub fn align_items(&self, align: AlignItems) -> &Self {
719 self.host_style_layers.borrow_mut().local.align_items = Some(align);
720 self.core.borrow_mut().behavior.align_items = Some(align);
721 if self.has_built_handle() {
722 ui::set_align_items(self.handle().raw(), align as u32);
723 self.notify_retained_mutation();
724 }
725 self
726 }
727
728 pub fn align_self(&self, align: AlignSelf) -> &Self {
729 self.core.borrow_mut().behavior.align_self = Some(align);
730 if self.has_built_handle() {
731 ui::set_align_self(self.handle().raw(), align as u32);
732 self.notify_retained_mutation();
733 }
734 self
735 }
736
737 pub fn margin(&self, left: f32, top: f32, right: f32, bottom: f32) -> &Self {
738 self.core.borrow_mut().behavior.margin = Some((left, top, right, bottom));
739 if self.has_built_handle() {
740 ui::set_margin(self.handle().raw(), left, top, right, bottom);
741 self.notify_retained_layout_mutation();
742 }
743 self
744 }
745
746 pub fn apply_presenter_style(&self, style: PresenterHostStyle) -> &Self {
747 let previous = self.host_style_layers.borrow().resolved();
748 self.host_style_layers.borrow_mut().presenter = style;
749 self.sync_resolved_host_style_if_changed(previous);
750 self
751 }
752
753 pub fn clear_presenter_style(&self) -> &Self {
754 self.apply_presenter_style(PresenterHostStyle::new())
755 }
756
757 pub fn clear_bg_color(&self) -> &Self {
758 self.clear_local_host_style(|style| style.background = None)
759 }
760
761 pub fn clear_padding(&self) -> &Self {
762 self.clear_local_host_style(|style| style.padding = None)
763 }
764
765 pub fn clear_corners(&self) -> &Self {
766 self.clear_local_host_style(|style| style.corners = None)
767 }
768
769 pub fn clear_border(&self) -> &Self {
770 self.clear_local_host_style(|style| style.border = None)
771 }
772
773 pub fn clear_drop_shadow(&self) -> &Self {
774 self.clear_local_host_style(|style| style.shadow = None)
775 }
776
777 pub fn clear_opacity(&self) -> &Self {
778 self.clear_local_host_style(|style| style.opacity = None)
779 }
780
781 pub fn clear_flex_direction(&self) -> &Self {
782 self.clear_local_host_style(|style| style.flex_direction = None)
783 }
784
785 pub fn clear_justify_content(&self) -> &Self {
786 self.clear_local_host_style(|style| style.justify_content = None)
787 }
788
789 pub fn clear_align_items(&self) -> &Self {
790 self.clear_local_host_style(|style| style.align_items = None)
791 }
792
793 pub fn clear_cursor(&self) -> &Self {
794 self.clear_local_host_style(|style| style.cursor = None)
795 }
796
797 pub fn resolved_host_style(&self) -> PresenterHostStyle {
798 self.host_style_layers.borrow().resolved()
799 }
800
801 fn clear_local_host_style(&self, clear: impl FnOnce(&mut PresenterHostStyle)) -> &Self {
802 let previous = self.host_style_layers.borrow().resolved();
803 clear(&mut self.host_style_layers.borrow_mut().local);
804 self.sync_resolved_host_style_if_changed(previous);
805 self
806 }
807
808 fn sync_resolved_host_style_if_changed(&self, previous: PresenterHostStyle) {
809 let resolved = self.host_style_layers.borrow().resolved();
810 if resolved == previous {
811 return;
812 }
813 self.sync_resolved_host_style(previous, resolved);
814 }
815
816 fn sync_resolved_host_style(&self, previous: PresenterHostStyle, resolved: PresenterHostStyle) {
817 let background_changed = previous.background != resolved.background;
818 let padding_changed = previous.padding != resolved.padding;
819 let flex_direction_changed = previous.flex_direction != resolved.flex_direction;
820 let justify_content_changed = previous.justify_content != resolved.justify_content;
821 let align_items_changed = previous.align_items != resolved.align_items;
822 let box_style_changed =
823 previous.corners != resolved.corners || previous.border != resolved.border;
824 let opacity_changed = previous.opacity != resolved.opacity;
825 let shadow_changed = previous.shadow != resolved.shadow;
826 let cursor_changed = previous.cursor != resolved.cursor;
827
828 {
829 let mut props = self.props.borrow_mut();
830 props.padding = resolved
831 .padding
832 .map(|value| (value.left, value.top, value.right, value.bottom));
833 props.flex_direction = resolved.flex_direction;
834 props.opacity = resolved.opacity;
835 props.drop_shadow = resolved.shadow.map(|value| DropShadow {
836 color: value.color,
837 offset_x: value.offset_x,
838 offset_y: value.offset_y,
839 blur_sigma: value.blur_sigma,
840 spread: value.spread,
841 });
842 props.box_style = if resolved.corners.is_some() || resolved.border.is_some() {
843 let corners = resolved.corners.unwrap_or_else(|| Corners::all(0.0));
844 let border = resolved
845 .border
846 .unwrap_or_else(|| Border::solid(0.0, 0x00000000));
847 Some(BoxStyle {
848 radius_tl: corners.top_left,
849 radius_tr: corners.top_right,
850 radius_br: corners.bottom_right,
851 radius_bl: corners.bottom_left,
852 border_width: border.width,
853 border_color: border.color,
854 border_style: border.style,
855 border_dash_on: border.dash_on,
856 border_dash_off: border.dash_off,
857 })
858 } else {
859 None
860 };
861 }
862 {
863 let mut core = self.core.borrow_mut();
864 core.behavior.justify_content = resolved.justify_content;
865 core.behavior.align_items = resolved.align_items;
866 core.behavior.cursor = resolved.cursor;
867 }
868 if !self.has_built_handle() {
869 self.props.borrow_mut().bg_color = resolved.background;
870 self.props.borrow_mut().opacity = resolved.opacity;
871 return;
872 }
873
874 let handle = self.handle().raw();
875 let mut direct_native_change = false;
876 if box_style_changed {
877 let corners = resolved.corners.unwrap_or_else(|| Corners::all(0.0));
878 let border = resolved
879 .border
880 .unwrap_or_else(|| Border::solid(0.0, 0x00000000));
881 ui::set_box_style(
882 handle,
883 if background_changed {
884 previous.background.unwrap_or(0x00000000)
885 } else {
886 resolved.background.unwrap_or(0x00000000)
887 },
888 corners.top_left,
889 corners.top_right,
890 corners.bottom_right,
891 corners.bottom_left,
892 border.width,
893 border.color,
894 border.style as u32,
895 border.dash_on,
896 border.dash_off,
897 );
898 direct_native_change = true;
899 }
900 if padding_changed {
901 let padding = resolved.padding.unwrap_or_else(|| EdgeInsets::all(0.0));
902 ui::set_padding(
903 handle,
904 padding.left,
905 padding.top,
906 padding.right,
907 padding.bottom,
908 );
909 direct_native_change = true;
910 }
911 if flex_direction_changed {
912 ui::set_flex_direction(
913 handle,
914 resolved.flex_direction.unwrap_or(FlexDirection::Column) as u32,
915 );
916 direct_native_change = true;
917 }
918 if justify_content_changed {
919 ui::set_justify_content(
920 handle,
921 resolved.justify_content.unwrap_or(JustifyContent::Start) as u32,
922 );
923 direct_native_change = true;
924 }
925 if align_items_changed {
926 ui::set_align_items(
927 handle,
928 resolved.align_items.unwrap_or(AlignItems::Stretch) as u32,
929 );
930 direct_native_change = true;
931 }
932 if shadow_changed {
933 let shadow = resolved
934 .shadow
935 .unwrap_or_else(|| Shadow::new(0x00000000, 0.0, 0.0, 0.0, 0.0));
936 ui::set_drop_shadow(
937 handle,
938 shadow.color,
939 shadow.offset_x,
940 shadow.offset_y,
941 shadow.blur_sigma,
942 shadow.spread,
943 );
944 direct_native_change = true;
945 }
946 if cursor_changed {
947 crate::event::handle_cursor_style_changed(self.handle());
948 }
949 if direct_native_change {
950 self.notify_retained_mutation();
951 }
952 if background_changed {
953 self.set_effective_background_color(resolved.background.unwrap_or(0x00000000));
954 }
955 if opacity_changed {
956 self.set_effective_opacity(resolved.opacity.unwrap_or(1.0));
957 }
958 }
959
960 pub fn position_type(&self, position_type: PositionType) -> &Self {
961 self.core.borrow_mut().behavior.position_type = Some(position_type);
962 if self.has_built_handle() {
963 ui::set_position_type(self.handle().raw(), position_type as u32);
964 self.notify_retained_layout_mutation();
965 }
966 self
967 }
968
969 pub fn position(&self, left: f32, top: f32) -> &Self {
970 self.core.borrow_mut().behavior.position = Some((left, top, f32::NAN, f32::NAN));
971 if self.has_built_handle() {
972 ui::set_position(self.handle().raw(), left, top, f32::NAN, f32::NAN);
973 self.notify_retained_layout_mutation();
974 }
975 self
976 }
977
978 pub fn custom_drawable(&self, enabled: bool) -> &Self {
979 self.core.borrow_mut().behavior.custom_drawable = enabled;
980 self
981 }
982
983 pub fn flex_wrap(&self, wrap: FlexWrap) -> &Self {
984 self.core.borrow_mut().behavior.flex_wrap = Some(wrap);
985 if self.has_built_handle() {
986 ui::set_flex_wrap(self.handle().raw(), wrap as u32);
987 self.notify_retained_layout_mutation();
988 }
989 self
990 }
991
992 pub fn clip_to_bounds(&self, clip: bool) -> &Self {
993 self.core.borrow_mut().behavior.clip_to_bounds = Some(clip);
994 if self.has_built_handle() {
995 ui::set_clip_to_bounds(self.handle().raw(), clip);
996 self.notify_retained_mutation();
997 }
998 self
999 }
1000
1001 pub fn selection_area(&self, enabled: bool) -> &Self {
1002 self.core.borrow_mut().behavior.selection_area = enabled;
1003 self
1004 }
1005
1006 pub fn selection_area_barrier(&self, enabled: bool) -> &Self {
1007 self.core.borrow_mut().behavior.selection_area_barrier = enabled;
1008 self
1009 }
1010
1011 pub fn on_pointer_click(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
1012 self.core.borrow_mut().handlers.pointer_click = Some(Rc::new(handler));
1013 self.retained_node_ref().require_interactive();
1014 self
1015 }
1016
1017 pub fn on_pointer_down(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
1018 self.core.borrow_mut().handlers.pointer_down = Some(Rc::new(handler));
1019 self.retained_node_ref().require_interactive();
1020 self
1021 }
1022
1023 pub fn on_pointer_move(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
1024 self.core.borrow_mut().handlers.pointer_move = Some(Rc::new(handler));
1025 self.retained_node_ref().require_interactive();
1026 self
1027 }
1028
1029 pub fn on_pointer_up(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
1030 self.core.borrow_mut().handlers.pointer_up = Some(Rc::new(handler));
1031 self.retained_node_ref().require_interactive();
1032 self
1033 }
1034
1035 pub fn on_pointer_enter(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
1036 self.core.borrow_mut().handlers.pointer_enter = Some(Rc::new(handler));
1037 self.retained_node_ref().require_interactive();
1038 self
1039 }
1040
1041 pub fn on_pointer_leave(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
1042 self.core.borrow_mut().handlers.pointer_leave = Some(Rc::new(handler));
1043 self.retained_node_ref().require_interactive();
1044 self
1045 }
1046
1047 pub fn on_pointer_cancel(&self, handler: impl Fn(&mut PointerEventArgs) + 'static) -> &Self {
1048 self.core.borrow_mut().handlers.pointer_cancel = Some(Rc::new(handler));
1049 self.retained_node_ref().require_interactive();
1050 self
1051 }
1052
1053 pub fn on_wheel(&self, handler: impl Fn(&mut WheelEventArgs) + 'static) -> &Self {
1054 self.core.borrow_mut().handlers.wheel = Some(Rc::new(handler));
1055 self.retained_node_ref().require_interactive();
1056 self
1057 }
1058
1059 pub fn on_pan_gesture(&self, handler: impl Fn(&mut GestureEventArgs) + 'static) -> &Self {
1060 self.core.borrow_mut().handlers.pan_gesture = Some(Rc::new(handler));
1061 self
1062 }
1063
1064 pub fn on_pinch_gesture(&self, handler: impl Fn(&mut GestureEventArgs) + 'static) -> &Self {
1065 self.core.borrow_mut().handlers.pinch_gesture = Some(Rc::new(handler));
1066 self
1067 }
1068
1069 pub fn long_press_options(&self, minimum_duration_ms: i32, movement_tolerance: f32) -> &Self {
1070 let mut core = self.core.borrow_mut();
1071 core.handlers.long_press_minimum_duration_ms = minimum_duration_ms.max(0);
1072 core.handlers.long_press_movement_tolerance = movement_tolerance.max(0.0);
1073 self
1074 }
1075
1076 pub fn on_long_press(&self, handler: impl Fn(&mut LongPressEventArgs) + 'static) -> &Self {
1077 self.core.borrow_mut().handlers.long_press = Some(Rc::new(handler));
1078 self
1079 }
1080
1081 pub fn on_key_down(&self, handler: impl Fn(&mut KeyEventArgs) + 'static) -> &Self {
1082 self.core.borrow_mut().handlers.key_down = Some(Rc::new(handler));
1083 self
1084 }
1085
1086 pub fn on_key_up(&self, handler: impl Fn(&mut KeyEventArgs) + 'static) -> &Self {
1087 self.core.borrow_mut().handlers.key_up = Some(Rc::new(handler));
1088 self
1089 }
1090
1091 pub fn on_focus_changed(&self, handler: impl Fn(FocusChangedEventArgs) + 'static) -> &Self {
1092 self.core.borrow_mut().handlers.focus_changed = Some(Rc::new(handler));
1093 self
1094 }
1095
1096 pub fn child<T: Node>(&self, child: &T) -> &Self {
1097 self.append_child(child);
1098 self
1099 }
1100
1101 pub fn children<I, C>(&self, children: I) -> &Self
1102 where
1103 I: IntoIterator<Item = C>,
1104 C: Into<Child>,
1105 {
1106 for child in children {
1107 self.retained_node_ref()
1108 .append_child_ref(&child.into().node_ref);
1109 }
1110 self
1111 }
1112}