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 #[cfg(debug_assertions)]
664 update_id: zng_var::VarUpdateId,
665 }
666 impl WidgetUiNodeImpl for WidgetNode {
667 fn with_context(&mut self, update_mode: WidgetUpdateMode, visitor: &mut dyn FnMut()) {
668 WIDGET.with_context(&mut self.ctx, update_mode, visitor);
669 }
670 }
671 impl UiNodeImpl for WidgetNode {
672 fn children_len(&self) -> usize {
673 1
674 }
675
676 fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
677 if index == 0 {
678 visitor(&mut self.child);
679 }
680 }
681
682 fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
683 Some(self)
684 }
685
686 fn init(&mut self) {
687 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
688 #[cfg(debug_assertions)]
689 if self.inited {
690 tracing::error!(target: "widget_base", "`UiNode::init` called in inited widget {:?}", WIDGET.id());
691 }
692
693 self.child.init();
694 WIDGET.update_info().layout().render();
695
696 #[cfg(debug_assertions)]
697 {
698 self.inited = true;
699 self.info_built = false;
700 }
701 });
702 self.ctx.take_reinit(); }
704
705 fn deinit(&mut self) {
706 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
707 #[cfg(debug_assertions)]
708 if !self.inited {
709 tracing::error!(target: "widget_base", "`UiNode::deinit` called in not inited widget {:?}", WIDGET.id());
710 }
711
712 self.child.deinit();
713 WIDGET.update_info().layout().render();
714
715 #[cfg(debug_assertions)]
716 {
717 self.inited = false;
718 self.info_built = false;
719 }
720 });
721 self.ctx.deinit(cfg!(any(test, feature = "test_util")));
722 }
723
724 fn info(&mut self, info: &mut WidgetInfoBuilder) {
725 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
726 #[cfg(debug_assertions)]
727 if !self.inited {
728 tracing::error!(target: "widget_base", "`UiNode::info` called in not inited widget {:?}", WIDGET.id());
729 }
730
731 #[cfg(debug_assertions)]
732 {
733 self.info_built = true;
734 }
735
736 info.push_widget(|info| {
737 self.child.info(info);
738 });
739 });
740
741 if self.ctx.is_pending_reinit() {
742 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
743 }
744 }
745
746 fn update(&mut self, updates: &WidgetUpdates) {
747 if self.ctx.take_reinit() {
748 self.deinit();
749 self.init();
750 return;
751 }
752
753 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
754 #[cfg(debug_assertions)]
755 {
756 if !self.inited {
757 tracing::error!(target: "widget_base", "`UiNode::update` called in not inited widget {:?}", WIDGET.id());
758 } else if !self.info_built {
759 tracing::error!(target: "widget_base", "`UiNode::update` called in widget {:?} before first info build", WIDGET.id());
760 }
761 let update_id = crate::update::UPDATES.update_id();
762 if self.update_id == update_id {
763 tracing::error!(target: "widget_base", "`UiNode::update` called again in widget {:?} for pass {:?}", WIDGET.id(), update_id);
764 } else {
765 self.update_id = update_id;
766 }
767 }
768
769 updates.with_widget(|| {
770 self.child.update(updates);
771 });
772 });
773
774 if self.ctx.take_reinit() {
775 self.deinit();
776 self.init();
777 }
778 }
779
780 fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
781 let desired_size = WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Ignore, || {
782 #[cfg(debug_assertions)]
783 if !self.inited {
784 tracing::error!(target: "widget_base", "`UiNode::measure` called in not inited widget {:?}", WIDGET.id());
785 } else if !self.info_built {
786 tracing::error!(target: "widget_base", "`UiNode::measure` called in widget {:?} before first info build", WIDGET.id());
787 }
788
789 wm.with_widget(|wm| {
790 let child_size = self.child.measure(wm);
791
792 #[cfg(debug_assertions)]
794 if let Some(inline) = wm.inline() {
795 for (name, size, segs) in [
796 ("first", inline.first, &inline.first_segs),
797 ("last", inline.last, &inline.last_segs),
798 ] {
799 let width = size.width.0 as f32;
800 let sum_width = segs.iter().map(|s| s.width).sum::<f32>();
801 if sum_width > width + 0.1 {
802 tracing::error!(
803 "widget {:?} measured inline {name} row has {width} width, but row segs sum to {sum_width} width",
804 WIDGET.id()
805 );
806 }
807 }
808 }
809
810 child_size
811 })
812 });
813
814 let _ = self.ctx.take_reinit();
816
817 desired_size
818 }
819
820 fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
821 let final_size = WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
822 #[cfg(debug_assertions)]
823 if !self.inited {
824 tracing::error!(target: "widget_base", "`UiNode::layout` called in not inited widget {:?}", WIDGET.id());
825 } else if !self.info_built {
826 tracing::error!(target: "widget_base", "`UiNode::layout` called in widget {:?} before first info build", WIDGET.id());
827 }
828
829 wl.with_widget(|wl| {
830 let child_size = self.child.layout(wl);
831
832 #[cfg(debug_assertions)]
834 if let Some(inline) = wl.inline() {
835 use zng_layout::unit::Px;
836
837 for (name, row, segs) in inline
838 .rows
839 .first()
840 .iter()
841 .map(|r| ("first", r, &inline.first_segs))
842 .chain(inline.rows.last().iter().map(|r| ("last", r, &inline.last_segs)))
843 {
844 let width = row.width();
845 let sum_width = segs.iter().map(|s| s.width).sum::<Px>();
846 if (sum_width - width) > Px(1) {
847 tracing::error!(
848 "widget {:?} layout inline {name} row has {width} width, but row segs widths sum to {sum_width}",
849 WIDGET.id()
850 );
851 }
852 }
853 }
854
855 child_size
856 })
857 });
858
859 if self.ctx.is_pending_reinit() {
860 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
861 }
862
863 final_size
864 }
865
866 fn render(&mut self, frame: &mut FrameBuilder) {
867 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
868 #[cfg(debug_assertions)]
869 if !self.inited {
870 tracing::error!(target: "widget_base", "`UiNode::render` called in not inited widget {:?}", WIDGET.id());
871 } else if !self.info_built {
872 tracing::error!(target: "widget_base", "`UiNode::render` called in widget {:?} before first info build", WIDGET.id());
873 }
874
875 frame.push_widget(|frame| self.child.render(frame));
876 });
877
878 if self.ctx.is_pending_reinit() {
879 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
880 }
881 }
882
883 fn render_update(&mut self, update: &mut FrameUpdate) {
884 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || {
885 #[cfg(debug_assertions)]
886 if !self.inited {
887 tracing::error!(target: "widget_base", "`UiNode::render_update` called in not inited widget {:?}", WIDGET.id());
888 } else if !self.info_built {
889 tracing::error!(target: "widget_base", "`UiNode::render_update` called in widget {:?} before first info build", WIDGET.id());
890 }
891
892 update.update_widget(|update| self.child.render_update(update));
893 });
894
895 if self.ctx.is_pending_reinit() {
896 WIDGET.with_context(&mut self.ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
897 }
898 }
899 }
900
901 WidgetNode {
902 ctx: WidgetCtx::new(id.into()),
903 child: child.into_node(),
904
905 #[cfg(debug_assertions)]
906 inited: false,
907 #[cfg(debug_assertions)]
908 info_built: false,
909 #[cfg(debug_assertions)]
910 update_id: zng_var::VarUpdateId::never(),
911 }
912 .into_node()
913 }
914}
915
916#[property(CONTEXT, default(WidgetId::new_unique()), widget_impl(WidgetBase))]
920pub fn id(wgt: &mut WidgetBuilding, id: impl IntoValue<WidgetId>) {
921 let _ = id;
922 wgt.expect_property_capture();
923}
924
925#[derive(Copy, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
927pub enum HitTestMode {
928 Disabled,
933 Bounds,
936 #[default]
940 RoundedBounds,
941 Detailed,
946}
947impl HitTestMode {
948 pub fn is_hit_testable(&self) -> bool {
952 !matches!(self, Self::Disabled)
953 }
954}
955impl fmt::Debug for HitTestMode {
956 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
957 if f.alternate() {
958 write!(f, "HitTestMode::")?;
959 }
960 match self {
961 Self::Disabled => write!(f, "Disabled"),
962 Self::Bounds => write!(f, "Bounds"),
963 Self::RoundedBounds => write!(f, "RoundedBounds"),
964 Self::Detailed => write!(f, "Detailed"),
965 }
966 }
967}
968impl_from_and_into_var! {
969 fn from(default_or_disabled: bool) -> HitTestMode {
970 if default_or_disabled {
971 HitTestMode::default()
972 } else {
973 HitTestMode::Disabled
974 }
975 }
976}
977impl Transitionable for HitTestMode {
978 fn lerp(self, to: &Self, step: zng_var::animation::easing::EasingStep) -> Self {
979 if step >= 1.fct() { *to } else { self }
980 }
981}
982
983bitflags::bitflags! {
984 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
986 #[serde(transparent)]
987 pub struct Parallel: u8 {
988 const INIT = 0b0000_0001;
990 const INFO = 0b0001_0000;
992 const DEINIT = 0b0000_0010;
994 const UPDATE = 0b0000_1000;
996 const LAYOUT = 0b0010_0000;
998 const RENDER = 0b0100_0000;
1000 }
1001}
1002impl Default for Parallel {
1003 fn default() -> Self {
1004 Self::all()
1005 }
1006}
1007context_var! {
1008 pub static PARALLEL_VAR: Parallel = Parallel::default();
1014
1015 pub static HIT_TEST_MODE_VAR: HitTestMode = HitTestMode::default();
1024}
1025impl_from_and_into_var! {
1026 fn from(all: bool) -> Parallel {
1027 if all { Parallel::all() } else { Parallel::empty() }
1028 }
1029}