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