1use crate::{handler::WidgetHandler, widget::node::IntoUiNode};
4use std::{
5 any::{Any, TypeId},
6 collections::{HashMap, hash_map},
7 fmt, ops,
8 sync::Arc,
9};
10
11#[doc(hidden)]
12pub use zng_var::{var_getter, var_state};
13
14#[macro_export]
18macro_rules! source_location {
19 () => {
20 $crate::widget::builder::SourceLocation::new(std::file!(), std::line!(), std::column!())
21 };
22}
23#[doc(inline)]
24pub use crate::source_location;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
32#[non_exhaustive]
33pub struct SourceLocation {
34 pub file: &'static str,
36 pub line: u32,
38 pub column: u32,
40}
41
42impl SourceLocation {
43 #[doc(hidden)]
44 pub fn new(file: &'static str, line: u32, column: u32) -> Self {
45 Self { file, line, column }
46 }
47}
48impl fmt::Display for SourceLocation {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "{}:{}:{}", self.file, self.line, self.column)
51 }
52}
53
54#[doc(hidden)]
55pub struct WgtInfo;
56impl WidgetExt for WgtInfo {
57 fn ext_property__(&mut self, _: Box<dyn PropertyArgs>) {
58 panic!("WgtInfo is for extracting info only")
59 }
60
61 fn ext_property_unset__(&mut self, _: PropertyId) {
62 panic!("WgtInfo is for extracting info only")
63 }
64}
65
66#[macro_export]
99macro_rules! property_id {
100 ($($tt:tt)*) => {
101 $crate::widget::property_meta!($($tt)*).id()
102 }
103}
104#[doc(inline)]
105pub use crate::property_id;
106
107#[macro_export]
134macro_rules! property_info {
135 ($($property:ident)::+ <$($generics:ty),*>) => {
136 $crate::widget::property_meta!($($property)::+).info::<$($generics),*>()
137 };
138 ($($tt:tt)*) => {
139 $crate::widget::property_meta!($($tt)*).info()
140 }
141}
142#[doc(inline)]
143pub use crate::property_info;
144
145#[macro_export]
154macro_rules! property_input_types {
155 ($($tt:tt)*) => {
156 $crate::widget::property_meta!($($tt)*).input_types()
157 }
158}
159#[doc(inline)]
160pub use crate::property_input_types;
161
162#[macro_export]
180macro_rules! property_args {
181 ($($property:ident)::+ = $($value:tt)*) => {
182 {
183 $crate::widget::builder::PropertyArgsGetter! {
184 $($property)::+ = $($value)*
185 }
186 }
187 };
188 ($($property:ident)::+ ::<$($generics:ty),*> = $($value:tt)*) => {
189 {
190 $crate::widget::builder::PropertyArgsGetter! {
191 $($property)::+ ::<$($generics),*> = $($value)*
192 }
193 }
194 };
195 ($property:ident $(;)?) => {
196 {
197 $crate::widget::builder::PropertyArgsGetter! {
198 $property
199 }
200 }
201 }
202}
203#[doc(inline)]
204pub use crate::property_args;
205
206#[macro_export]
208macro_rules! widget_type {
209 ($($widget:ident)::+) => {
210 $($widget)::+::widget_type()
211 };
212}
213use parking_lot::Mutex;
214#[doc(inline)]
215pub use widget_type;
216use zng_app_context::context_local;
217use zng_app_proc_macros::widget;
218use zng_txt::{Txt, formatx};
219use zng_unique_id::{IdEntry, IdMap, IdSet, unique_id_32};
220use zng_var::{
221 AnyVar, AnyVarValue, AnyWhenVarBuilder, ContextInitHandle, IntoValue, IntoVar, Var, VarValue, WeakContextInitHandle, any_const_var,
222 const_var, contextual_var, impl_from_and_into_var,
223};
224
225use super::{
226 base::{WidgetBase, WidgetExt},
227 node::{ArcNode, FillUiNode, UiNode, WhenUiNodeBuilder, with_new_context_init_id},
228};
229
230#[doc(hidden)]
231#[widget($crate::widget::builder::PropertyArgsGetter)]
232pub struct PropertyArgsGetter(WidgetBase);
233impl PropertyArgsGetter {
234 pub fn widget_build(&mut self) -> Box<dyn PropertyArgs> {
235 let mut wgt = self.widget_take();
236 if !wgt.p.items.is_empty() {
237 if wgt.p.items.len() > 1 {
238 tracing::error!("properties ignored, `property_args!` only collects args for first property");
239 }
240 match wgt.p.items.remove(0).item {
241 WidgetItem::Property { args, .. } => args,
242 WidgetItem::Intrinsic { .. } => unreachable!(),
243 }
244 } else if wgt.unset.is_empty() {
245 panic!("missing property");
246 } else {
247 panic!("cannot use `unset!` in `property_args!`")
248 }
249 }
250}
251
252#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
256pub struct NestPosition {
257 pub group: NestGroup,
259 pub index: u16,
261}
262impl NestPosition {
263 pub const INTRINSIC_INDEX: u16 = u16::MAX / 3;
265
266 pub const PROPERTY_INDEX: u16 = Self::INTRINSIC_INDEX * 2;
268
269 pub fn property(group: NestGroup) -> Self {
271 NestPosition {
272 group,
273 index: Self::PROPERTY_INDEX,
274 }
275 }
276
277 pub fn intrinsic(group: NestGroup) -> Self {
279 NestPosition {
280 group,
281 index: Self::INTRINSIC_INDEX,
282 }
283 }
284}
285impl fmt::Debug for NestPosition {
286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287 struct IndexName(u16);
288 impl fmt::Debug for IndexName {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 match self.0 {
291 NestPosition::INTRINSIC_INDEX => write!(f, "INTRINSIC_INDEX"),
292 NestPosition::PROPERTY_INDEX => write!(f, "PROPERTY_INDEX"),
293 i => write!(f, "{i}"),
294 }
295 }
296 }
297
298 f.debug_struct("NestPosition")
299 .field("group", &self.group)
300 .field("index", &IndexName(self.index))
301 .finish()
302 }
303}
304
305macro_rules! nest_group_items {
306 () => {
307 pub const WIDGET: NestGroup = NestGroup(0);
311
312 pub const CONTEXT: NestGroup = NestGroup(NestGroup::NEXT_GROUP);
319 pub const EVENT: NestGroup = NestGroup(NestGroup::CONTEXT.0 + NestGroup::NEXT_GROUP);
327 pub const LAYOUT: NestGroup = NestGroup(NestGroup::EVENT.0 + NestGroup::NEXT_GROUP);
332
333 pub const SIZE: NestGroup = NestGroup(NestGroup::LAYOUT.0 + NestGroup::NEXT_GROUP);
338
339 pub const WIDGET_INNER: NestGroup = NestGroup(NestGroup::SIZE.0 + NestGroup::NEXT_GROUP);
345
346 pub const BORDER: NestGroup = NestGroup(NestGroup::WIDGET_INNER.0 + NestGroup::NEXT_GROUP);
353 pub const FILL: NestGroup = NestGroup(NestGroup::BORDER.0 + NestGroup::NEXT_GROUP);
358 pub const CHILD_CONTEXT: NestGroup = NestGroup(NestGroup::FILL.0 + NestGroup::NEXT_GROUP);
361 pub const CHILD_LAYOUT: NestGroup = NestGroup(NestGroup::CHILD_CONTEXT.0 + NestGroup::NEXT_GROUP);
365
366 pub const CHILD: NestGroup = NestGroup(u16::MAX);
371 };
372}
373
374#[doc(hidden)]
375pub mod nest_group_items {
376 use super::NestGroup;
380
381 nest_group_items!();
382}
383
384#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
391pub struct NestGroup(u16);
392impl NestGroup {
393 const NEXT_GROUP: u16 = u16::MAX / 10;
394
395 nest_group_items!();
396
397 pub const ITEMS: [Self; 11] = [
402 Self::WIDGET,
403 Self::CONTEXT,
404 Self::EVENT,
405 Self::LAYOUT,
406 Self::SIZE,
407 Self::WIDGET_INNER,
408 Self::BORDER,
409 Self::FILL,
410 Self::CHILD_CONTEXT,
411 Self::CHILD_LAYOUT,
412 Self::CHILD,
413 ];
414
415 fn exact_name(self) -> &'static str {
416 if self.0 == Self::WIDGET.0 {
417 "WIDGET"
418 } else if self.0 == Self::CONTEXT.0 {
419 "CONTEXT"
420 } else if self.0 == Self::EVENT.0 {
421 "EVENT"
422 } else if self.0 == Self::LAYOUT.0 {
423 "LAYOUT"
424 } else if self.0 == Self::SIZE.0 {
425 "SIZE"
426 } else if self.0 == Self::WIDGET_INNER.0 {
427 "WIDGET_INNER"
428 } else if self.0 == Self::BORDER.0 {
429 "BORDER"
430 } else if self.0 == Self::FILL.0 {
431 "FILL"
432 } else if self.0 == Self::CHILD_CONTEXT.0 {
433 "CHILD_CONTEXT"
434 } else if self.0 == Self::CHILD_LAYOUT.0 {
435 "CHILD_LAYOUT"
436 } else if self.0 == Self::CHILD.0 {
437 "CHILD"
438 } else {
439 ""
440 }
441 }
442
443 pub fn name(self) -> Txt {
445 let name = self.exact_name();
446 if name.is_empty() {
447 let closest = Self::ITEMS.into_iter().min_by_key(|i| (self.0 as i32 - i.0 as i32).abs()).unwrap();
448 let diff = self.0 as i32 - closest.0 as i32;
449
450 let name = closest.exact_name();
451 debug_assert!(!name.is_empty());
452
453 formatx!("{closest}{diff:+}")
454 } else {
455 Txt::from_static(name)
456 }
457 }
458}
459impl fmt::Debug for NestGroup {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 if f.alternate() {
462 write!(f, "NestGroup::")?;
463 }
464 write!(f, "{}", self.name())
465 }
466}
467impl fmt::Display for NestGroup {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 write!(f, "{}", self.name())
470 }
471}
472impl ops::Add<i16> for NestGroup {
473 type Output = Self;
474
475 fn add(self, rhs: i16) -> Self::Output {
476 let r = (self.0 as i32) + rhs as i32;
477
478 Self(r.clamp(0, u16::MAX as i32) as u16)
479 }
480}
481impl ops::Sub<i16> for NestGroup {
482 type Output = Self;
483
484 fn sub(self, rhs: i16) -> Self::Output {
485 let r = (self.0 as i32) - rhs as i32;
486
487 Self(r.clamp(0, u16::MAX as i32) as u16)
488 }
489}
490impl ops::AddAssign<i16> for NestGroup {
491 fn add_assign(&mut self, rhs: i16) {
492 *self = *self + rhs;
493 }
494}
495impl ops::SubAssign<i16> for NestGroup {
496 fn sub_assign(&mut self, rhs: i16) {
497 *self = *self - rhs;
498 }
499}
500#[test]
501fn nest_group_spacing() {
502 let mut expected = NestGroup::NEXT_GROUP;
503 for g in &NestGroup::ITEMS[1..NestGroup::ITEMS.len() - 1] {
504 assert_eq!(expected, g.0);
505 expected += NestGroup::NEXT_GROUP;
506 }
507 assert_eq!(expected, (u16::MAX / 10) * 10); }
509#[derive(serde::Deserialize)]
510#[serde(untagged)]
511enum NestGroupSerde<'s> {
512 Named(&'s str),
513 Unnamed(u16),
514}
515impl serde::Serialize for NestGroup {
516 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
517 where
518 S: serde::Serializer,
519 {
520 if serializer.is_human_readable() {
521 self.name().serialize(serializer)
522 } else {
523 self.0.serialize(serializer)
524 }
525 }
526}
527impl<'de> serde::Deserialize<'de> for NestGroup {
528 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
529 where
530 D: serde::Deserializer<'de>,
531 {
532 use serde::de::Error;
533
534 match NestGroupSerde::deserialize(deserializer)? {
535 NestGroupSerde::Named(n) => match n.parse() {
536 Ok(g) => Ok(g),
537 Err(e) => Err(D::Error::custom(e)),
538 },
539 NestGroupSerde::Unnamed(i) => Ok(NestGroup(i)),
540 }
541 }
542}
543impl std::str::FromStr for NestGroup {
544 type Err = String;
545
546 fn from_str(s: &str) -> Result<Self, Self::Err> {
547 let mut name = s;
548 let mut add = 0i16;
549
550 if let Some((n, a)) = s.split_once('+') {
551 add = a.parse().map_err(|e| format!("{e}"))?;
552 name = n;
553 } else if let Some((n, s)) = s.split_once('-') {
554 add = -s.parse().map_err(|e| format!("{e}"))?;
555 name = n;
556 }
557
558 match name {
559 "WIDGET" => Ok(NestGroup::WIDGET + add),
560 "CONTEXT" => Ok(NestGroup::CONTEXT + add),
561 "EVENT" => Ok(NestGroup::EVENT + add),
562 "LAYOUT" => Ok(NestGroup::LAYOUT + add),
563 "SIZE" => Ok(NestGroup::SIZE + add),
564 "BORDER" => Ok(NestGroup::BORDER + add),
565 "FILL" => Ok(NestGroup::FILL + add),
566 "CHILD_CONTEXT" => Ok(NestGroup::CHILD_CONTEXT + add),
567 "CHILD_LAYOUT" => Ok(NestGroup::CHILD_LAYOUT + add),
568 "CHILD" => Ok(NestGroup::CHILD + add),
569 ukn => Err(format!("unknown nest group {ukn:?}")),
570 }
571 }
572}
573
574#[derive(PartialEq, Eq, Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
576pub enum InputKind {
577 Var,
579 Value,
581 UiNode,
583 WidgetHandler,
585}
586
587#[derive(Clone)]
596pub struct ArcWidgetHandler<A: Clone + 'static>(Arc<Mutex<dyn WidgetHandler<A>>>);
597impl<A: Clone + 'static> ArcWidgetHandler<A> {
598 pub fn new(handler: impl WidgetHandler<A>) -> Self {
600 Self(Arc::new(Mutex::new(handler)))
601 }
602}
603impl<A: Clone + 'static> WidgetHandler<A> for ArcWidgetHandler<A> {
604 #[inline(always)]
605 fn event(&mut self, args: &A) -> bool {
606 self.0.lock().event(args)
607 }
608
609 #[inline(always)]
610 fn update(&mut self) -> bool {
611 self.0.lock().update()
612 }
613}
614
615pub trait AnyArcWidgetHandler: Any {
617 fn as_any(&self) -> &dyn Any;
619
620 fn into_any(self: Box<Self>) -> Box<dyn Any>;
622
623 fn clone_boxed(&self) -> Box<dyn AnyArcWidgetHandler>;
625}
626impl<A: Clone + 'static> AnyArcWidgetHandler for ArcWidgetHandler<A> {
627 fn clone_boxed(&self) -> Box<dyn AnyArcWidgetHandler> {
628 Box::new(self.clone())
629 }
630
631 fn as_any(&self) -> &dyn Any {
632 self
633 }
634
635 fn into_any(self: Box<Self>) -> Box<dyn Any> {
636 self
637 }
638}
639
640pub struct AnyWhenArcWidgetHandlerBuilder {
644 default: Box<dyn AnyArcWidgetHandler>,
645 conditions: Vec<(Var<bool>, Box<dyn AnyArcWidgetHandler>)>,
646}
647impl AnyWhenArcWidgetHandlerBuilder {
648 pub fn new(default: Box<dyn AnyArcWidgetHandler>) -> Self {
650 Self {
651 default,
652 conditions: vec![],
653 }
654 }
655
656 pub fn push(&mut self, condition: Var<bool>, handler: Box<dyn AnyArcWidgetHandler>) {
658 self.conditions.push((condition, handler));
659 }
660
661 pub fn build<A: Clone + 'static>(self) -> ArcWidgetHandler<A> {
663 match self.default.into_any().downcast::<ArcWidgetHandler<A>>() {
664 Ok(default) => {
665 let mut conditions = Vec::with_capacity(self.conditions.len());
666 for (c, h) in self.conditions {
667 match h.into_any().downcast::<ArcWidgetHandler<A>>() {
668 Ok(h) => conditions.push((c, *h)),
669 Err(_) => continue,
670 }
671 }
672 ArcWidgetHandler::new(WhenWidgetHandler {
673 default: *default,
674 conditions,
675 })
676 }
677 Err(_) => panic!("unexpected build type in widget handler when builder"),
678 }
679 }
680}
681
682struct WhenWidgetHandler<A: Clone + 'static> {
683 default: ArcWidgetHandler<A>,
684 conditions: Vec<(Var<bool>, ArcWidgetHandler<A>)>,
685}
686impl<A: Clone + 'static> WidgetHandler<A> for WhenWidgetHandler<A> {
687 fn event(&mut self, args: &A) -> bool {
688 for (c, h) in &mut self.conditions {
689 if c.get() {
690 return h.event(args);
691 }
692 }
693 self.default.event(args)
694 }
695
696 fn update(&mut self) -> bool {
697 let mut pending = self.default.update();
698 for (_, h) in &mut self.conditions {
699 pending |= h.update();
700 }
701 pending
702 }
703}
704
705pub type PropertyBuildActions = Vec<Vec<Box<dyn AnyPropertyBuildAction>>>;
709
710pub type PropertyBuildActionsWhenData = Vec<Vec<Option<WhenBuildActionData>>>;
714
715#[non_exhaustive]
717pub struct PropertyNewArgs {
718 pub args: Vec<Box<dyn Any>>,
737
738 pub build_actions: PropertyBuildActions,
757
758 pub build_actions_when_data: PropertyBuildActionsWhenData,
764}
765
766#[derive(Debug, Clone)]
770pub struct PropertyInfo {
771 pub group: NestGroup,
773 pub capture: bool,
777
778 pub id: PropertyId,
780 pub name: &'static str,
782
783 pub location: SourceLocation,
785
786 pub default: Option<fn() -> Box<dyn PropertyArgs>>,
790
791 pub new: fn(PropertyNewArgs) -> Box<dyn PropertyArgs>,
801
802 pub inputs: Box<[PropertyInput]>,
804
805 #[doc(hidden)] pub _non_exhaustive: (),
807}
808impl PropertyInfo {
809 pub fn input_idx(&self, name: &str) -> Option<usize> {
811 self.inputs.iter().position(|i| i.name == name)
812 }
813}
814
815#[derive(Debug, Clone)]
817pub struct PropertyInput {
818 pub name: &'static str,
820 pub kind: InputKind,
822 pub ty: TypeId,
824 pub ty_name: &'static str,
826
827 #[doc(hidden)] pub _non_exhaustive: (),
829}
830impl PropertyInput {
831 pub fn display_ty_name(&self) -> Txt {
835 pretty_type_name::pretty_type_name_str(self.ty_name).into()
836 }
837}
838
839pub trait PropertyArgs: Send + Sync {
841 fn clone_boxed(&self) -> Box<dyn PropertyArgs>;
843
844 fn property(&self) -> PropertyInfo;
846
847 fn var(&self, i: usize) -> &AnyVar {
849 panic_input(&self.property(), i, InputKind::Var)
850 }
851
852 fn value(&self, i: usize) -> &dyn AnyVarValue {
854 panic_input(&self.property(), i, InputKind::Value)
855 }
856
857 fn ui_node(&self, i: usize) -> &ArcNode {
859 panic_input(&self.property(), i, InputKind::UiNode)
860 }
861
862 fn widget_handler(&self, i: usize) -> &dyn AnyArcWidgetHandler {
866 panic_input(&self.property(), i, InputKind::WidgetHandler)
867 }
868
869 fn instantiate(&self, child: UiNode) -> UiNode;
873}
874impl dyn PropertyArgs + '_ {
875 pub fn id(&self) -> PropertyId {
877 self.property().id
878 }
879
880 pub fn downcast_value<T>(&self, i: usize) -> &T
886 where
887 T: VarValue,
888 {
889 self.value(i).downcast_ref::<T>().expect("cannot downcast value to type")
890 }
891 pub fn downcast_var<T>(&self, i: usize) -> Var<T>
897 where
898 T: VarValue,
899 {
900 self.var(i)
901 .clone()
902 .downcast::<T>()
903 .unwrap_or_else(|_| panic!("cannot downcast var to type"))
904 }
905
906 pub fn downcast_handler<A>(&self, i: usize) -> &ArcWidgetHandler<A>
912 where
913 A: 'static + Clone,
914 {
915 self.widget_handler(i)
916 .as_any()
917 .downcast_ref::<ArcWidgetHandler<A>>()
918 .expect("cannot downcast handler to type")
919 }
920
921 pub fn live_debug(&self, i: usize) -> Var<Txt> {
927 let p = self.property();
928 match p.inputs[i].kind {
929 InputKind::Var => self.var(i).map_debug(false),
930 InputKind::Value => const_var(formatx!("{:?}", self.value(i))),
931 InputKind::UiNode => const_var(Txt::from_static("UiNode")),
932 InputKind::WidgetHandler => const_var(formatx!("<impl WidgetHandler<{}>>", p.inputs[i].display_ty_name())),
933 }
934 }
935
936 pub fn debug(&self, i: usize) -> Txt {
940 let p = self.property();
941 match p.inputs[i].kind {
942 InputKind::Var => formatx!("{:?}", self.var(i).get()),
943 InputKind::Value => formatx!("{:?}", self.value(i)),
944 InputKind::UiNode => Txt::from_static("UiNode"),
945 InputKind::WidgetHandler => formatx!("<impl WidgetHandler<{}>>", p.inputs[i].display_ty_name()),
946 }
947 }
948
949 pub fn new_build(
953 &self,
954 build_actions: PropertyBuildActions,
955 build_actions_when_data: PropertyBuildActionsWhenData,
956 ) -> Box<dyn PropertyArgs> {
957 let p = self.property();
958
959 let mut args: Vec<Box<dyn Any>> = Vec::with_capacity(p.inputs.len());
960 for (i, input) in p.inputs.iter().enumerate() {
961 match input.kind {
962 InputKind::Var => args.push(Box::new(self.var(i).clone())),
963 InputKind::Value => args.push(Box::new(self.value(i).clone_boxed())),
964 InputKind::UiNode => args.push(Box::new(self.ui_node(i).clone())),
965 InputKind::WidgetHandler => args.push(self.widget_handler(i).clone_boxed().into_any()),
966 }
967 }
968
969 (p.new)(PropertyNewArgs {
970 args,
971 build_actions,
972 build_actions_when_data,
973 })
974 }
975}
976
977#[doc(hidden)]
978pub fn panic_input(info: &PropertyInfo, i: usize, kind: InputKind) -> ! {
979 if i > info.inputs.len() {
980 panic!("index out of bounds, the input len is {}, but the index is {i}", info.inputs.len())
981 } else if info.inputs[i].kind != kind {
982 panic!(
983 "invalid input request `{:?}`, but `{}` is `{:?}`",
984 kind, info.inputs[i].name, info.inputs[i].kind
985 )
986 } else {
987 panic!("invalid input `{}`", info.inputs[i].name)
988 }
989}
990
991#[doc(hidden)]
992pub fn var_to_args<T: VarValue>(var: impl IntoVar<T>) -> Var<T> {
993 var.into_var()
994}
995
996#[doc(hidden)]
997pub fn value_to_args<T: VarValue>(value: impl IntoValue<T>) -> T {
998 value.into()
999}
1000
1001#[doc(hidden)]
1002pub fn ui_node_to_args(node: impl IntoUiNode) -> ArcNode {
1003 ArcNode::new(node)
1004}
1005
1006#[doc(hidden)]
1007pub fn widget_handler_to_args<A: Clone + 'static>(handler: impl WidgetHandler<A>) -> ArcWidgetHandler<A> {
1008 ArcWidgetHandler::new(handler)
1009}
1010
1011#[doc(hidden)]
1012pub fn iter_input_build_actions<'a>(
1013 actions: &'a PropertyBuildActions,
1014 data: &'a PropertyBuildActionsWhenData,
1015 index: usize,
1016) -> impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])> {
1017 let mut actions = actions.iter();
1018 let mut data = data.iter();
1019
1020 std::iter::from_fn(move || {
1021 let action = &*actions.next()?[index];
1022 let data = if let Some(data) = data.next() { &data[..] } else { &[] };
1023
1024 Some((action, data))
1025 })
1026}
1027
1028fn apply_build_actions<'a, I: Any + Send>(
1029 mut item: I,
1030 mut actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1031) -> I {
1032 if let Some((action, data)) = actions.next() {
1033 let action = action
1034 .as_any()
1035 .downcast_ref::<PropertyBuildAction<I>>()
1036 .expect("property build action type did not match expected var type");
1037
1038 item = action.build(PropertyBuildActionArgs {
1039 input: item,
1040 when_conditions_data: data,
1041 });
1042 }
1043 item
1044}
1045
1046#[doc(hidden)]
1047pub fn new_dyn_var<'a, T: VarValue>(
1048 inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1049 actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1050) -> Var<T> {
1051 let item = inputs.next().expect("missing input");
1052
1053 let item = match item.downcast::<AnyWhenVarBuilder>() {
1054 Ok(builder) => builder.into_typed::<T>().build(),
1055 Err(item) => {
1056 let any = *item.downcast::<AnyVar>().expect("input did not match expected var types");
1057 any.downcast::<T>().expect("input did not match expected var types")
1058 }
1059 };
1060
1061 apply_build_actions(item, actions)
1062}
1063
1064#[doc(hidden)]
1065pub fn new_dyn_ui_node<'a>(
1066 inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1067 actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1068) -> ArcNode {
1069 let item = inputs.next().expect("missing input");
1070
1071 let item = match item.downcast::<WhenUiNodeBuilder>() {
1072 Ok(builder) => ArcNode::new(builder.build()),
1073 Err(item) => *item.downcast::<ArcNode>().expect("input did not match expected UiNode types"),
1074 };
1075
1076 apply_build_actions(item, actions)
1077}
1078
1079#[doc(hidden)]
1080pub fn new_dyn_widget_handler<'a, A: Clone + 'static>(
1081 inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1082 actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1083) -> ArcWidgetHandler<A> {
1084 let item = inputs.next().expect("missing input");
1085
1086 let item = match item.downcast::<AnyWhenArcWidgetHandlerBuilder>() {
1087 Ok(builder) => builder.build(),
1088 Err(item) => *item
1089 .downcast::<ArcWidgetHandler<A>>()
1090 .expect("input did not match expected WidgetHandler types"),
1091 };
1092
1093 apply_build_actions(item, actions)
1094}
1095
1096#[doc(hidden)]
1097pub fn new_dyn_other<'a, T: Any + Send>(
1098 inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1099 actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1100) -> T {
1101 let item = *inputs
1102 .next()
1103 .expect("missing input")
1104 .downcast::<T>()
1105 .expect("input did not match expected var type");
1106
1107 apply_build_actions(item, actions)
1108}
1109
1110#[derive(Clone, PartialEq)]
1114pub struct UiNodeInWhenExprError;
1115impl fmt::Debug for UiNodeInWhenExprError {
1116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1117 write!(f, "{self}")
1118 }
1119}
1120impl fmt::Display for UiNodeInWhenExprError {
1121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1122 write!(f, "cannot ref `UiNode` in when expression, only var and value properties allowed")
1123 }
1124}
1125impl std::error::Error for UiNodeInWhenExprError {}
1126
1127#[derive(Clone, PartialEq)]
1131pub struct WidgetHandlerInWhenExprError;
1132impl fmt::Debug for WidgetHandlerInWhenExprError {
1133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1134 write!(f, "{self}")
1135 }
1136}
1137impl fmt::Display for WidgetHandlerInWhenExprError {
1138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1139 write!(
1140 f,
1141 "cannot ref `impl WidgetHandler<A>` in when expression, only var and value properties allowed"
1142 )
1143 }
1144}
1145impl std::error::Error for WidgetHandlerInWhenExprError {}
1146
1147#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1155pub struct Importance(pub u32);
1156impl Importance {
1157 pub const WIDGET: Importance = Importance(1000);
1159 pub const INSTANCE: Importance = Importance(1000 * 10);
1161}
1162impl_from_and_into_var! {
1163 fn from(imp: u32) -> Importance {
1164 Importance(imp)
1165 }
1166}
1167
1168unique_id_32! {
1169 pub struct PropertyId;
1171}
1172zng_unique_id::impl_unique_id_bytemuck!(PropertyId);
1173impl fmt::Debug for PropertyId {
1174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1175 f.debug_tuple("PropertyId").field(&self.get()).finish()
1176 }
1177}
1178
1179#[derive(Clone, Copy, Debug)]
1185#[non_exhaustive]
1186pub struct WidgetType {
1187 pub type_id: TypeId,
1189 pub path: &'static str,
1191 pub location: SourceLocation,
1193}
1194impl WidgetType {
1195 #[doc(hidden)]
1196 pub fn new(type_id: TypeId, path: &'static str, location: SourceLocation) -> Self {
1197 Self { type_id, path, location }
1198 }
1199
1200 pub fn name(&self) -> &'static str {
1202 self.path.rsplit_once(':').map(|(_, n)| n).unwrap_or(self.path)
1203 }
1204}
1205impl PartialEq for WidgetType {
1206 fn eq(&self, other: &Self) -> bool {
1207 self.type_id == other.type_id
1208 }
1209}
1210impl Eq for WidgetType {}
1211impl std::hash::Hash for WidgetType {
1212 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1213 self.type_id.hash(state);
1214 }
1215}
1216
1217#[derive(Clone, Copy, Debug)]
1219pub enum WhenInputMember {
1220 Named(&'static str),
1222 Index(usize),
1224}
1225
1226#[derive(Clone)]
1228pub struct WhenInput {
1229 pub property: PropertyId,
1231 pub member: WhenInputMember,
1233 pub var: WhenInputVar,
1235 pub property_default: Option<fn() -> Box<dyn PropertyArgs>>,
1237
1238 #[doc(hidden)] pub _non_exhaustive: (),
1240}
1241impl fmt::Debug for WhenInput {
1242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1243 f.debug_struct("WhenInput")
1244 .field("property", &self.property)
1245 .field("member", &self.member)
1246 .finish_non_exhaustive()
1247 }
1248}
1249
1250context_local! {
1251 static WHEN_INPUT_CONTEXT_INIT_ID: ContextInitHandle = ContextInitHandle::no_context();
1253}
1254
1255#[derive(Clone)]
1257pub struct WhenInputVar {
1258 var: Arc<Mutex<Vec<(WeakContextInitHandle, AnyVar)>>>,
1259}
1260impl WhenInputVar {
1261 pub fn new<T: VarValue>() -> (Self, Var<T>) {
1265 let arc = Arc::new(Mutex::new(vec![]));
1266 (
1267 WhenInputVar { var: arc.clone() },
1268 contextual_var(move || {
1269 let mut data = arc.lock();
1270
1271 let current_id = WHEN_INPUT_CONTEXT_INIT_ID.get();
1272 let current_id = current_id.downgrade();
1273
1274 let mut r = None;
1275 data.retain(|(id, val)| {
1276 let retain = id.is_alive();
1277 if retain && id == ¤t_id {
1278 r = Some(val.clone());
1279 }
1280 retain
1281 });
1282 match r {
1283 Some(r) => r,
1284 None => {
1285 if !data.is_empty() {
1287 let last = data.len() - 1;
1289 let last = &data[last];
1290 tracing::error!(
1291 "when input not inited for context {:?}, using value from {:?} to avoid crash",
1292 current_id,
1293 last.0
1294 );
1295 last.1.clone()
1296 } else {
1297 panic!("when input not inited for context {current_id:?}")
1299 }
1300 }
1301 }
1302 .downcast()
1303 .expect("incorrect when input var type")
1304 }),
1305 )
1306 }
1307
1308 fn set(&self, handle: WeakContextInitHandle, var: AnyVar) {
1309 let mut data = self.var.lock();
1310
1311 if let Some(i) = data.iter().position(|(i, _)| i == &handle) {
1312 data[i].1 = var;
1313 } else {
1314 data.push((handle, var));
1315 }
1316 }
1317}
1318
1319type WhenBuildActionData = Arc<dyn Any + Send + Sync>;
1320type WhenBuildDefaultAction = Arc<dyn Fn() -> Vec<Box<dyn AnyPropertyBuildAction>> + Send + Sync>;
1321
1322#[derive(Clone)]
1324#[non_exhaustive]
1325pub struct WhenBuildAction {
1326 pub data: WhenBuildActionData,
1328 pub default_action: Option<WhenBuildDefaultAction>,
1334}
1335impl WhenBuildAction {
1336 pub fn new<D, F>(data: D, default_action: F) -> Self
1338 where
1339 D: Any + Send + Sync + 'static,
1340 F: Fn() -> Vec<Box<dyn AnyPropertyBuildAction>> + Send + Sync + 'static,
1341 {
1342 Self {
1343 data: Arc::new(data),
1344 default_action: Some(Arc::new(default_action)),
1345 }
1346 }
1347
1348 pub fn new_no_default(data: impl Any + Send + Sync + 'static) -> Self {
1350 Self {
1351 data: Arc::new(data),
1352 default_action: None,
1353 }
1354 }
1355}
1356
1357#[derive(Clone)]
1359#[non_exhaustive]
1360pub struct WhenInfo {
1361 pub inputs: Box<[WhenInput]>,
1369
1370 pub state: Var<bool>,
1374
1375 pub assigns: Vec<Box<dyn PropertyArgs>>,
1378
1379 pub build_action_data: Vec<((PropertyId, &'static str), WhenBuildAction)>,
1381
1382 pub expr: &'static str,
1384
1385 pub location: SourceLocation,
1387}
1388impl fmt::Debug for WhenInfo {
1389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1390 struct DebugBuildActions<'a>(&'a WhenInfo);
1391 impl fmt::Debug for DebugBuildActions<'_> {
1392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1393 f.debug_list().entries(self.0.build_action_data.iter().map(|(k, _)| k)).finish()
1394 }
1395 }
1396
1397 f.debug_struct("WhenInfo")
1398 .field("inputs", &self.inputs)
1399 .field("state", &self.state.get_debug(false))
1400 .field("assigns", &self.assigns)
1401 .field("build_action_data", &DebugBuildActions(self))
1402 .field("expr", &self.expr)
1403 .finish()
1404 }
1405}
1406impl Clone for Box<dyn PropertyArgs> {
1407 fn clone(&self) -> Self {
1408 PropertyArgs::clone_boxed(&**self)
1409 }
1410}
1411impl fmt::Debug for &dyn PropertyArgs {
1412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1413 f.debug_struct("dyn PropertyArgs")
1414 .field("property", &self.property())
1415 .finish_non_exhaustive()
1416 }
1417}
1418impl fmt::Debug for Box<dyn PropertyArgs> {
1419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1420 f.debug_struct("dyn PropertyArgs")
1421 .field("property", &self.property())
1422 .finish_non_exhaustive()
1423 }
1424}
1425
1426#[derive(Clone)]
1427struct WidgetItemPositioned {
1428 position: NestPosition,
1429 insert_idx: u32,
1430 item: WidgetItem,
1431}
1432impl WidgetItemPositioned {
1433 fn sort_key(&self) -> (NestPosition, u32) {
1434 (self.position, self.insert_idx)
1435 }
1436}
1437
1438#[derive(Clone, Debug)]
1439struct WhenItemPositioned {
1440 importance: Importance,
1441 insert_idx: u32,
1442 when: WhenInfo,
1443}
1444impl WhenItemPositioned {
1445 fn sort_key(&self) -> (Importance, u32) {
1446 (self.importance, self.insert_idx)
1447 }
1448}
1449
1450enum WidgetItem {
1451 Property {
1452 importance: Importance,
1453 args: Box<dyn PropertyArgs>,
1454 captured: bool,
1455 },
1456 Intrinsic {
1457 name: &'static str,
1458 new: Box<dyn FnOnce(UiNode) -> UiNode + Send + Sync>,
1459 },
1460}
1461impl Clone for WidgetItem {
1462 fn clone(&self) -> Self {
1463 match self {
1464 Self::Property {
1465 importance,
1466 args,
1467 captured,
1468 } => Self::Property {
1469 importance: *importance,
1470 captured: *captured,
1471 args: args.clone(),
1472 },
1473 Self::Intrinsic { .. } => unreachable!("only WidgetBuilder clones, and it does not insert intrinsic"),
1474 }
1475 }
1476}
1477
1478type PropertyBuildActionsMap = HashMap<(PropertyId, &'static str), (Importance, Vec<Box<dyn AnyPropertyBuildAction>>)>;
1480type PropertyBuildActionsVec = Vec<((PropertyId, &'static str), (Importance, Vec<Box<dyn AnyPropertyBuildAction>>))>;
1481
1482pub struct WidgetBuilder {
1484 widget_type: WidgetType,
1485
1486 insert_idx: u32,
1487 p: WidgetBuilderProperties,
1488 unset: HashMap<PropertyId, Importance>,
1489
1490 whens: Vec<WhenItemPositioned>,
1491 when_insert_idx: u32,
1492
1493 p_build_actions: PropertyBuildActionsMap,
1494 p_build_actions_unset: HashMap<(PropertyId, &'static str), Importance>,
1495
1496 build_actions: Vec<Arc<Mutex<dyn FnMut(&mut WidgetBuilding) + Send>>>,
1497
1498 custom_build: Option<Arc<Mutex<dyn FnMut(WidgetBuilder) -> UiNode + Send>>>,
1499}
1500impl Clone for WidgetBuilder {
1501 fn clone(&self) -> Self {
1502 Self {
1503 widget_type: self.widget_type,
1504 p: WidgetBuilderProperties { items: self.items.clone() },
1505 p_build_actions: self.p_build_actions.clone(),
1506 insert_idx: self.insert_idx,
1507 unset: self.unset.clone(),
1508 p_build_actions_unset: self.p_build_actions_unset.clone(),
1509 whens: self.whens.clone(),
1510 when_insert_idx: self.when_insert_idx,
1511 build_actions: self.build_actions.clone(),
1512 custom_build: self.custom_build.clone(),
1513 }
1514 }
1515}
1516impl fmt::Debug for WidgetBuilder {
1517 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1518 struct PropertiesDebug<'a>(&'a WidgetBuilderProperties);
1519 impl fmt::Debug for PropertiesDebug<'_> {
1520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1521 f.debug_list().entries(self.0.properties()).finish()
1522 }
1523 }
1524 f.debug_struct("WidgetBuilder")
1525 .field("widget_type", &self.widget_type)
1526 .field("properties", &PropertiesDebug(&self.p))
1527 .field("unset", &self.unset)
1528 .field("whens", &self.whens)
1529 .field("build_actions.len", &self.build_actions.len())
1530 .field("is_custom_build", &self.is_custom_build())
1531 .finish()
1532 }
1533}
1534impl WidgetBuilder {
1535 pub fn new(widget: WidgetType) -> Self {
1537 Self {
1538 widget_type: widget,
1539 p: WidgetBuilderProperties { items: Default::default() },
1540 insert_idx: 0,
1541 unset: Default::default(),
1542 whens: Default::default(),
1543 p_build_actions: Default::default(),
1544 p_build_actions_unset: Default::default(),
1545 when_insert_idx: 0,
1546 build_actions: Default::default(),
1547 custom_build: Default::default(),
1548 }
1549 }
1550
1551 pub fn widget_type(&self) -> WidgetType {
1553 self.widget_type
1554 }
1555
1556 pub fn push_property(&mut self, importance: Importance, args: Box<dyn PropertyArgs>) {
1560 let pos = NestPosition::property(args.property().group);
1561 self.push_property_positioned(importance, pos, args);
1562 }
1563
1564 pub fn push_property_positioned(&mut self, importance: Importance, position: NestPosition, args: Box<dyn PropertyArgs>) {
1566 self.push_property_positioned_impl(importance, position, args, false)
1567 }
1568 fn push_property_positioned_impl(
1569 &mut self,
1570 importance: Importance,
1571 position: NestPosition,
1572 args: Box<dyn PropertyArgs>,
1573 captured: bool,
1574 ) {
1575 let insert_idx = self.insert_idx;
1576 self.insert_idx = insert_idx.wrapping_add(1);
1577
1578 let property_id = args.id();
1579 if let Some(i) = self.p.property_index(property_id) {
1580 match &self.p.items[i].item {
1581 WidgetItem::Property { importance: imp, .. } => {
1582 if *imp <= importance {
1583 self.p.items[i] = WidgetItemPositioned {
1585 position,
1586 insert_idx,
1587 item: WidgetItem::Property {
1588 importance,
1589 args,
1590 captured,
1591 },
1592 };
1593 }
1594 }
1595 WidgetItem::Intrinsic { .. } => unreachable!(),
1596 }
1597 } else {
1598 if let Some(imp) = self.unset.get(&property_id)
1599 && *imp >= importance
1600 {
1601 return; }
1603 self.p.items.push(WidgetItemPositioned {
1604 position,
1605 insert_idx,
1606 item: WidgetItem::Property {
1607 importance,
1608 args,
1609 captured,
1610 },
1611 });
1612 }
1613 }
1614
1615 pub fn push_when(&mut self, importance: Importance, mut when: WhenInfo) {
1617 let insert_idx = self.when_insert_idx;
1618 self.when_insert_idx = insert_idx.wrapping_add(1);
1619
1620 when.assigns.retain(|a| {
1621 if let Some(imp) = self.unset.get(&a.id()) {
1622 *imp < importance
1623 } else {
1624 true
1625 }
1626 });
1627
1628 if !when.assigns.is_empty() {
1629 self.whens.push(WhenItemPositioned {
1630 importance,
1631 insert_idx,
1632 when,
1633 });
1634 }
1635 }
1636
1637 pub fn push_unset(&mut self, importance: Importance, property_id: PropertyId) {
1639 let check;
1640 match self.unset.entry(property_id) {
1641 hash_map::Entry::Occupied(mut e) => {
1642 let i = e.get_mut();
1643 check = *i < importance;
1644 *i = importance;
1645 }
1646 hash_map::Entry::Vacant(e) => {
1647 check = true;
1648 e.insert(importance);
1649 }
1650 }
1651
1652 if check {
1653 if let Some(i) = self.p.property_index(property_id) {
1654 match &self.p.items[i].item {
1655 WidgetItem::Property { importance: imp, .. } => {
1656 if *imp <= importance {
1657 self.p.items.swap_remove(i);
1658 }
1659 }
1660 WidgetItem::Intrinsic { .. } => unreachable!(),
1661 }
1662 }
1663
1664 self.whens.retain_mut(|w| {
1665 if w.importance <= importance {
1666 w.when.assigns.retain(|a| a.id() != property_id);
1667 !w.when.assigns.is_empty()
1668 } else {
1669 true
1670 }
1671 });
1672 }
1673 }
1674
1675 pub fn push_property_build_action(
1680 &mut self,
1681 property_id: PropertyId,
1682 action_name: &'static str,
1683 importance: Importance,
1684 input_actions: Vec<Box<dyn AnyPropertyBuildAction>>,
1685 ) {
1686 match self.p_build_actions.entry((property_id, action_name)) {
1687 hash_map::Entry::Occupied(mut e) => {
1688 if e.get().0 < importance {
1689 e.insert((importance, input_actions));
1690 }
1691 }
1692 hash_map::Entry::Vacant(e) => {
1693 if let Some(imp) = self.p_build_actions_unset.get(&(property_id, action_name))
1694 && *imp >= importance
1695 {
1696 return;
1698 }
1699 e.insert((importance, input_actions));
1700 }
1701 }
1702 }
1703
1704 pub fn push_unset_property_build_action(&mut self, property_id: PropertyId, action_name: &'static str, importance: Importance) {
1708 let mut check = false;
1709 match self.p_build_actions_unset.entry((property_id, action_name)) {
1710 hash_map::Entry::Occupied(mut e) => {
1711 if *e.get() < importance {
1712 e.insert(importance);
1713 check = true;
1714 }
1715 }
1716 hash_map::Entry::Vacant(e) => {
1717 e.insert(importance);
1718 check = true;
1719 }
1720 }
1721 if check {
1722 self.p_build_actions.retain(|_, (imp, _)| *imp > importance);
1723 }
1724 }
1725
1726 pub fn clear_property_build_actions(&mut self) {
1728 self.p_build_actions.clear();
1729 }
1730
1731 pub fn push_build_action(&mut self, action: impl FnMut(&mut WidgetBuilding) + Send + 'static) {
1733 self.build_actions.push(Arc::new(Mutex::new(action)))
1734 }
1735
1736 pub fn clear_build_actions(&mut self) {
1738 self.build_actions.clear();
1739 }
1740
1741 pub fn is_custom_build(&self) -> bool {
1743 self.custom_build.is_some()
1744 }
1745
1746 pub fn set_custom_build(&mut self, build: impl FnMut(WidgetBuilder) -> UiNode + Send + 'static) {
1753 self.custom_build = Some(Arc::new(Mutex::new(build)));
1754 }
1755
1756 pub fn clear_custom_build(&mut self) {
1758 self.custom_build = None;
1759 }
1760
1761 pub fn extend(&mut self, other: WidgetBuilder) {
1771 for (id, imp) in other.unset {
1772 self.push_unset(imp, id);
1773 }
1774
1775 for ((id, name), imp) in other.p_build_actions_unset {
1776 self.push_unset_property_build_action(id, name, imp);
1777 }
1778
1779 for WidgetItemPositioned { position, item, .. } in other.p.items {
1780 match item {
1781 WidgetItem::Property {
1782 importance,
1783 args,
1784 captured,
1785 } => {
1786 self.push_property_positioned_impl(importance, position, args, captured);
1787 }
1788 WidgetItem::Intrinsic { .. } => unreachable!(),
1789 }
1790 }
1791
1792 for w in other.whens {
1793 self.push_when(w.importance, w.when);
1794 }
1795
1796 for ((id, name), (imp, action)) in other.p_build_actions {
1797 self.push_property_build_action(id, name, imp, action);
1798 }
1799
1800 for act in other.build_actions {
1801 self.build_actions.push(act);
1802 }
1803
1804 if let Some(c) = other.custom_build {
1805 self.custom_build = Some(c);
1806 }
1807 }
1808
1809 pub fn has_properties(&self) -> bool {
1811 !self.p.items.is_empty()
1812 }
1813
1814 pub fn has_unsets(&self) -> bool {
1816 !self.unset.is_empty()
1817 }
1818
1819 pub fn has_whens(&self) -> bool {
1821 !self.whens.is_empty()
1822 }
1823
1824 pub fn split_off(&mut self, properties: impl IntoIterator<Item = PropertyId>, out: &mut WidgetBuilder) {
1831 self.split_off_impl(properties.into_iter().collect(), out)
1832 }
1833 fn split_off_impl(&mut self, properties: IdSet<PropertyId>, out: &mut WidgetBuilder) {
1834 let mut found = 0;
1835
1836 let mut i = 0;
1838 while i < self.items.len() && found < properties.len() {
1839 match &self.items[i].item {
1840 WidgetItem::Property { args, .. } if properties.contains(&args.id()) => match self.items.swap_remove(i) {
1841 WidgetItemPositioned {
1842 position,
1843 item: WidgetItem::Property { importance, args, .. },
1844 ..
1845 } => {
1846 out.push_property_positioned(importance, position, args);
1847 found += 1;
1848 }
1849 _ => unreachable!(),
1850 },
1851 _ => {
1852 i += 1;
1853 continue;
1854 }
1855 }
1856 }
1857
1858 i = 0;
1859 while i < self.whens.len() {
1860 let mut ai = 0;
1862 let mut moved_assigns = vec![];
1863 while ai < self.whens[i].when.assigns.len() {
1864 if properties.contains(&self.whens[i].when.assigns[ai].id()) {
1865 let args = self.whens[i].when.assigns.remove(ai);
1866 moved_assigns.push(args);
1867 } else {
1868 ai += 1;
1869 }
1870 }
1871
1872 if !moved_assigns.is_empty() {
1873 let out_imp;
1874 let out_when;
1875 if self.whens[i].when.assigns.is_empty() {
1876 let WhenItemPositioned { importance, mut when, .. } = self.whens.remove(i);
1878 when.assigns = moved_assigns;
1879
1880 out_imp = importance;
1881 out_when = when;
1882 } else {
1883 let WhenItemPositioned { importance, when, .. } = &self.whens[i];
1885 out_imp = *importance;
1886 out_when = WhenInfo {
1887 inputs: when.inputs.clone(),
1888 state: when.state.clone(),
1889 assigns: moved_assigns,
1890 build_action_data: when.build_action_data.clone(),
1891 expr: when.expr,
1892 location: when.location,
1893 };
1894
1895 i += 1;
1896 };
1897
1898 for input in out_when.inputs.iter() {
1900 if let Some(i) = self.property_index(input.property) {
1901 match &self.items[i] {
1902 WidgetItemPositioned {
1903 position,
1904 item: WidgetItem::Property { importance, args, .. },
1905 ..
1906 } => {
1907 out.push_property_positioned(*importance, *position, args.clone());
1908 }
1909 _ => unreachable!(),
1910 }
1911 }
1912 }
1913
1914 out.push_when(out_imp, out_when);
1915 } else {
1916 i += 1;
1917 }
1918 }
1919
1920 for id in properties {
1922 if let Some(imp) = self.unset.remove(&id) {
1923 out.push_unset(imp, id);
1924 }
1925 }
1926 }
1927
1928 pub fn build(self) -> UiNode {
1934 if let Some(custom) = self.custom_build.clone() {
1935 match custom.try_lock() {
1936 Some(mut c) => c(self),
1937 None => self.default_build(),
1938 }
1939 } else {
1940 self.default_build()
1941 }
1942 }
1943
1944 pub fn default_build(self) -> UiNode {
1948 #[cfg(feature = "inspector")]
1949 let builder = self.clone();
1950
1951 let mut building = WidgetBuilding {
1952 #[cfg(feature = "inspector")]
1953 builder: Some(builder),
1954 #[cfg(feature = "trace_widget")]
1955 trace_widget: true,
1956 #[cfg(feature = "trace_wgt_item")]
1957 trace_wgt_item: true,
1958
1959 widget_type: self.widget_type,
1960 p: self.p,
1961 child: None,
1962 };
1963
1964 let mut p_build_actions = self.p_build_actions.into_iter().collect();
1965
1966 let mut when_init_context_handle = None;
1967
1968 if !self.whens.is_empty() {
1969 let handle = ContextInitHandle::new();
1970 building.build_whens(self.whens, handle.downgrade(), &mut p_build_actions);
1971 when_init_context_handle = Some(handle);
1972 }
1973
1974 if !p_build_actions.is_empty() {
1975 building.build_p_actions(p_build_actions);
1976 }
1977
1978 for action in self.build_actions {
1979 (action.lock())(&mut building);
1980 }
1981
1982 building.build(when_init_context_handle)
1983 }
1984}
1985impl ops::Deref for WidgetBuilder {
1986 type Target = WidgetBuilderProperties;
1987
1988 fn deref(&self) -> &Self::Target {
1989 &self.p
1990 }
1991}
1992impl ops::DerefMut for WidgetBuilder {
1993 fn deref_mut(&mut self) -> &mut Self::Target {
1994 &mut self.p
1995 }
1996}
1997
1998pub struct WidgetBuilding {
2006 #[cfg(feature = "inspector")]
2007 builder: Option<WidgetBuilder>,
2008 #[cfg(feature = "trace_widget")]
2009 trace_widget: bool,
2010 #[cfg(feature = "trace_wgt_item")]
2011 trace_wgt_item: bool,
2012
2013 widget_type: WidgetType,
2014 p: WidgetBuilderProperties,
2015 child: Option<UiNode>,
2016}
2017impl WidgetBuilding {
2018 pub fn widget_type(&self) -> WidgetType {
2020 self.widget_type
2021 }
2022
2023 pub fn has_child(&self) -> bool {
2027 self.child.is_some()
2028 }
2029
2030 pub fn set_child(&mut self, node: impl IntoUiNode) {
2032 self.child = Some(node.into_node());
2033 }
2034
2035 #[cfg(feature = "inspector")]
2039 pub fn disable_inspector(&mut self) {
2040 self.builder = None;
2041 }
2042
2043 #[cfg(feature = "trace_widget")]
2047 pub fn disable_trace_widget(&mut self) {
2048 self.trace_widget = false;
2049 }
2050
2051 #[cfg(feature = "trace_wgt_item")]
2055 pub fn disable_trace_wgt_item(&mut self) {
2056 self.trace_wgt_item = false;
2057 }
2058
2059 pub fn push_intrinsic(
2063 &mut self,
2064 group: NestGroup,
2065 name: &'static str,
2066 intrinsic: impl FnOnce(UiNode) -> UiNode + Send + Sync + 'static,
2067 ) {
2068 self.push_intrinsic_positioned(NestPosition::intrinsic(group), name, intrinsic)
2069 }
2070
2071 pub fn push_intrinsic_positioned(
2075 &mut self,
2076 position: NestPosition,
2077 name: &'static str,
2078 intrinsic: impl FnOnce(UiNode) -> UiNode + Send + Sync + 'static,
2079 ) {
2080 self.items.push(WidgetItemPositioned {
2081 position,
2082 insert_idx: u32::MAX,
2083 item: WidgetItem::Intrinsic {
2084 name,
2085 new: Box::new(intrinsic),
2086 },
2087 });
2088 }
2089
2090 pub fn remove_property(&mut self, property_id: PropertyId) -> Option<BuilderProperty> {
2094 if let Some(i) = self.property_index(property_id) {
2095 match self.items.swap_remove(i) {
2096 WidgetItemPositioned {
2097 position,
2098 item:
2099 WidgetItem::Property {
2100 importance,
2101 args,
2102 captured,
2103 },
2104 ..
2105 } => Some(BuilderProperty {
2106 importance,
2107 position,
2108 args,
2109 captured,
2110 }),
2111 _ => unreachable!(),
2112 }
2113 } else {
2114 None
2115 }
2116 }
2117
2118 pub fn capture_property(&mut self, property_id: PropertyId) -> Option<BuilderPropertyRef<'_>> {
2123 self.capture_property_impl(property_id)
2124 }
2125
2126 pub fn capture_var<T>(&mut self, property_id: PropertyId) -> Option<Var<T>>
2128 where
2129 T: VarValue,
2130 {
2131 let p = self.capture_property(property_id)?;
2132 let var = p.args.downcast_var::<T>(0).clone();
2133 Some(var)
2134 }
2135
2136 pub fn capture_var_or_else<T, F>(&mut self, property_id: PropertyId, or_else: impl FnOnce() -> F) -> Var<T>
2138 where
2139 T: VarValue,
2140 F: IntoVar<T>,
2141 {
2142 match self.capture_var::<T>(property_id) {
2143 Some(var) => var,
2144 None => or_else().into_var(),
2145 }
2146 }
2147
2148 pub fn capture_var_or_default<T>(&mut self, property_id: PropertyId) -> Var<T>
2150 where
2151 T: VarValue + Default,
2152 {
2153 self.capture_var_or_else(property_id, T::default)
2154 }
2155
2156 pub fn capture_ui_node(&mut self, property_id: PropertyId) -> Option<UiNode> {
2158 let p = self.capture_property(property_id)?;
2159 let node = p.args.ui_node(0).take_on_init();
2160 Some(node)
2161 }
2162
2163 pub fn capture_ui_node_or_else(&mut self, property_id: PropertyId, or_else: impl FnOnce() -> UiNode) -> UiNode {
2165 match self.capture_ui_node(property_id) {
2166 Some(u) => u,
2167 None => or_else(),
2168 }
2169 }
2170
2171 pub fn capture_ui_node_or_nil(&mut self, property_id: PropertyId) -> UiNode {
2173 self.capture_ui_node_or_else(property_id, UiNode::nil)
2174 }
2175
2176 pub fn capture_widget_handler<A: Clone + 'static>(&mut self, property_id: PropertyId) -> Option<ArcWidgetHandler<A>> {
2178 let p = self.capture_property(property_id)?;
2179 let handler = p.args.downcast_handler::<A>(0).clone();
2180 Some(handler)
2181 }
2182
2183 fn build_whens(
2184 &mut self,
2185 mut whens: Vec<WhenItemPositioned>,
2186 when_init_context_id: WeakContextInitHandle,
2187 build_actions: &mut PropertyBuildActionsVec,
2188 ) {
2189 whens.sort_unstable_by_key(|w| w.sort_key());
2190
2191 struct Input<'a> {
2192 input: &'a WhenInput,
2193 item_idx: usize,
2194 }
2195 let mut inputs = vec![];
2196
2197 struct Assign {
2198 item_idx: usize,
2199 builder: Vec<Box<dyn Any>>,
2200 when_count: usize,
2201 actions_data: HashMap<&'static str, (Vec<Option<WhenBuildActionData>>, Option<WhenBuildDefaultAction>)>,
2204 }
2205 let mut assigns = IdMap::default();
2206
2207 'when: for WhenItemPositioned { when, .. } in whens.iter().rev() {
2209 let valid_inputs = inputs.len();
2211 let valid_items = self.p.items.len();
2212 for input in when.inputs.iter() {
2213 if let Some(i) = self.property_index(input.property) {
2214 inputs.push(Input { input, item_idx: i })
2215 } else if let Some(default) = input.property_default {
2216 let args = default();
2217 self.p.items.push(WidgetItemPositioned {
2218 position: NestPosition::property(args.property().group),
2219 insert_idx: u32::MAX,
2220 item: WidgetItem::Property {
2221 importance: Importance::WIDGET,
2222 args,
2223 captured: false,
2224 },
2225 });
2226 inputs.push(Input {
2227 input,
2228 item_idx: self.p.items.len() - 1,
2229 });
2230 } else {
2231 inputs.truncate(valid_inputs);
2232 self.p.items.truncate(valid_items);
2233 continue 'when;
2234 }
2235 }
2236
2237 let mut any_assign = false;
2238 'assign: for assign in when.assigns.iter() {
2240 let id = assign.id();
2241 let assign_info;
2242 let i;
2243 if let Some(idx) = self.property_index(id) {
2244 assign_info = assign.property();
2245 i = idx;
2246 } else if let Some(default) = assign.property().default {
2247 let args = default();
2248 assign_info = args.property();
2249 i = self.p.items.len();
2250 self.p.items.push(WidgetItemPositioned {
2251 position: NestPosition::property(args.property().group),
2252 insert_idx: u32::MAX,
2253 item: WidgetItem::Property {
2254 importance: Importance::WIDGET,
2255 args,
2256 captured: false,
2257 },
2258 });
2259 } else {
2260 tracing::warn!(
2261 "property `{}` ignored, it is only set in `when` block and has no default value",
2262 assign.property().name
2263 );
2264 continue;
2265 }
2266
2267 any_assign = true;
2268
2269 let default_args = match &self.items[i].item {
2270 WidgetItem::Property { args, .. } => args,
2271 WidgetItem::Intrinsic { .. } => unreachable!(),
2272 };
2273 let info = default_args.property();
2274
2275 for (default_info, assign_info) in info.inputs.iter().zip(assign_info.inputs.iter()) {
2276 if default_info.ty != assign_info.ty {
2277 continue 'assign;
2279 }
2280 }
2281
2282 let entry = match assigns.entry(id) {
2283 IdEntry::Occupied(e) => e.into_mut(),
2284 IdEntry::Vacant(e) => e.insert(Assign {
2285 item_idx: i,
2286 builder: info
2287 .inputs
2288 .iter()
2289 .enumerate()
2290 .map(|(i, input)| match input.kind {
2291 InputKind::Var => Box::new(AnyWhenVarBuilder::new(default_args.var(i).clone())) as _,
2292 InputKind::UiNode => Box::new(WhenUiNodeBuilder::new(default_args.ui_node(i).take_on_init())) as _,
2293 InputKind::WidgetHandler => {
2294 Box::new(AnyWhenArcWidgetHandlerBuilder::new(default_args.widget_handler(i).clone_boxed())) as _
2295 }
2296 InputKind::Value => panic!("can only assign vars in when blocks"),
2297 })
2298 .collect(),
2299 when_count: 0,
2300 actions_data: Default::default(),
2301 }),
2302 };
2303 entry.when_count += 1;
2304
2305 for (i, (input, entry)) in info.inputs.iter().zip(entry.builder.iter_mut()).enumerate() {
2306 match input.kind {
2307 InputKind::Var => {
2308 let entry = entry.downcast_mut::<AnyWhenVarBuilder>().unwrap();
2309 let value = assign.var(i).clone();
2310 entry.push(when.state.clone(), value);
2311 }
2312 InputKind::UiNode => {
2313 let entry = entry.downcast_mut::<WhenUiNodeBuilder>().unwrap();
2314 let node = assign.ui_node(i).take_on_init();
2315 entry.push(when.state.clone(), node);
2316 }
2317 InputKind::WidgetHandler => {
2318 let entry = entry.downcast_mut::<AnyWhenArcWidgetHandlerBuilder>().unwrap();
2319 let handler = assign.widget_handler(i).clone_boxed();
2320 entry.push(when.state.clone(), handler);
2321 }
2322 InputKind::Value => panic!("cannot assign `Value` in when blocks"),
2323 }
2324 }
2325
2326 for ((property_id, action_key), action) in &when.build_action_data {
2327 if *property_id == id {
2328 match entry.actions_data.entry(*action_key) {
2329 hash_map::Entry::Occupied(mut e) => {
2330 let e = e.get_mut();
2331 for _ in e.0.len()..(entry.when_count - 1) {
2332 e.0.push(None);
2333 }
2334 e.0.push(Some(action.data.clone()));
2335 if action.default_action.is_some() && e.1.is_none() {
2336 e.1.clone_from(&action.default_action);
2337 }
2338 }
2339 hash_map::Entry::Vacant(e) => {
2340 let mut a = Vec::with_capacity(entry.when_count);
2341 for _ in 0..(entry.when_count - 1) {
2342 a.push(None);
2343 }
2344 a.push(Some(action.data.clone()));
2345 e.insert((a, action.default_action.clone()));
2346 }
2347 }
2348 }
2349 }
2350 }
2351
2352 if !any_assign {
2353 inputs.truncate(valid_inputs);
2354 self.p.items.truncate(valid_items);
2355 }
2356 }
2357
2358 for Input { input, item_idx } in inputs {
2359 let args = match &self.items[item_idx].item {
2360 WidgetItem::Property { args, .. } => args,
2361 WidgetItem::Intrinsic { .. } => unreachable!(),
2362 };
2363 let info = args.property();
2364
2365 let member_i = match input.member {
2366 WhenInputMember::Named(name) => info.input_idx(name).expect("when ref named input not found"),
2367 WhenInputMember::Index(i) => i,
2368 };
2369
2370 let actual = match info.inputs[member_i].kind {
2371 InputKind::Var => args.var(member_i).clone(),
2372 InputKind::Value => any_const_var(args.value(member_i).clone_boxed()),
2373 _ => panic!("can only ref var or values in when expr"),
2374 };
2375 input.var.set(when_init_context_id.clone(), actual);
2376 }
2377
2378 for (
2379 _,
2380 Assign {
2381 item_idx,
2382 builder,
2383 when_count,
2384 mut actions_data,
2385 },
2386 ) in assigns
2387 {
2388 let args = match &mut self.items[item_idx].item {
2389 WidgetItem::Property { args, .. } => args,
2390 WidgetItem::Intrinsic { .. } => unreachable!(),
2391 };
2392
2393 let mut actions = vec![];
2394 let mut b_actions_data = vec![];
2395 if !build_actions.is_empty() {
2396 let p_id = args.id();
2397 while let Some(i) = build_actions.iter().position(|((id, _), _)| *id == p_id) {
2398 let ((_, action_key), (_, a)) = build_actions.swap_remove(i);
2399 actions.push(a);
2400
2401 if let Some(data) = actions_data.remove(action_key) {
2402 let mut data = data.clone();
2403 for _ in data.0.len()..when_count {
2404 data.0.push(None);
2405 }
2406 b_actions_data.push(data.0);
2407 }
2408 }
2409 }
2410
2411 for (_, (mut data, default)) in actions_data {
2412 if let Some(default) = default {
2413 let action = default();
2414 for _ in data.len()..when_count {
2415 data.push(None);
2416 }
2417
2418 actions.push(action);
2419 b_actions_data.push(data);
2420 }
2421 }
2422
2423 *args = (args.property().new)(PropertyNewArgs {
2424 args: builder,
2425 build_actions: actions,
2426 build_actions_when_data: b_actions_data,
2427 });
2428 }
2429 }
2430
2431 fn build_p_actions(&mut self, mut build_actions: PropertyBuildActionsVec) {
2432 while !build_actions.is_empty() {
2433 let ((p_id, _), (_, a)) = build_actions.swap_remove(0);
2434 let mut actions = vec![a];
2435
2436 while let Some(i) = build_actions.iter().position(|((id, _), _)| *id == p_id) {
2437 let (_, (_, a)) = build_actions.swap_remove(i);
2438 actions.push(a);
2439 }
2440
2441 if let Some(i) = self.property_index(p_id) {
2442 match &mut self.items[i].item {
2443 WidgetItem::Property { args, .. } => *args = args.new_build(actions, vec![]),
2444 WidgetItem::Intrinsic { .. } => unreachable!(),
2445 }
2446 }
2447 }
2448 }
2449
2450 fn build(mut self, when_init_context_handle: Option<ContextInitHandle>) -> UiNode {
2451 self.items.sort_unstable_by_key(|b| b.sort_key());
2453
2454 #[cfg(feature = "inspector")]
2455 let mut inspector_items = Vec::with_capacity(self.p.items.len());
2456
2457 let mut node = self.child.take().unwrap_or_else(|| FillUiNode.into_node());
2458 for WidgetItemPositioned { position, item, .. } in self.p.items.into_iter().rev() {
2459 match item {
2460 WidgetItem::Property { args, captured, .. } => {
2461 if !captured {
2462 #[cfg(debug_assertions)]
2463 {
2464 let p = args.property();
2465 if p.capture {
2466 tracing::error!(
2467 "capture only property `{}` is not captured in `{}!`, it will have no effect",
2468 p.name,
2469 self.widget_type.name()
2470 );
2471 }
2472 }
2473
2474 node = args.instantiate(node);
2475
2476 #[cfg(feature = "trace_wgt_item")]
2477 if self.trace_wgt_item {
2478 let name = args.property().name;
2479 node = node.trace(move |mtd| crate::update::UpdatesTrace::property_span(name, mtd.mtd_name()));
2480 }
2481 }
2482
2483 #[cfg(feature = "inspector")]
2484 {
2485 if args.property().inputs.iter().any(|i| matches!(i.kind, InputKind::Var)) {
2486 node = crate::widget::inspector::actualize_var_info(node, args.id());
2487 }
2488
2489 inspector_items.push(crate::widget::inspector::InstanceItem::Property { args, captured });
2490 }
2491 }
2492 #[allow(unused_variables)] WidgetItem::Intrinsic { new, name } => {
2494 node = new(node);
2495 #[cfg(feature = "trace_wgt_item")]
2496 if self.trace_wgt_item {
2497 node = node.trace(move |mtd| crate::update::UpdatesTrace::intrinsic_span(name, mtd.mtd_name()));
2498 }
2499
2500 #[cfg(feature = "inspector")]
2501 inspector_items.push(crate::widget::inspector::InstanceItem::Intrinsic {
2502 group: position.group,
2503 name,
2504 });
2505
2506 #[cfg(not(feature = "inspector"))]
2507 let _ = position;
2508 }
2509 }
2510 }
2511
2512 #[cfg(feature = "inspector")]
2513 if let Some(builder) = self.builder {
2514 node = crate::widget::inspector::insert_widget_builder_info(
2515 node,
2516 crate::widget::inspector::InspectorInfo {
2517 builder,
2518 items: inspector_items.into_boxed_slice(),
2519 actual_vars: crate::widget::inspector::InspectorActualVars::default(),
2520 },
2521 );
2522 }
2523
2524 #[cfg(feature = "trace_widget")]
2525 if self.trace_widget {
2526 let name = self.widget_type.name();
2527 node = node.trace(move |op| crate::update::UpdatesTrace::widget_span(crate::widget::WIDGET.id(), name, op.mtd_name()));
2528 }
2529
2530 node = with_new_context_init_id(node);
2532
2533 if let Some(handle) = when_init_context_handle {
2534 let mut handle = Some(Arc::new(handle));
2536 node = crate::widget::node::match_node(node, move |c, op| {
2537 WHEN_INPUT_CONTEXT_INIT_ID.with_context(&mut handle, || c.op(op));
2538 });
2539 }
2540
2541 node
2542 }
2543}
2544impl ops::Deref for WidgetBuilding {
2545 type Target = WidgetBuilderProperties;
2546
2547 fn deref(&self) -> &Self::Target {
2548 &self.p
2549 }
2550}
2551impl ops::DerefMut for WidgetBuilding {
2552 fn deref_mut(&mut self) -> &mut Self::Target {
2553 &mut self.p
2554 }
2555}
2556
2557#[derive(Debug)]
2559#[non_exhaustive]
2560pub struct BuilderProperty {
2561 pub importance: Importance,
2563 pub position: NestPosition,
2565 pub args: Box<dyn PropertyArgs>,
2567 pub captured: bool,
2569}
2570
2571#[derive(Debug)]
2573#[non_exhaustive]
2574pub struct BuilderPropertyRef<'a> {
2575 pub importance: Importance,
2577 pub position: NestPosition,
2579 pub args: &'a dyn PropertyArgs,
2581 pub captured: bool,
2585}
2586
2587#[derive(Debug)]
2589#[non_exhaustive]
2590pub struct BuilderPropertyMut<'a> {
2591 pub importance: &'a mut Importance,
2593 pub position: &'a mut NestPosition,
2595 pub args: &'a mut Box<dyn PropertyArgs>,
2597 pub captured: &'a mut bool,
2601}
2602
2603pub struct WidgetBuilderProperties {
2605 items: Vec<WidgetItemPositioned>,
2606}
2607impl WidgetBuilderProperties {
2608 pub fn property(&self, property_id: PropertyId) -> Option<BuilderPropertyRef<'_>> {
2610 match self.property_index(property_id) {
2611 Some(i) => match &self.items[i].item {
2612 WidgetItem::Property {
2613 importance,
2614 args,
2615 captured,
2616 } => Some(BuilderPropertyRef {
2617 importance: *importance,
2618 position: self.items[i].position,
2619 args: &**args,
2620 captured: *captured,
2621 }),
2622 WidgetItem::Intrinsic { .. } => unreachable!(),
2623 },
2624 None => None,
2625 }
2626 }
2627
2628 pub fn property_mut(&mut self, property_id: PropertyId) -> Option<BuilderPropertyMut<'_>> {
2630 match self.property_index(property_id) {
2631 Some(i) => match &mut self.items[i] {
2632 WidgetItemPositioned {
2633 position,
2634 item:
2635 WidgetItem::Property {
2636 importance,
2637 args,
2638 captured,
2639 },
2640 ..
2641 } => Some(BuilderPropertyMut {
2642 importance,
2643 position,
2644 args,
2645 captured,
2646 }),
2647 _ => unreachable!(),
2648 },
2649 None => None,
2650 }
2651 }
2652
2653 pub fn properties(&self) -> impl Iterator<Item = BuilderPropertyRef<'_>> {
2657 self.items.iter().filter_map(|it| match &it.item {
2658 WidgetItem::Intrinsic { .. } => None,
2659 WidgetItem::Property {
2660 importance,
2661 args,
2662 captured,
2663 } => Some(BuilderPropertyRef {
2664 importance: *importance,
2665 position: it.position,
2666 args: &**args,
2667 captured: *captured,
2668 }),
2669 })
2670 }
2671
2672 pub fn properties_mut(&mut self) -> impl Iterator<Item = BuilderPropertyMut<'_>> {
2674 self.items.iter_mut().filter_map(|it| match &mut it.item {
2675 WidgetItem::Intrinsic { .. } => None,
2676 WidgetItem::Property {
2677 importance,
2678 args,
2679 captured,
2680 } => Some(BuilderPropertyMut {
2681 importance,
2682 position: &mut it.position,
2683 args,
2684 captured,
2685 }),
2686 })
2687 }
2688
2689 pub fn capture_value<T>(&mut self, property_id: PropertyId) -> Option<T>
2697 where
2698 T: VarValue,
2699 {
2700 let p = self.capture_property_impl(property_id)?;
2701 let value = p.args.downcast_value::<T>(0).clone();
2702 Some(value)
2703 }
2704
2705 pub fn capture_value_or_else<T>(&mut self, property_id: PropertyId, or_else: impl FnOnce() -> T) -> T
2707 where
2708 T: VarValue,
2709 {
2710 match self.capture_value(property_id) {
2711 Some(v) => v,
2712 None => or_else(),
2713 }
2714 }
2715
2716 pub fn capture_value_or_default<T>(&mut self, property_id: PropertyId) -> T
2718 where
2719 T: VarValue + Default,
2720 {
2721 self.capture_value_or_else(property_id, T::default)
2722 }
2723
2724 fn capture_property_impl(&mut self, property_id: PropertyId) -> Option<BuilderPropertyRef<'_>> {
2725 if let Some(i) = self.property_index(property_id) {
2726 match &mut self.items[i] {
2727 WidgetItemPositioned {
2728 position,
2729 item:
2730 WidgetItem::Property {
2731 importance,
2732 args,
2733 captured,
2734 },
2735 ..
2736 } => {
2737 *captured = true;
2738 Some(BuilderPropertyRef {
2739 importance: *importance,
2740 position: *position,
2741 args: &**args,
2742 captured: *captured,
2743 })
2744 }
2745 _ => unreachable!(),
2746 }
2747 } else {
2748 None
2749 }
2750 }
2751
2752 fn property_index(&self, property_id: PropertyId) -> Option<usize> {
2753 self.items.iter().position(|it| match &it.item {
2754 WidgetItem::Property { args, .. } => args.id() == property_id,
2755 WidgetItem::Intrinsic { .. } => false,
2756 })
2757 }
2758}
2759
2760pub trait AnyPropertyBuildAction: crate::private::Sealed + Any + Send + Sync {
2762 fn as_any(&self) -> &dyn Any;
2764
2765 fn clone_boxed(&self) -> Box<dyn AnyPropertyBuildAction>;
2767}
2768
2769#[non_exhaustive]
2771pub struct PropertyBuildActionArgs<'a, I: Any + Send> {
2772 pub input: I,
2774 pub when_conditions_data: &'a [Option<WhenBuildActionData>],
2778}
2779
2780pub struct PropertyBuildAction<I: Any + Send>(Arc<Mutex<dyn FnMut(PropertyBuildActionArgs<I>) -> I + Send>>);
2798impl<I: Any + Send> crate::private::Sealed for PropertyBuildAction<I> {}
2799impl<I: Any + Send> Clone for PropertyBuildAction<I> {
2800 fn clone(&self) -> Self {
2801 Self(self.0.clone())
2802 }
2803}
2804impl<I: Any + Send> AnyPropertyBuildAction for PropertyBuildAction<I> {
2805 fn clone_boxed(&self) -> Box<dyn AnyPropertyBuildAction> {
2806 Box::new(self.clone())
2807 }
2808
2809 fn as_any(&self) -> &dyn Any {
2810 self
2811 }
2812}
2813impl<I: Any + Send> PropertyBuildAction<I> {
2814 pub fn new(build: impl FnMut(PropertyBuildActionArgs<I>) -> I + Send + 'static) -> Self {
2816 Self(Arc::new(Mutex::new(build)))
2817 }
2818
2819 pub fn no_op() -> Self {
2821 Self::new(|i| i.input)
2822 }
2823
2824 pub fn build(&self, args: PropertyBuildActionArgs<I>) -> I {
2826 (self.0.lock())(args)
2827 }
2828}
2829impl Clone for Box<dyn AnyPropertyBuildAction> {
2830 fn clone(&self) -> Self {
2831 self.clone_boxed()
2832 }
2833}
2834
2835pub struct PropertyInputTypes<Tuple>(std::marker::PhantomData<Tuple>);
2896impl<Tuple> PropertyInputTypes<Tuple> {
2897 pub const fn unit() -> Self {
2899 Self(std::marker::PhantomData)
2900 }
2901}
2902impl<Tuple> Clone for PropertyInputTypes<Tuple> {
2903 fn clone(&self) -> Self {
2904 *self
2905 }
2906}
2907impl<Tuple> Copy for PropertyInputTypes<Tuple> {}
2908unsafe impl<Tuple> Send for PropertyInputTypes<Tuple> {}
2910unsafe impl<Tuple> Sync for PropertyInputTypes<Tuple> {}