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::{IntoValue, Var, 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) -> UiNode {
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: Var<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: Var<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
448 use crate::{
449 render::{FrameBuilder, FrameUpdate, FrameValueKey},
450 update::{EventUpdate, WidgetUpdates},
451 widget::{
452 WidgetCtx, WidgetUpdateMode,
453 info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
454 node::{IntoUiNode, UiNode, UiNodeImpl, WidgetUiNodeImpl},
455 },
456 };
457
458 use super::*;
459
460 pub fn include_intrinsics(wgt: &mut WidgetBuilder) {
462 wgt.push_build_action(|wgt| {
463 wgt.push_intrinsic(NestGroup::CHILD, "widget_child", node::widget_child);
464 wgt.push_intrinsic(NestGroup::WIDGET_INNER, "widget_inner", node::widget_inner);
465 });
466 }
467
468 pub fn build(mut wgt: WidgetBuilder) -> UiNode {
476 let id = wgt.capture_value_or_else(property_id!(id), WidgetId::new_unique);
477 let child = wgt.build();
478 node::widget(child, id)
479 }
480
481 pub fn widget_child(child: impl IntoUiNode) -> UiNode {
492 let key = FrameValueKey::new_unique();
493 let mut define_ref_frame = false;
494
495 match_node(child, move |child, op| match op {
496 UiNodeOp::Measure { wm, desired_size } => {
497 *desired_size = child.measure(wm);
498
499 if let Some(inline) = wm.inline()
500 && inline.is_default()
501 && let Some(child_inline) = child
502 .node()
503 .as_widget()
504 .and_then(|mut w| w.with_context(WidgetUpdateMode::Ignore, || WIDGET.bounds().measure_inline()))
505 {
506 *inline = child_inline;
508 }
509 }
510 UiNodeOp::Layout { wl, final_size } => {
511 let (s, d) = wl.with_child(|wl| child.layout(wl));
512 *final_size = s;
513
514 if d != define_ref_frame {
515 define_ref_frame = d;
516 WIDGET.render();
517 }
518
519 if !define_ref_frame {
520 if let Some(inline) = wl.inline()
522 && inline.is_default()
523 && let Some(mut wgt) = child.node().as_widget()
524 {
525 wgt.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 UiNodeOp::Render { frame } => {
537 let offset = WIDGET.bounds().child_offset();
538 if define_ref_frame {
539 frame.push_reference_frame(key.into(), key.bind(offset.into(), true), true, false, |frame| child.render(frame));
540 } else {
541 frame.push_child(offset, |frame| {
542 child.render(frame);
543 });
544 }
545 }
546 UiNodeOp::RenderUpdate { update } => {
547 let offset = WIDGET.bounds().child_offset();
548 if define_ref_frame {
549 update.with_transform(key.update(offset.into(), true), false, |update| child.render_update(update));
550 } else {
551 update.with_child(offset, |update| child.render_update(update))
552 }
553 }
554 _ => {}
555 })
556 }
557
558 pub fn widget_inner(child: impl IntoUiNode) -> UiNode {
566 #[derive(Default, PartialEq)]
567 struct HitClips {
568 bounds: PxSize,
569 corners: PxCornerRadius,
570 }
571
572 let transform_key = FrameValueKey::new_unique();
573 let mut clips = HitClips::default();
574
575 match_node(child, move |child, op| match op {
576 UiNodeOp::Init => {
577 WIDGET.sub_var_layout(&HIT_TEST_MODE_VAR);
578 }
579 UiNodeOp::Layout { wl, final_size } => {
580 *final_size = wl.with_inner(|wl| child.layout(wl));
581
582 let mode = HIT_TEST_MODE_VAR.get();
583 let c = if matches!(mode, HitTestMode::Bounds | HitTestMode::RoundedBounds) {
584 HitClips {
585 bounds: *final_size,
586 corners: if matches!(mode, HitTestMode::RoundedBounds) {
587 WIDGET.border().corner_radius()
588 } else {
589 PxCornerRadius::zero()
590 },
591 }
592 } else {
593 HitClips::default()
594 };
595
596 if c != clips {
597 clips = c;
598 WIDGET.render();
599 }
600 }
601 UiNodeOp::Render { frame } => {
602 frame.push_inner(transform_key, true, |frame| {
603 frame.hit_test().push_clips(
604 |c| {
605 if let Some(inline) = WIDGET.bounds().inline() {
606 for r in inline.negative_space().iter() {
607 c.push_clip_rect(*r, true);
608 }
609 }
610 },
611 |h| match HIT_TEST_MODE_VAR.get() {
612 HitTestMode::RoundedBounds => {
613 h.push_rounded_rect(PxRect::from_size(clips.bounds), clips.corners);
614 }
615 HitTestMode::Bounds => {
616 h.push_rect(PxRect::from_size(clips.bounds));
617 }
618 _ => {}
619 },
620 );
621
622 child.render(frame);
623 });
624 }
625 UiNodeOp::RenderUpdate { update } => {
626 update.update_inner(transform_key, true, |update| child.render_update(update));
627 }
628 _ => {}
629 })
630 }
631
632 pub fn widget(child: impl IntoUiNode, id: impl IntoValue<WidgetId>) -> UiNode {
642 struct WidgetNode {
643 ctx: WidgetCtx,
644 child: UiNode,
645
646 #[cfg(debug_assertions)]
647 inited: bool,
648 #[cfg(debug_assertions)]
649 info_built: bool,
650 }
651 impl WidgetUiNodeImpl for WidgetNode {
652 fn with_context(&mut self, update_mode: WidgetUpdateMode, visitor: &mut dyn FnMut()) {
653 WIDGET.with_context(&mut self.ctx, update_mode, visitor);
654 }
655 }
656 impl UiNodeImpl for WidgetNode {
657 fn children_len(&self) -> usize {
658 1
659 }
660
661 fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
662 if index == 0 {
663 visitor(&mut self.child);
664 }
665 }
666
667 fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
668 Some(self)
669 }
670
671 fn init(&mut self) {
672 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
673 #[cfg(debug_assertions)]
674 if self.inited {
675 tracing::error!(target: "widget_base", "`UiNode::init` called in inited widget {:?}", WIDGET.id());
676 }
677
678 self.child.init();
679 WIDGET.update_info().layout().render();
680
681 #[cfg(debug_assertions)]
682 {
683 self.inited = true;
684 self.info_built = false;
685 }
686 });
687 self.ctx.take_reinit(); }
689
690 fn deinit(&mut self) {
691 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
692 #[cfg(debug_assertions)]
693 if !self.inited {
694 tracing::error!(target: "widget_base", "`UiNode::deinit` called in not inited widget {:?}", WIDGET.id());
695 }
696
697 self.child.deinit();
698 WIDGET.update_info().layout().render();
699
700 #[cfg(debug_assertions)]
701 {
702 self.inited = false;
703 self.info_built = false;
704 }
705 });
706 self.ctx.deinit(cfg!(any(test, feature = "test_util")));
707 }
708
709 fn info(&mut self, info: &mut WidgetInfoBuilder) {
710 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
711 #[cfg(debug_assertions)]
712 if !self.inited {
713 tracing::error!(target: "widget_base", "`UiNode::info` called in not inited widget {:?}", WIDGET.id());
714 }
715
716 #[cfg(debug_assertions)]
717 {
718 self.info_built = true;
719 }
720
721 info.push_widget(|info| {
722 self.child.info(info);
723 });
724 });
725
726 if self.ctx.is_pending_reinit() {
727 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
728 }
729 }
730
731 fn event(&mut self, update: &EventUpdate) {
732 if self.ctx.take_reinit() {
733 self.deinit();
734 self.init();
735 }
736
737 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
738 #[cfg(debug_assertions)]
739 if !self.inited {
740 tracing::error!(target: "widget_base", "`UiNode::event::<{}>` called in not inited widget {:?}", update.event().name(), WIDGET.id());
741 } else if !self.info_built {
742 tracing::error!(target: "widget_base", "`UiNode::event::<{}>` called in widget {:?} before first info build", update.event().name(), WIDGET.id());
743 }
744
745 update.with_widget(|| {
746 self.child.event(update);
747 });
748 });
749
750 if self.ctx.take_reinit() {
751 self.deinit();
752 self.init();
753 }
754 }
755
756 fn update(&mut self, updates: &WidgetUpdates) {
757 if self.ctx.take_reinit() {
758 self.deinit();
759 self.init();
760 return;
761 }
762
763 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
764 #[cfg(debug_assertions)]
765 if !self.inited {
766 tracing::error!(target: "widget_base", "`UiNode::update` called in not inited widget {:?}", WIDGET.id());
767 } else if !self.info_built {
768 tracing::error!(target: "widget_base", "`UiNode::update` called in widget {:?} before first info build", WIDGET.id());
769 }
770
771 updates.with_widget(|| {
772 self.child.update(updates);
773 });
774 });
775
776 if self.ctx.take_reinit() {
777 self.deinit();
778 self.init();
779 }
780 }
781
782 fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
783 let desired_size = WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Ignore, || {
784 #[cfg(debug_assertions)]
785 if !self.inited {
786 tracing::error!(target: "widget_base", "`UiNode::measure` called in not inited widget {:?}", WIDGET.id());
787 } else if !self.info_built {
788 tracing::error!(target: "widget_base", "`UiNode::measure` called in widget {:?} before first info build", WIDGET.id());
789 }
790
791 wm.with_widget(|wm| {
792 let child_size = self.child.measure(wm);
793
794 #[cfg(debug_assertions)]
796 if let Some(inline) = wm.inline() {
797 for (name, size, segs) in [
798 ("first", inline.first, &inline.first_segs),
799 ("last", inline.last, &inline.last_segs),
800 ] {
801 let width = size.width.0 as f32;
802 let sum_width = segs.iter().map(|s| s.width).sum::<f32>();
803 if sum_width > width + 0.1 {
804 tracing::error!(
805 "widget {:?} measured inline {name} row has {width} width, but row segs sum to {sum_width} width",
806 WIDGET.id()
807 );
808 }
809 }
810 }
811
812 child_size
813 })
814 });
815
816 let _ = self.ctx.take_reinit();
818
819 desired_size
820 }
821
822 fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
823 let final_size = WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
824 #[cfg(debug_assertions)]
825 if !self.inited {
826 tracing::error!(target: "widget_base", "`UiNode::layout` called in not inited widget {:?}", WIDGET.id());
827 } else if !self.info_built {
828 tracing::error!(target: "widget_base", "`UiNode::layout` called in widget {:?} before first info build", WIDGET.id());
829 }
830
831 wl.with_widget(|wl| {
832 let child_size = self.child.layout(wl);
833
834 #[cfg(debug_assertions)]
836 if let Some(inline) = wl.inline() {
837 use zng_layout::unit::Px;
838
839 for (name, row, segs) in inline
840 .rows
841 .first()
842 .iter()
843 .map(|r| ("first", r, &inline.first_segs))
844 .chain(inline.rows.last().iter().map(|r| ("last", r, &inline.last_segs)))
845 {
846 let width = row.width();
847 let sum_width = segs.iter().map(|s| s.width).sum::<Px>();
848 if (sum_width - width) > Px(1) {
849 tracing::error!(
850 "widget {:?} layout inline {name} row has {width} width, but row segs widths sum to {sum_width}",
851 WIDGET.id()
852 );
853 }
854 }
855 }
856
857 child_size
858 })
859 });
860
861 if self.ctx.is_pending_reinit() {
862 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
863 }
864
865 final_size
866 }
867
868 fn render(&mut self, frame: &mut FrameBuilder) {
869 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
870 #[cfg(debug_assertions)]
871 if !self.inited {
872 tracing::error!(target: "widget_base", "`UiNode::render` called in not inited widget {:?}", WIDGET.id());
873 } else if !self.info_built {
874 tracing::error!(target: "widget_base", "`UiNode::render` called in widget {:?} before first info build", WIDGET.id());
875 }
876
877 frame.push_widget(|frame| self.child.render(frame));
878 });
879
880 if self.ctx.is_pending_reinit() {
881 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
882 }
883 }
884
885 fn render_update(&mut self, update: &mut FrameUpdate) {
886 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
887 #[cfg(debug_assertions)]
888 if !self.inited {
889 tracing::error!(target: "widget_base", "`UiNode::render_update` called in not inited widget {:?}", WIDGET.id());
890 } else if !self.info_built {
891 tracing::error!(target: "widget_base", "`UiNode::render_update` called in widget {:?} before first info build", WIDGET.id());
892 }
893
894 update.update_widget(|update| self.child.render_update(update));
895 });
896
897 if self.ctx.is_pending_reinit() {
898 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
899 }
900 }
901 }
902
903 WidgetNode {
904 ctx: WidgetCtx::new(id.into()),
905 child: child.into_node(),
906
907 #[cfg(debug_assertions)]
908 inited: false,
909 #[cfg(debug_assertions)]
910 info_built: false,
911 }
912 .into_node()
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 { Parallel::all() } else { Parallel::empty() }
1022 }
1023}