1use std::{any::TypeId, cell::RefCell, fmt};
4
5use crate::{source_location, widget::WidgetId};
6
7use super::{
8 WIDGET,
9 builder::{
10 AnyPropertyBuildAction, Importance, PropertyArgs, PropertyId, SourceLocation, WhenBuildAction, WhenInfo, WhenInput, WidgetBuilder,
11 WidgetType,
12 },
13 node::{FillUiNode, UiNode, UiNodeOp},
14};
15
16use crate::widget::{
17 builder::{NestGroup, property_id},
18 node::match_node,
19 property,
20};
21use zng_var::{BoxedVar, IntoValue, context_var, impl_from_and_into_var};
22
23pub struct WidgetBase {
32 builder: RefCell<Option<WidgetBuilder>>,
33 importance: Importance,
34 when: RefCell<Option<WhenInfo>>,
35}
36impl WidgetBase {
37 pub fn widget_type() -> WidgetType {
39 WidgetType {
40 type_id: TypeId::of::<Self>(),
41 path: "$crate::widget::base::WidgetBase",
42 location: source_location!(),
43 }
44 }
45
46 pub fn widget_new() -> Self {
48 Self::inherit(Self::widget_type())
49 }
50
51 pub fn widget_builder(&mut self) -> &mut WidgetBuilder {
53 self.builder.get_mut().as_mut().expect("already built")
54 }
55
56 pub fn widget_when(&mut self) -> Option<&mut WhenInfo> {
58 self.when.get_mut().as_mut()
59 }
60
61 pub fn widget_take(&mut self) -> WidgetBuilder {
66 assert!(self.when.get_mut().is_none(), "cannot take builder with `when` pending");
67 self.builder.get_mut().take().expect("builder already taken")
68 }
69
70 pub fn widget_build(&mut self) -> impl UiNode + use<> {
74 let mut wgt = self.widget_take();
75 wgt.push_build_action(|wgt| {
76 if !wgt.has_child() {
77 wgt.set_child(FillUiNode);
78 }
79 });
80 node::build(wgt)
81 }
82
83 pub fn widget_importance(&mut self) -> &mut Importance {
87 &mut self.importance
88 }
89
90 pub fn start_when_block(&mut self, inputs: Box<[WhenInput]>, state: BoxedVar<bool>, expr: &'static str, location: SourceLocation) {
92 assert!(self.builder.get_mut().is_some(), "cannot start `when` after build");
93 assert!(self.when.get_mut().is_none(), "cannot nest `when` blocks");
94
95 *self.when.get_mut() = Some(WhenInfo {
96 inputs,
97 state,
98 assigns: vec![],
99 build_action_data: vec![],
100 expr,
101 location,
102 });
103 }
104
105 pub fn end_when_block(&mut self) {
107 let when = self.when.get_mut().take().expect("no current `when` block to end");
108 self.builder.get_mut().as_mut().unwrap().push_when(self.importance, when);
109 }
110
111 fn widget_intrinsic(&mut self) {
112 node::include_intrinsics(self.widget_builder());
113 }
114
115 #[doc(hidden)]
117 pub fn mtd_property__(&self, args: Box<dyn PropertyArgs>) {
118 if let Some(when) = &mut *self.when.borrow_mut() {
119 when.assigns.push(args);
120 } else {
121 self.builder
122 .borrow_mut()
123 .as_mut()
124 .expect("cannot set after build")
125 .push_property(self.importance, args);
126 }
127 }
128
129 #[doc(hidden)]
131 pub fn mtd_property_unset__(&self, id: PropertyId) {
132 assert!(self.when.borrow().is_none(), "cannot unset in when assign");
133 self.builder
134 .borrow_mut()
135 .as_mut()
136 .expect("cannot unset after build")
137 .push_unset(self.importance, id);
138 }
139
140 #[doc(hidden)]
141 pub fn reexport__(&self, f: impl FnOnce(&mut Self)) {
142 let mut inner = Self {
143 builder: RefCell::new(self.builder.borrow_mut().take()),
144 importance: self.importance,
145 when: RefCell::new(self.when.borrow_mut().take()),
146 };
147 f(&mut inner);
148 *self.builder.borrow_mut() = inner.builder.into_inner();
149 *self.when.borrow_mut() = inner.when.into_inner();
150 debug_assert_eq!(self.importance, inner.importance);
151 }
152
153 #[doc(hidden)]
154 pub fn push_unset_property_build_action__(&mut self, property_id: PropertyId, action_name: &'static str) {
155 assert!(self.when.get_mut().is_none(), "cannot unset build actions in when assigns");
156
157 self.builder
158 .get_mut()
159 .as_mut()
160 .expect("cannot unset build actions after build")
161 .push_unset_property_build_action(property_id, action_name, self.importance);
162 }
163
164 #[doc(hidden)]
165 pub fn push_property_build_action__(
166 &mut self,
167 property_id: PropertyId,
168 action_name: &'static str,
169 input_actions: Vec<Box<dyn AnyPropertyBuildAction>>,
170 ) {
171 assert!(
172 self.when.get_mut().is_none(),
173 "cannot push property build action in `when`, use `push_when_build_action_data__`"
174 );
175
176 self.builder
177 .get_mut()
178 .as_mut()
179 .expect("cannot unset build actions after build")
180 .push_property_build_action(property_id, action_name, self.importance, input_actions);
181 }
182
183 #[doc(hidden)]
184 pub fn push_when_build_action_data__(&mut self, property_id: PropertyId, action_name: &'static str, data: WhenBuildAction) {
185 let when = self
186 .when
187 .get_mut()
188 .as_mut()
189 .expect("cannot push when build action data outside when blocks");
190 when.build_action_data.push(((property_id, action_name), data));
191 }
192}
193
194#[diagnostic::on_unimplemented(note = "`{Self}` is not an `#[widget]`")]
199pub trait WidgetImpl {
200 fn inherit(widget: WidgetType) -> Self;
202
203 fn base(&mut self) -> &mut WidgetBase;
205
206 #[doc(hidden)]
207 fn base_ref(&self) -> &WidgetBase;
208
209 #[doc(hidden)]
210 fn info_instance__() -> Self;
211
212 #[doc(hidden)]
213 fn widget_intrinsic(&mut self) {}
214}
215impl WidgetImpl for WidgetBase {
216 fn inherit(widget: WidgetType) -> Self {
217 let builder = WidgetBuilder::new(widget);
218 let mut w = Self {
219 builder: RefCell::new(Some(builder)),
220 importance: Importance::WIDGET,
221 when: RefCell::new(None),
222 };
223 w.widget_intrinsic();
224 w.importance = Importance::INSTANCE;
225 w
226 }
227
228 fn base(&mut self) -> &mut WidgetBase {
229 self
230 }
231
232 fn base_ref(&self) -> &WidgetBase {
233 self
234 }
235
236 fn info_instance__() -> Self {
237 WidgetBase {
238 builder: RefCell::new(None),
239 importance: Importance::INSTANCE,
240 when: RefCell::new(None),
241 }
242 }
243}
244
245#[doc(hidden)]
246pub trait WidgetExt {
247 #[doc(hidden)]
248 fn ext_property__(&mut self, args: Box<dyn PropertyArgs>);
249 #[doc(hidden)]
250 fn ext_property_unset__(&mut self, id: PropertyId);
251}
252impl WidgetExt for WidgetBase {
253 fn ext_property__(&mut self, args: Box<dyn PropertyArgs>) {
254 if let Some(when) = self.when.get_mut() {
255 when.assigns.push(args);
256 } else {
257 self.builder
258 .get_mut()
259 .as_mut()
260 .expect("cannot set after build")
261 .push_property(self.importance, args);
262 }
263 }
264
265 fn ext_property_unset__(&mut self, id: PropertyId) {
266 assert!(self.when.get_mut().is_none(), "cannot unset in when blocks");
267
268 self.builder
269 .get_mut()
270 .as_mut()
271 .expect("cannot unset after build")
272 .push_unset(self.importance, id);
273 }
274}
275
276#[doc(hidden)]
277#[macro_export]
278macro_rules! WidgetBaseMacro__ {
279 ($($tt:tt)*) => {
280 $crate::widget::widget_new! {
281 new {
282 let mut wgt__ = $crate::widget::base::WidgetBase::widget_new();
283 let wgt__ = &mut wgt__;
284 }
285 build {
286 let wgt__ = wgt__.widget_build();
287 wgt__
288 }
289 set { $($tt)* }
290 }
291 }
292}
293#[doc(hidden)]
294pub use WidgetBaseMacro__ as WidgetBase;
295
296pub struct NonWidgetBase {
301 base: WidgetBase,
302}
303impl NonWidgetBase {
304 pub fn widget_type() -> WidgetType {
306 WidgetType {
307 type_id: TypeId::of::<Self>(),
308 path: "$crate::widget::base::NonWidgetBase",
309 location: source_location!(),
310 }
311 }
312
313 pub fn widget_new() -> Self {
315 Self::inherit(Self::widget_type())
316 }
317
318 pub fn widget_builder(&mut self) -> &mut WidgetBuilder {
320 self.base.widget_builder()
321 }
322
323 pub fn widget_when(&mut self) -> Option<&mut WhenInfo> {
325 self.base.widget_when()
326 }
327
328 pub fn widget_take(&mut self) -> WidgetBuilder {
333 self.base.widget_take()
334 }
335
336 pub fn widget_build(&mut self) -> WidgetBuilder {
340 self.widget_take()
341 }
342
343 pub fn widget_importance(&mut self) -> &mut Importance {
347 self.base.widget_importance()
348 }
349
350 pub fn start_when_block(&mut self, inputs: Box<[WhenInput]>, state: BoxedVar<bool>, expr: &'static str, location: SourceLocation) {
352 self.base.start_when_block(inputs, state, expr, location)
353 }
354
355 pub fn end_when_block(&mut self) {
357 self.base.end_when_block()
358 }
359
360 fn widget_intrinsic(&mut self) {}
361
362 #[doc(hidden)]
364 pub fn mtd_property__(&self, args: Box<dyn PropertyArgs>) {
365 self.base.mtd_property__(args)
366 }
367
368 #[doc(hidden)]
370 pub fn mtd_property_unset__(&self, id: PropertyId) {
371 self.base.mtd_property_unset__(id)
372 }
373
374 #[doc(hidden)]
375 pub fn reexport__(&self, f: impl FnOnce(&mut WidgetBase)) {
376 self.base.reexport__(f)
377 }
378
379 #[doc(hidden)]
380 pub fn push_unset_property_build_action__(&mut self, property_id: PropertyId, action_name: &'static str) {
381 self.base.push_unset_property_build_action__(property_id, action_name)
382 }
383
384 #[doc(hidden)]
385 pub fn push_property_build_action__(
386 &mut self,
387 property_id: PropertyId,
388 action_name: &'static str,
389 input_actions: Vec<Box<dyn AnyPropertyBuildAction>>,
390 ) {
391 self.base.push_property_build_action__(property_id, action_name, input_actions)
392 }
393
394 #[doc(hidden)]
395 pub fn push_when_build_action_data__(&mut self, property_id: PropertyId, action_name: &'static str, data: WhenBuildAction) {
396 self.base.push_when_build_action_data__(property_id, action_name, data)
397 }
398}
399impl WidgetImpl for NonWidgetBase {
400 fn inherit(widget: WidgetType) -> Self {
401 let builder = WidgetBuilder::new(widget);
402 let mut w = Self {
403 base: WidgetBase {
404 builder: RefCell::new(Some(builder)),
405 importance: Importance::WIDGET,
406 when: RefCell::new(None),
407 },
408 };
409 w.widget_intrinsic();
410 w.base.importance = Importance::INSTANCE;
411 w
412 }
413
414 fn base(&mut self) -> &mut WidgetBase {
415 &mut self.base
416 }
417
418 fn base_ref(&self) -> &WidgetBase {
419 &self.base
420 }
421
422 fn info_instance__() -> Self {
423 Self {
424 base: WidgetBase {
425 builder: RefCell::new(None),
426 importance: Importance::INSTANCE,
427 when: RefCell::new(None),
428 },
429 }
430 }
431}
432impl WidgetExt for NonWidgetBase {
433 fn ext_property__(&mut self, args: Box<dyn PropertyArgs>) {
434 self.base.ext_property__(args)
435 }
436
437 fn ext_property_unset__(&mut self, id: PropertyId) {
438 self.base.ext_property_unset__(id)
439 }
440}
441
442pub mod node {
446 use zng_layout::unit::{PxCornerRadius, PxRect, PxSize};
447 use zng_var::Var;
448
449 use crate::{
450 render::{FrameBuilder, FrameUpdate, FrameValueKey},
451 update::{EventUpdate, WidgetUpdates},
452 widget::{
453 WidgetCtx, WidgetUpdateMode,
454 info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
455 node::BoxedUiNode,
456 },
457 };
458
459 use super::*;
460
461 pub fn include_intrinsics(wgt: &mut WidgetBuilder) {
463 wgt.push_build_action(|wgt| {
464 wgt.push_intrinsic(NestGroup::CHILD, "widget_child", node::widget_child);
465 wgt.push_intrinsic(NestGroup::WIDGET_INNER, "widget_inner", node::widget_inner);
466 });
467 }
468
469 pub fn build(mut wgt: WidgetBuilder) -> impl UiNode {
477 let id = wgt.capture_value_or_else(property_id!(id), WidgetId::new_unique);
478 let child = wgt.build();
479 node::widget(child, id)
480 }
481
482 pub fn widget_child(child: impl UiNode) -> impl UiNode {
493 let key = FrameValueKey::new_unique();
494 let mut define_ref_frame = false;
495
496 match_node(child, move |child, op| match op {
497 UiNodeOp::Measure { wm, desired_size } => {
498 *desired_size = child.measure(wm);
499
500 if let Some(inline) = wm.inline() {
501 if inline.is_default() {
502 if let Some(child_inline) = child
503 .with_context(WidgetUpdateMode::Ignore, || WIDGET.bounds().measure_inline())
504 .flatten()
505 {
506 *inline = child_inline;
508 }
509 }
510 }
511 }
512 UiNodeOp::Layout { wl, final_size } => {
513 let (s, d) = wl.with_child(|wl| child.layout(wl));
514 *final_size = s;
515
516 if d != define_ref_frame {
517 define_ref_frame = d;
518 WIDGET.render();
519 }
520
521 if !define_ref_frame {
522 if let Some(inline) = wl.inline() {
524 if inline.is_default() {
525 child.with_context(WidgetUpdateMode::Ignore, || {
526 let bounds = WIDGET.bounds();
527 let child_inline = bounds.inline();
528 if let Some(child_inline) = child_inline {
529 inline.clone_from(&*child_inline);
530 }
531 });
532 }
533 }
534 }
535 }
536
537 UiNodeOp::Render { frame } => {
538 let offset = WIDGET.bounds().child_offset();
539 if define_ref_frame {
540 frame.push_reference_frame(key.into(), key.bind(offset.into(), true), true, false, |frame| child.render(frame));
541 } else {
542 frame.push_child(offset, |frame| {
543 child.render(frame);
544 });
545 }
546 }
547 UiNodeOp::RenderUpdate { update } => {
548 let offset = WIDGET.bounds().child_offset();
549 if define_ref_frame {
550 update.with_transform(key.update(offset.into(), true), false, |update| child.render_update(update));
551 } else {
552 update.with_child(offset, |update| child.render_update(update))
553 }
554 }
555 _ => {}
556 })
557 }
558
559 pub fn widget_inner(child: impl UiNode) -> impl UiNode {
567 #[derive(Default, PartialEq)]
568 struct HitClips {
569 bounds: PxSize,
570 corners: PxCornerRadius,
571 }
572
573 let transform_key = FrameValueKey::new_unique();
574 let mut clips = HitClips::default();
575
576 match_node(child, move |child, op| match op {
577 UiNodeOp::Init => {
578 WIDGET.sub_var_layout(&HIT_TEST_MODE_VAR);
579 }
580 UiNodeOp::Layout { wl, final_size } => {
581 *final_size = wl.with_inner(|wl| child.layout(wl));
582
583 let mode = HIT_TEST_MODE_VAR.get();
584 let c = if matches!(mode, HitTestMode::Bounds | HitTestMode::RoundedBounds) {
585 HitClips {
586 bounds: *final_size,
587 corners: if matches!(mode, HitTestMode::RoundedBounds) {
588 WIDGET.border().corner_radius()
589 } else {
590 PxCornerRadius::zero()
591 },
592 }
593 } else {
594 HitClips::default()
595 };
596
597 if c != clips {
598 clips = c;
599 WIDGET.render();
600 }
601 }
602 UiNodeOp::Render { frame } => {
603 frame.push_inner(transform_key, true, |frame| {
604 frame.hit_test().push_clips(
605 |c| {
606 if let Some(inline) = WIDGET.bounds().inline() {
607 for r in inline.negative_space().iter() {
608 c.push_clip_rect(*r, true);
609 }
610 }
611 },
612 |h| match HIT_TEST_MODE_VAR.get() {
613 HitTestMode::RoundedBounds => {
614 h.push_rounded_rect(PxRect::from_size(clips.bounds), clips.corners);
615 }
616 HitTestMode::Bounds => {
617 h.push_rect(PxRect::from_size(clips.bounds));
618 }
619 _ => {}
620 },
621 );
622
623 child.render(frame);
624 });
625 }
626 UiNodeOp::RenderUpdate { update } => {
627 update.update_inner(transform_key, true, |update| child.render_update(update));
628 }
629 _ => {}
630 })
631 }
632
633 pub fn widget(child: impl UiNode, id: impl IntoValue<WidgetId>) -> impl UiNode {
643 struct WidgetNode<C> {
644 ctx: WidgetCtx,
645 child: C,
646
647 #[cfg(debug_assertions)]
648 inited: bool,
649 #[cfg(debug_assertions)]
650 info_built: bool,
651 }
652 impl<C: UiNode> UiNode for WidgetNode<C> {
653 fn init(&mut self) {
654 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
655 #[cfg(debug_assertions)]
656 if self.inited {
657 tracing::error!(target: "widget_base", "`UiNode::init` called in inited widget {:?}", WIDGET.id());
658 }
659
660 self.child.init();
661 WIDGET.update_info().layout().render();
662
663 #[cfg(debug_assertions)]
664 {
665 self.inited = true;
666 self.info_built = false;
667 }
668 });
669 self.ctx.take_reinit(); }
671
672 fn deinit(&mut self) {
673 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
674 #[cfg(debug_assertions)]
675 if !self.inited {
676 tracing::error!(target: "widget_base", "`UiNode::deinit` called in not inited widget {:?}", WIDGET.id());
677 }
678
679 self.child.deinit();
680 WIDGET.update_info().layout().render();
681
682 #[cfg(debug_assertions)]
683 {
684 self.inited = false;
685 self.info_built = false;
686 }
687 });
688 self.ctx.deinit(cfg!(any(test, feature = "test_util")));
689 }
690
691 fn info(&mut self, info: &mut WidgetInfoBuilder) {
692 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
693 #[cfg(debug_assertions)]
694 if !self.inited {
695 tracing::error!(target: "widget_base", "`UiNode::info` called in not inited widget {:?}", WIDGET.id());
696 }
697
698 #[cfg(debug_assertions)]
699 {
700 self.info_built = true;
701 }
702
703 info.push_widget(|info| {
704 self.child.info(info);
705 });
706 });
707
708 if self.ctx.is_pending_reinit() {
709 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
710 }
711 }
712
713 fn event(&mut self, update: &EventUpdate) {
714 if self.ctx.take_reinit() {
715 self.deinit();
716 self.init();
717 }
718
719 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
720 #[cfg(debug_assertions)]
721 if !self.inited {
722 tracing::error!(target: "widget_base", "`UiNode::event::<{}>` called in not inited widget {:?}", update.event().name(), WIDGET.id());
723 } else if !self.info_built {
724 tracing::error!(target: "widget_base", "`UiNode::event::<{}>` called in widget {:?} before first info build", update.event().name(), WIDGET.id());
725 }
726
727 update.with_widget(|| {
728 self.child.event(update);
729 });
730 });
731
732 if self.ctx.take_reinit() {
733 self.deinit();
734 self.init();
735 }
736 }
737
738 fn update(&mut self, updates: &WidgetUpdates) {
739 if self.ctx.take_reinit() {
740 self.deinit();
741 self.init();
742 return;
743 }
744
745 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
746 #[cfg(debug_assertions)]
747 if !self.inited {
748 tracing::error!(target: "widget_base", "`UiNode::update` called in not inited widget {:?}", WIDGET.id());
749 } else if !self.info_built {
750 tracing::error!(target: "widget_base", "`UiNode::update` called in widget {:?} before first info build", WIDGET.id());
751 }
752
753 updates.with_widget(|| {
754 self.child.update(updates);
755 });
756 });
757
758 if self.ctx.take_reinit() {
759 self.deinit();
760 self.init();
761 }
762 }
763
764 fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
765 let desired_size = WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Ignore, || {
766 #[cfg(debug_assertions)]
767 if !self.inited {
768 tracing::error!(target: "widget_base", "`UiNode::measure` called in not inited widget {:?}", WIDGET.id());
769 } else if !self.info_built {
770 tracing::error!(target: "widget_base", "`UiNode::measure` called in widget {:?} before first info build", WIDGET.id());
771 }
772
773 wm.with_widget(|wm| {
774 let child_size = self.child.measure(wm);
775
776 #[cfg(debug_assertions)]
778 if let Some(inline) = wm.inline() {
779 for (name, size, segs) in [
780 ("first", inline.first, &inline.first_segs),
781 ("last", inline.last, &inline.last_segs),
782 ] {
783 let width = size.width.0 as f32;
784 let sum_width = segs.iter().map(|s| s.width).sum::<f32>();
785 if sum_width > width + 0.1 {
786 tracing::error!(
787 "widget {:?} measured inline {name} row has {width} width, but row segs sum to {sum_width} width",
788 WIDGET.id()
789 );
790 }
791 }
792 }
793
794 child_size
795 })
796 });
797
798 let _ = self.ctx.take_reinit();
800
801 desired_size
802 }
803
804 fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
805 let final_size = WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
806 #[cfg(debug_assertions)]
807 if !self.inited {
808 tracing::error!(target: "widget_base", "`UiNode::layout` called in not inited widget {:?}", WIDGET.id());
809 } else if !self.info_built {
810 tracing::error!(target: "widget_base", "`UiNode::layout` called in widget {:?} before first info build", WIDGET.id());
811 }
812
813 wl.with_widget(|wl| {
814 let child_size = self.child.layout(wl);
815
816 #[cfg(debug_assertions)]
818 if let Some(inline) = wl.inline() {
819 use zng_layout::unit::Px;
820
821 for (name, row, segs) in inline
822 .rows
823 .first()
824 .iter()
825 .map(|r| ("first", r, &inline.first_segs))
826 .chain(inline.rows.last().iter().map(|r| ("last", r, &inline.last_segs)))
827 {
828 let width = row.width();
829 let sum_width = segs.iter().map(|s| s.width).sum::<Px>();
830 if (sum_width - width) > Px(1) {
831 tracing::error!(
832 "widget {:?} layout inline {name} row has {width} width, but row segs widths sum to {sum_width}",
833 WIDGET.id()
834 );
835 }
836 }
837 }
838
839 child_size
840 })
841 });
842
843 if self.ctx.is_pending_reinit() {
844 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
845 }
846
847 final_size
848 }
849
850 fn render(&mut self, frame: &mut FrameBuilder) {
851 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
852 #[cfg(debug_assertions)]
853 if !self.inited {
854 tracing::error!(target: "widget_base", "`UiNode::render` called in not inited widget {:?}", WIDGET.id());
855 } else if !self.info_built {
856 tracing::error!(target: "widget_base", "`UiNode::render` called in widget {:?} before first info build", WIDGET.id());
857 }
858
859 frame.push_widget(|frame| self.child.render(frame));
860 });
861
862 if self.ctx.is_pending_reinit() {
863 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
864 }
865 }
866
867 fn render_update(&mut self, update: &mut FrameUpdate) {
868 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
869 #[cfg(debug_assertions)]
870 if !self.inited {
871 tracing::error!(target: "widget_base", "`UiNode::render_update` called in not inited widget {:?}", WIDGET.id());
872 } else if !self.info_built {
873 tracing::error!(target: "widget_base", "`UiNode::render_update` called in widget {:?} before first info build", WIDGET.id());
874 }
875
876 update.update_widget(|update| self.child.render_update(update));
877 });
878
879 if self.ctx.is_pending_reinit() {
880 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
881 }
882 }
883
884 fn is_widget(&self) -> bool {
885 true
886 }
887
888 fn with_context<R, F>(&mut self, update_mode: WidgetUpdateMode, f: F) -> Option<R>
889 where
890 F: FnOnce() -> R,
891 {
892 WIDGET.with_context(&mut self.ctx, update_mode, || Some(f()))
893 }
894
895 fn into_widget(self) -> BoxedUiNode
896 where
897 Self: Sized,
898 {
899 self.boxed()
900 }
901 }
902
903 WidgetNode {
904 ctx: WidgetCtx::new(id.into()),
905 child: child.cfg_boxed(),
906
907 #[cfg(debug_assertions)]
908 inited: false,
909 #[cfg(debug_assertions)]
910 info_built: false,
911 }
912 .cfg_boxed()
913 }
914}
915
916#[property(CONTEXT, capture, default(WidgetId::new_unique()), widget_impl(WidgetBase))]
920pub fn id(id: impl IntoValue<WidgetId>) {}
921
922#[derive(Copy, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
924pub enum HitTestMode {
925 Disabled,
930 Bounds,
933 #[default]
937 RoundedBounds,
938 Detailed,
943}
944impl HitTestMode {
945 pub fn is_hit_testable(&self) -> bool {
949 !matches!(self, Self::Disabled)
950 }
951}
952impl fmt::Debug for HitTestMode {
953 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954 if f.alternate() {
955 write!(f, "HitTestMode::")?;
956 }
957 match self {
958 Self::Disabled => write!(f, "Disabled"),
959 Self::Bounds => write!(f, "Bounds"),
960 Self::RoundedBounds => write!(f, "RoundedBounds"),
961 Self::Detailed => write!(f, "Detailed"),
962 }
963 }
964}
965impl_from_and_into_var! {
966 fn from(default_or_disabled: bool) -> HitTestMode {
967 if default_or_disabled {
968 HitTestMode::default()
969 } else {
970 HitTestMode::Disabled
971 }
972 }
973}
974
975bitflags::bitflags! {
976 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
978 #[serde(transparent)]
979 pub struct Parallel: u8 {
980 const INIT = 0b0000_0001;
982 const INFO = 0b0001_0000;
984 const DEINIT = 0b0000_0010;
986 const EVENT = 0b0000_0100;
988 const UPDATE = 0b0000_1000;
990 const LAYOUT = 0b0010_0000;
992 const RENDER = 0b0100_0000;
994 }
995}
996impl Default for Parallel {
997 fn default() -> Self {
998 Self::all()
999 }
1000}
1001context_var! {
1002 pub static PARALLEL_VAR: Parallel = Parallel::default();
1008
1009 pub static HIT_TEST_MODE_VAR: HitTestMode = HitTestMode::default();
1018}
1019impl_from_and_into_var! {
1020 fn from(all: bool) -> Parallel {
1021 if all {
1022 Parallel::all()
1023 } else {
1024 Parallel::empty()
1025 }
1026 }
1027}