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