raui_immediate_widgets/
lib.rs

1use raui_immediate::*;
2
3macro_rules! impl_imports {
4    () => {
5        #[allow(unused_imports)]
6        use raui_core::widget::component::{
7            containers::{
8                anchor_box::*, area_box::*, content_box::*, context_box::*, flex_box::*,
9                float_box::*, grid_box::*, hidden_box::*, horizontal_box::*, portal_box::*,
10                responsive_box::*, scroll_box::*, size_box::*, switch_box::*, tabs_box::*,
11                tooltip_box::*, variant_box::*, vertical_box::*, wrap_box::*,
12            },
13            interactive::{
14                button::*, float_view::*, input_field::*, navigation::*, options_view::*,
15                scroll_view::*, slider_view::*,
16            },
17        };
18        #[allow(unused_imports)]
19        use raui_core::widget::{
20            component::{image_box::*, space_box::*, text_box::*},
21            none_widget,
22        };
23        #[allow(unused_imports)]
24        use raui_material::component::{
25            containers::{
26                context_paper::*, flex_paper::*, grid_paper::*, horizontal_paper::*,
27                modal_paper::*, paper::*, scroll_paper::*, text_tooltip_paper::*, tooltip_paper::*,
28                vertical_paper::*, window_paper::*, wrap_paper::*,
29            },
30            interactive::{
31                button_paper::*, icon_button_paper::*, slider_paper::*, switch_button_paper::*,
32                text_button_paper::*, text_field_paper::*,
33            },
34        };
35        #[allow(unused_imports)]
36        use raui_material::component::{icon_paper::*, switch_paper::*, text_paper::*};
37    };
38}
39
40macro_rules! impl_slot_components {
41    ($($name:ident),+ $(,)?) => {
42        $(
43            pub fn $name<R>(
44                props: impl Into<raui_core::props::Props>,
45                f: impl FnMut() -> R,
46            ) -> R {
47                impl_imports!();
48                crate::slot_component(raui_core::make_widget!($name), props, f)
49            }
50        )+
51    };
52}
53
54macro_rules! impl_list_components {
55    ($($name:ident),+ $(,)?) => {
56        $(
57            pub fn $name<R>(
58                props: impl Into<raui_core::props::Props>,
59                f: impl FnMut() -> R,
60            ) -> R {
61                impl_imports!();
62                crate::list_component(raui_core::make_widget!($name), props, f)
63            }
64        )+
65    };
66}
67
68macro_rules! impl_content_components {
69    ($content:literal : $($name:ident),+ $(,)?) => {
70        $(
71            pub fn $name<R>(
72                props: impl Into<raui_core::props::Props>,
73                f: impl FnMut() -> R,
74            ) -> R {
75                impl_imports!();
76                crate::content_component(raui_core::make_widget!($name), $content, props, f)
77            }
78        )+
79    };
80}
81
82macro_rules! impl_components {
83    ($($name:ident),+ $(,)?) => {
84        $(
85            pub fn $name(
86                props: impl Into<raui_core::props::Props>,
87            ) {
88                impl_imports!();
89                crate::component(raui_core::make_widget!($name), props)
90            }
91        )+
92    };
93}
94
95pub mod core {
96    impl_components! {
97        image_box,
98        nav_scroll_box_side_scrollbars,
99        none_widget,
100        space_box,
101        text_box,
102    }
103
104    pub mod containers {
105        impl_content_components! {
106            "content":
107            anchor_box,
108            area_box,
109            hidden_box,
110            nav_scroll_box_content,
111            pivot_box,
112            portal_box,
113            size_box,
114            wrap_box,
115        }
116
117        impl_slot_components! {
118            context_box,
119            nav_scroll_box,
120            portals_context_box,
121            portals_tooltip_box,
122            responsive_props_box,
123            tooltip_box,
124            variant_box,
125        }
126
127        impl_list_components! {
128            content_box,
129            flex_box,
130            float_box,
131            grid_box,
132            horizontal_box,
133            nav_content_box,
134            nav_flex_box,
135            nav_float_box,
136            nav_grid_box,
137            nav_horizontal_box,
138            nav_switch_box,
139            nav_tabs_box,
140            nav_vertical_box,
141            responsive_box,
142            switch_box,
143            vertical_box,
144        }
145    }
146
147    pub mod interactive {
148        use raui_core::{
149            make_widget,
150            props::Props,
151            widget::{
152                component::interactive::{
153                    button::ButtonProps,
154                    input_field::{TextInputProps, TextInputState},
155                    navigation::NavTrackingProps,
156                    options_view::{OptionsViewProps, OptionsViewProxy},
157                    slider_view::{SliderViewProps, SliderViewProxy},
158                },
159                utils::Vec2,
160            },
161        };
162        use raui_immediate::{begin, end, pop, push, use_state};
163        use std::str::FromStr;
164
165        #[derive(Debug, Default, Copy, Clone)]
166        pub struct ImmediateTracking {
167            pub state: NavTrackingProps,
168            pub prev: NavTrackingProps,
169        }
170
171        impl ImmediateTracking {
172            pub fn pointer_delta_factor(&self) -> Vec2 {
173                Vec2 {
174                    x: self.state.factor.x - self.prev.factor.x,
175                    y: self.state.factor.y - self.prev.factor.y,
176                }
177            }
178
179            pub fn pointer_delta_unscaled(&self) -> Vec2 {
180                Vec2 {
181                    x: self.state.unscaled.x - self.prev.unscaled.x,
182                    y: self.state.unscaled.y - self.prev.unscaled.y,
183                }
184            }
185
186            pub fn pointer_delta_ui_space(&self) -> Vec2 {
187                Vec2 {
188                    x: self.state.ui_space.x - self.prev.ui_space.x,
189                    y: self.state.ui_space.y - self.prev.ui_space.y,
190                }
191            }
192
193            pub fn pointer_moved(&self) -> bool {
194                (self.state.factor.x - self.prev.factor.x)
195                    + (self.state.factor.y - self.prev.factor.y)
196                    > 1.0e-6
197            }
198        }
199
200        #[derive(Debug, Default, Copy, Clone)]
201        pub struct ImmediateButton {
202            pub state: ButtonProps,
203            pub prev: ButtonProps,
204        }
205
206        impl ImmediateButton {
207            pub fn select_start(&self) -> bool {
208                !self.prev.selected && self.state.selected
209            }
210
211            pub fn select_stop(&self) -> bool {
212                self.prev.selected && !self.state.selected
213            }
214
215            pub fn select_changed(&self) -> bool {
216                self.prev.selected != self.state.selected
217            }
218
219            pub fn trigger_start(&self) -> bool {
220                !self.prev.trigger && self.state.trigger
221            }
222
223            pub fn trigger_stop(&self) -> bool {
224                self.prev.trigger && !self.state.trigger
225            }
226
227            pub fn trigger_changed(&self) -> bool {
228                self.prev.trigger != self.state.trigger
229            }
230
231            pub fn context_start(&self) -> bool {
232                !self.prev.context && self.state.context
233            }
234
235            pub fn context_stop(&self) -> bool {
236                self.prev.context && !self.state.context
237            }
238
239            pub fn context_changed(&self) -> bool {
240                self.prev.context != self.state.context
241            }
242        }
243
244        impl_content_components! {
245            "content":
246            float_view_control,
247            navigation_barrier,
248        }
249
250        pub fn tracking(
251            props: impl Into<Props>,
252            mut f: impl FnMut(ImmediateTracking),
253        ) -> ImmediateTracking {
254            use crate::internal::*;
255            let state = use_state(ImmediateTracking::default);
256            let result = state.read().unwrap().to_owned();
257            begin();
258            f(result);
259            let node = end().pop().unwrap_or_default();
260            push(
261                make_widget!(immediate_tracking)
262                    .with_props(ImmediateTrackingProps { state: Some(state) })
263                    .merge_props(props.into())
264                    .named_slot("content", node),
265            );
266            result
267        }
268
269        pub fn self_tracking(
270            props: impl Into<Props>,
271            mut f: impl FnMut(ImmediateTracking),
272        ) -> ImmediateTracking {
273            use crate::internal::*;
274            let state = use_state(ImmediateTracking::default);
275            let result = state.read().unwrap().to_owned();
276            begin();
277            f(result);
278            let node = end().pop().unwrap_or_default();
279            push(
280                make_widget!(immediate_self_tracking)
281                    .with_props(ImmediateTrackingProps { state: Some(state) })
282                    .merge_props(props.into())
283                    .named_slot("content", node),
284            );
285            result
286        }
287
288        pub fn button(
289            props: impl Into<Props>,
290            mut f: impl FnMut(ImmediateButton),
291        ) -> ImmediateButton {
292            use crate::internal::*;
293            let state = use_state(ImmediateButton::default);
294            let result = state.read().unwrap().to_owned();
295            begin();
296            f(result);
297            let node = end().pop().unwrap_or_default();
298            push(
299                make_widget!(immediate_button)
300                    .with_props(ImmediateButtonProps { state: Some(state) })
301                    .merge_props(props.into())
302                    .named_slot("content", node),
303            );
304            result
305        }
306
307        pub fn tracked_button(
308            props: impl Into<Props>,
309            mut f: impl FnMut(ImmediateButton),
310        ) -> ImmediateButton {
311            use crate::internal::*;
312            let state = use_state(ImmediateButton::default);
313            let result = state.read().unwrap().to_owned();
314            begin();
315            f(result);
316            let node = end().pop().unwrap_or_default();
317            push(
318                make_widget!(immediate_tracked_button)
319                    .with_props(ImmediateButtonProps { state: Some(state) })
320                    .merge_props(props.into())
321                    .named_slot("content", node),
322            );
323            result
324        }
325
326        pub fn self_tracked_button(
327            props: impl Into<Props>,
328            mut f: impl FnMut(ImmediateButton),
329        ) -> ImmediateButton {
330            use crate::internal::*;
331            let state = use_state(ImmediateButton::default);
332            let result = state.read().unwrap().to_owned();
333            begin();
334            f(result);
335            let node = end().pop().unwrap_or_default();
336            push(
337                make_widget!(immediate_self_tracked_button)
338                    .with_props(ImmediateButtonProps { state: Some(state) })
339                    .merge_props(props.into())
340                    .named_slot("content", node),
341            );
342            result
343        }
344
345        pub fn text_input<T: ToString + FromStr + Send + Sync>(
346            value: &T,
347            props: impl Into<Props>,
348            mut f: impl FnMut(&str, TextInputState),
349        ) -> (Option<T>, TextInputState) {
350            use crate::internal::*;
351            let content = use_state(|| value.to_string());
352            let props = props.into();
353            let TextInputProps { allow_new_line, .. } = props.read_cloned_or_default();
354            let text_state = use_state(TextInputState::default);
355            let text_result = text_state.read().unwrap().to_owned();
356            if !text_result.focused {
357                *content.write().unwrap() = value.to_string();
358            }
359            let result = content.read().unwrap().to_string();
360            begin();
361            f(&result, text_result);
362            let node = end().pop().unwrap_or_default();
363            push(
364                make_widget!(immediate_text_input)
365                    .with_props(ImmediateTextInputProps {
366                        state: Some(text_state),
367                    })
368                    .merge_props(props)
369                    .with_props(TextInputProps {
370                        allow_new_line,
371                        text: Some(content.into()),
372                    })
373                    .named_slot("content", node),
374            );
375            (result.parse().ok(), text_result)
376        }
377
378        pub fn input_field<T: ToString + FromStr + Send + Sync>(
379            value: &T,
380            props: impl Into<Props>,
381            mut f: impl FnMut(&str, TextInputState, ImmediateButton),
382        ) -> (Option<T>, TextInputState, ImmediateButton) {
383            use crate::internal::*;
384            let content = use_state(|| value.to_string());
385            let props = props.into();
386            let TextInputProps { allow_new_line, .. } = props.read_cloned_or_default();
387            let text_state = use_state(TextInputState::default);
388            let text_result = text_state.read().unwrap().to_owned();
389            let button_state = use_state(ImmediateButton::default);
390            let button_result = button_state.read().unwrap().to_owned();
391            if !text_result.focused {
392                *content.write().unwrap() = value.to_string();
393            }
394            let result = content.read().unwrap().to_string();
395            begin();
396            f(&result, text_result, button_result);
397            let node = end().pop().unwrap_or_default();
398            push(
399                make_widget!(immediate_input_field)
400                    .with_props(ImmediateTextInputProps {
401                        state: Some(text_state),
402                    })
403                    .with_props(ImmediateButtonProps {
404                        state: Some(button_state),
405                    })
406                    .merge_props(props)
407                    .with_props(TextInputProps {
408                        allow_new_line,
409                        text: Some(content.into()),
410                    })
411                    .named_slot("content", node),
412            );
413            (result.parse().ok(), text_result, button_result)
414        }
415
416        pub fn slider_view<T: SliderViewProxy + Clone + 'static>(
417            value: T,
418            props: impl Into<Props>,
419            mut f: impl FnMut(&T, ImmediateButton),
420        ) -> (T, ImmediateButton) {
421            use crate::internal::*;
422            let content = use_state(|| value.to_owned());
423            let props = props.into();
424            let SliderViewProps {
425                from,
426                to,
427                direction,
428                ..
429            } = props.read_cloned_or_default();
430            let button_state = use_state(ImmediateButton::default);
431            let button_result = button_state.read().unwrap().to_owned();
432            let result = content.read().unwrap().to_owned();
433            begin();
434            f(&result, button_result);
435            let node = end().pop().unwrap_or_default();
436            push(
437                make_widget!(immediate_slider_view)
438                    .with_props(ImmediateButtonProps {
439                        state: Some(button_state),
440                    })
441                    .merge_props(props)
442                    .with_props(SliderViewProps {
443                        input: Some(content.into()),
444                        from,
445                        to,
446                        direction,
447                    })
448                    .named_slot("content", node),
449            );
450            (result, button_result)
451        }
452
453        pub fn options_view<T: OptionsViewProxy + Clone + 'static>(
454            value: T,
455            props: impl Into<Props>,
456            mut f_items: impl FnMut(&T),
457            mut f_content: impl FnMut(),
458        ) -> T {
459            let content = use_state(|| value.to_owned());
460            let props = props.into();
461            let result = content.read().unwrap().to_owned();
462            begin();
463            f_items(&result);
464            let nodes = end();
465            begin();
466            f_content();
467            let node = pop();
468            push(
469                make_widget!(raui_core::widget::component::interactive::options_view::options_view)
470                    .merge_props(props)
471                    .with_props(OptionsViewProps {
472                        input: Some(content.into()),
473                    })
474                    .named_slot("content", node)
475                    .listed_slots(nodes),
476            );
477            result
478        }
479    }
480}
481
482pub mod material {
483    impl_components! {
484        icon_paper,
485        scroll_paper_side_scrollbars,
486        switch_paper,
487        text_paper,
488    }
489
490    pub mod containers {
491        impl_slot_components! {
492            context_paper,
493            scroll_paper,
494            tooltip_paper,
495            window_paper,
496            window_title_controls_paper,
497        }
498
499        impl_content_components! {
500            "content":
501            modal_paper,
502            text_tooltip_paper,
503            wrap_paper,
504        }
505
506        impl_list_components! {
507            flex_paper,
508            grid_paper,
509            horizontal_paper,
510            nav_flex_paper,
511            nav_grid_paper,
512            nav_horizontal_paper,
513            nav_paper,
514            nav_vertical_paper,
515            paper,
516            vertical_paper,
517        }
518    }
519
520    pub mod interactive {
521        use crate::core::interactive::ImmediateButton;
522        use raui_core::{
523            make_widget,
524            props::Props,
525            widget::component::interactive::{
526                input_field::{TextInputProps, TextInputState},
527                slider_view::{SliderViewProps, SliderViewProxy},
528            },
529        };
530        use raui_immediate::{begin, end, push, use_state};
531        use std::str::FromStr;
532
533        pub fn button_paper(
534            props: impl Into<Props>,
535            mut f: impl FnMut(ImmediateButton),
536        ) -> ImmediateButton {
537            use crate::internal::*;
538            let state = use_state(ImmediateButton::default);
539            let result = state.read().unwrap().to_owned();
540            begin();
541            f(result);
542            let node = end().pop().unwrap_or_default();
543            push(
544                make_widget!(immediate_button_paper)
545                    .with_props(ImmediateButtonProps { state: Some(state) })
546                    .merge_props(props.into())
547                    .named_slot("content", node),
548            );
549            result
550        }
551
552        pub fn icon_button_paper(props: impl Into<Props>) -> ImmediateButton {
553            use crate::internal::*;
554            let state = use_state(ImmediateButton::default);
555            let result = state.read().unwrap().to_owned();
556            push(
557                make_widget!(immediate_icon_button_paper)
558                    .with_props(ImmediateButtonProps { state: Some(state) })
559                    .merge_props(props.into()),
560            );
561            result
562        }
563
564        pub fn switch_button_paper(props: impl Into<Props>) -> ImmediateButton {
565            use crate::internal::*;
566            let state = use_state(ImmediateButton::default);
567            let result = state.read().unwrap().to_owned();
568            push(
569                make_widget!(immediate_switch_button_paper)
570                    .with_props(ImmediateButtonProps { state: Some(state) })
571                    .merge_props(props.into()),
572            );
573            result
574        }
575
576        pub fn text_button_paper(props: impl Into<Props>) -> ImmediateButton {
577            use crate::internal::*;
578            let state = use_state(ImmediateButton::default);
579            let result = state.read().unwrap().to_owned();
580            push(
581                make_widget!(immediate_text_button_paper)
582                    .with_props(ImmediateButtonProps { state: Some(state) })
583                    .merge_props(props.into()),
584            );
585            result
586        }
587
588        pub fn text_field_paper<T: ToString + FromStr + Send + Sync>(
589            value: &T,
590            props: impl Into<Props>,
591        ) -> (Option<T>, TextInputState, ImmediateButton) {
592            use crate::internal::*;
593            let content = use_state(|| value.to_string());
594            let props = props.into();
595            let TextInputProps { allow_new_line, .. } =
596                props.read_cloned_or_default::<TextInputProps>();
597            let text_state = use_state(TextInputState::default);
598            let text_result = text_state.read().unwrap().to_owned();
599            let button_state = use_state(ImmediateButton::default);
600            let button_result = button_state.read().unwrap().to_owned();
601            if !text_result.focused {
602                *content.write().unwrap() = value.to_string();
603            }
604            let result = content.read().unwrap().to_string();
605            push(
606                make_widget!(immediate_text_field_paper)
607                    .with_props(ImmediateTextInputProps {
608                        state: Some(text_state),
609                    })
610                    .with_props(ImmediateButtonProps {
611                        state: Some(button_state),
612                    })
613                    .merge_props(props)
614                    .with_props(TextInputProps {
615                        allow_new_line,
616                        text: Some(content.into()),
617                    }),
618            );
619            (result.parse().ok(), text_result, button_result)
620        }
621
622        pub fn slider_paper<T: SliderViewProxy + Clone + 'static>(
623            value: T,
624            props: impl Into<Props>,
625            mut f: impl FnMut(&T, ImmediateButton),
626        ) -> (T, ImmediateButton) {
627            use crate::internal::*;
628            let content = use_state(|| value.to_owned());
629            let props = props.into();
630            let SliderViewProps {
631                from,
632                to,
633                direction,
634                ..
635            } = props.read_cloned_or_default();
636            let button_state = use_state(ImmediateButton::default);
637            let button_result = button_state.read().unwrap().to_owned();
638            let result = content.read().unwrap().to_owned();
639            begin();
640            f(&result, button_result);
641            let node = end().pop().unwrap_or_default();
642            push(
643                make_widget!(immediate_slider_paper)
644                    .with_props(ImmediateButtonProps {
645                        state: Some(button_state),
646                    })
647                    .merge_props(props)
648                    .with_props(SliderViewProps {
649                        input: Some(content.into()),
650                        from,
651                        to,
652                        direction,
653                    })
654                    .named_slot("content", node),
655            );
656            (result, button_result)
657        }
658
659        pub fn numeric_slider_paper<T: SliderViewProxy + Clone + 'static>(
660            value: T,
661            props: impl Into<Props>,
662        ) -> (T, ImmediateButton) {
663            use crate::internal::*;
664            let content = use_state(|| value.to_owned());
665            let props = props.into();
666            let SliderViewProps {
667                from,
668                to,
669                direction,
670                ..
671            } = props.read_cloned_or_default();
672            let button_state = use_state(ImmediateButton::default);
673            let button_result = button_state.read().unwrap().to_owned();
674            let result = content.read().unwrap().to_owned();
675            push(
676                make_widget!(immediate_numeric_slider_paper)
677                    .with_props(ImmediateButtonProps {
678                        state: Some(button_state),
679                    })
680                    .merge_props(props)
681                    .with_props(SliderViewProps {
682                        input: Some(content.into()),
683                        from,
684                        to,
685                        direction,
686                    }),
687            );
688            (result, button_result)
689        }
690    }
691}
692
693mod internal {
694    use crate::core::interactive::{ImmediateButton, ImmediateTracking};
695    use raui_core::{
696        ManagedLazy, Prefab, PropsData, make_widget, pre_hooks,
697        widget::{
698            component::interactive::{
699                button::{
700                    ButtonNotifyMessage, ButtonNotifyProps, button, self_tracked_button,
701                    tracked_button,
702                },
703                input_field::{TextInputState, input_field, text_input},
704                navigation::{
705                    NavTrackingNotifyMessage, NavTrackingNotifyProps, self_tracking, tracking,
706                    use_nav_tracking_self,
707                },
708                slider_view::slider_view,
709            },
710            context::WidgetContext,
711            node::WidgetNode,
712        },
713    };
714    use raui_material::component::interactive::{
715        button_paper::button_paper_impl,
716        icon_button_paper::icon_button_paper_impl,
717        slider_paper::{numeric_slider_paper_impl, slider_paper_impl},
718        switch_button_paper::switch_button_paper_impl,
719        text_button_paper::text_button_paper_impl,
720        text_field_paper::text_field_paper_impl,
721    };
722    use serde::{Deserialize, Serialize};
723
724    #[derive(PropsData, Default, Clone, Serialize, Deserialize)]
725    #[props_data(raui_core::props::PropsData)]
726    #[prefab(raui_core::Prefab)]
727    pub struct ImmediateTrackingProps {
728        #[serde(default, skip)]
729        pub state: Option<ManagedLazy<ImmediateTracking>>,
730    }
731
732    impl std::fmt::Debug for ImmediateTrackingProps {
733        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
734            f.debug_struct("ImmediateTrackingProps")
735                .field(
736                    "state",
737                    &self
738                        .state
739                        .as_ref()
740                        .and_then(|state| state.read())
741                        .map(|state| *state),
742                )
743                .finish()
744        }
745    }
746
747    #[derive(PropsData, Default, Clone, Serialize, Deserialize)]
748    #[props_data(raui_core::props::PropsData)]
749    #[prefab(raui_core::Prefab)]
750    pub struct ImmediateButtonProps {
751        #[serde(default, skip)]
752        pub state: Option<ManagedLazy<ImmediateButton>>,
753    }
754
755    impl std::fmt::Debug for ImmediateButtonProps {
756        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
757            f.debug_struct("ImmediateButtonProps")
758                .field(
759                    "state",
760                    &self
761                        .state
762                        .as_ref()
763                        .and_then(|state| state.read())
764                        .map(|state| *state),
765                )
766                .finish()
767        }
768    }
769
770    #[derive(PropsData, Default, Clone, Serialize, Deserialize)]
771    #[props_data(raui_core::props::PropsData)]
772    pub struct ImmediateTextInputProps {
773        #[serde(default, skip)]
774        pub state: Option<ManagedLazy<TextInputState>>,
775    }
776
777    impl std::fmt::Debug for ImmediateTextInputProps {
778        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
779            f.debug_struct("ImmediateTextInputProps")
780                .finish_non_exhaustive()
781        }
782    }
783
784    fn use_immediate_tracking(ctx: &mut WidgetContext) {
785        ctx.props
786            .write(NavTrackingNotifyProps(ctx.id.to_owned().into()));
787
788        if let Ok(props) = ctx.props.read::<ImmediateTrackingProps>() {
789            let state = props.state.as_ref().unwrap();
790            let mut state = state.write().unwrap();
791            state.prev = state.state;
792        }
793
794        ctx.life_cycle.change(|ctx| {
795            if let Ok(props) = ctx.props.read::<ImmediateTrackingProps>()
796                && let Some(state) = props.state.as_ref()
797                && let Some(mut state) = state.write()
798            {
799                for msg in ctx.messenger.messages {
800                    if let Some(msg) = msg.as_any().downcast_ref::<NavTrackingNotifyMessage>() {
801                        state.state = msg.state;
802                    }
803                }
804            }
805        });
806    }
807
808    fn use_immediate_button(ctx: &mut WidgetContext) {
809        ctx.props.write(ButtonNotifyProps(ctx.id.to_owned().into()));
810
811        if let Ok(props) = ctx.props.read::<ImmediateButtonProps>() {
812            let state = props.state.as_ref().unwrap();
813            let mut state = state.write().unwrap();
814            state.prev = state.state;
815        }
816
817        ctx.life_cycle.change(|ctx| {
818            if let Ok(props) = ctx.props.read::<ImmediateButtonProps>()
819                && let Some(state) = props.state.as_ref()
820                && let Some(mut state) = state.write()
821            {
822                for msg in ctx.messenger.messages {
823                    if let Some(msg) = msg.as_any().downcast_ref::<ButtonNotifyMessage>() {
824                        state.state = msg.state;
825                    }
826                }
827            }
828        });
829    }
830
831    fn use_immediate_text_input(ctx: &mut WidgetContext) {
832        if let Ok(data) = ctx.state.read_cloned::<TextInputState>()
833            && let Ok(props) = ctx.props.read::<ImmediateTextInputProps>()
834        {
835            let state = props.state.as_ref().unwrap();
836            let mut state = state.write().unwrap();
837            *state = data;
838        }
839    }
840
841    #[pre_hooks(use_immediate_tracking)]
842    pub(crate) fn immediate_tracking(mut ctx: WidgetContext) -> WidgetNode {
843        tracking(ctx)
844    }
845
846    #[pre_hooks(use_immediate_tracking, use_nav_tracking_self)]
847    pub(crate) fn immediate_self_tracking(mut ctx: WidgetContext) -> WidgetNode {
848        self_tracking(ctx)
849    }
850
851    #[pre_hooks(use_immediate_button)]
852    pub(crate) fn immediate_button(mut ctx: WidgetContext) -> WidgetNode {
853        button(ctx)
854    }
855
856    #[pre_hooks(use_immediate_button)]
857    pub(crate) fn immediate_tracked_button(mut ctx: WidgetContext) -> WidgetNode {
858        tracked_button(ctx)
859    }
860
861    #[pre_hooks(use_immediate_button)]
862    pub(crate) fn immediate_self_tracked_button(mut ctx: WidgetContext) -> WidgetNode {
863        self_tracked_button(ctx)
864    }
865
866    #[pre_hooks(use_immediate_text_input)]
867    pub(crate) fn immediate_text_input(mut ctx: WidgetContext) -> WidgetNode {
868        text_input(ctx)
869    }
870
871    #[pre_hooks(use_immediate_text_input, use_immediate_button)]
872    pub(crate) fn immediate_input_field(mut ctx: WidgetContext) -> WidgetNode {
873        input_field(ctx)
874    }
875
876    #[pre_hooks(use_immediate_button)]
877    pub(crate) fn immediate_slider_view(mut ctx: WidgetContext) -> WidgetNode {
878        slider_view(ctx)
879    }
880
881    pub(crate) fn immediate_button_paper(ctx: WidgetContext) -> WidgetNode {
882        button_paper_impl(make_widget!(immediate_button), ctx)
883    }
884
885    pub(crate) fn immediate_icon_button_paper(ctx: WidgetContext) -> WidgetNode {
886        icon_button_paper_impl(make_widget!(immediate_button_paper), ctx)
887    }
888
889    pub(crate) fn immediate_switch_button_paper(ctx: WidgetContext) -> WidgetNode {
890        switch_button_paper_impl(make_widget!(immediate_button_paper), ctx)
891    }
892
893    pub(crate) fn immediate_text_button_paper(ctx: WidgetContext) -> WidgetNode {
894        text_button_paper_impl(make_widget!(immediate_button_paper), ctx)
895    }
896
897    pub(crate) fn immediate_text_field_paper(ctx: WidgetContext) -> WidgetNode {
898        text_field_paper_impl(make_widget!(immediate_input_field), ctx)
899    }
900
901    pub(crate) fn immediate_slider_paper(ctx: WidgetContext) -> WidgetNode {
902        slider_paper_impl(make_widget!(immediate_slider_view), ctx)
903    }
904
905    pub(crate) fn immediate_numeric_slider_paper(ctx: WidgetContext) -> WidgetNode {
906        numeric_slider_paper_impl(make_widget!(immediate_slider_paper), ctx)
907    }
908}