zng_wgt_dialog/
backdrop.rs

1//! Modal backdrop widget.
2
3use zng_ext_window::WINDOWS;
4use zng_wgt::{prelude::*, *};
5use zng_wgt_container::Container;
6use zng_wgt_fill::background_color;
7use zng_wgt_input::gesture::on_click;
8use zng_wgt_layer::popup::{POPUP_CLOSE_REQUESTED_EVENT, PopupCloseRequestedArgs};
9use zng_wgt_style::{Style, StyleMix, impl_style_fn};
10
11use crate::DIALOG;
12
13/// Modal dialog parent widget that fills the window.
14///
15/// This widget is instantiated by [`DIALOG`] automatically, you can only customize it by setting the [`style_fn`](fn@style_fn)
16/// contextual property. Note that the [`popup::close_delay`] and [`popup::is_close_delaying`] properties work with this widget.
17///
18/// [`popup::close_delay`]: fn@zng_wgt_layer::popup::close_delay
19/// [`popup::is_close_delaying`]: fn@zng_wgt_layer::popup::is_close_delaying
20#[widget($crate::backdrop::DialogBackdrop {
21    ($child:expr) => {
22        child = $child;
23    }
24})]
25pub struct DialogBackdrop(StyleMix<Container>);
26impl DialogBackdrop {
27    fn widget_intrinsic(&mut self) {
28        self.style_intrinsic(STYLE_FN_VAR, property_id!(self::style_fn));
29
30        // the backdrop widget id identifies the popup, so
31        self.widget_builder()
32            .push_build_action(|b| b.push_intrinsic(NestGroup::EVENT, "popup-pump", backdrop_node));
33
34        widget_set! {
35            self;
36            modal = true;
37
38            on_click = hn!(|args| {
39                args.propagation.stop();
40                DIALOG.respond_default();
41            });
42        }
43    }
44}
45impl_style_fn!(DialogBackdrop, DefaultStyle);
46
47/// Share popup events with the dialog child.
48fn backdrop_node(child: impl IntoUiNode) -> UiNode {
49    match_node(child, |_, op| {
50        if let UiNodeOp::Init = op {
51            let win_id = WINDOW.id();
52            let id = WIDGET.id();
53            WIDGET.push_var_handle(POPUP_CLOSE_REQUESTED_EVENT.hook(move |args| {
54                if args.popup.widget_id() == id
55                    && let Some(tree) = WINDOWS.widget_tree(win_id)
56                    && let Some(info) = tree.get(id)
57                {
58                    for child in info.children() {
59                        POPUP_CLOSE_REQUESTED_EVENT.notify(PopupCloseRequestedArgs::new(
60                            args.timestamp,
61                            args.propagation.clone(),
62                            child.path(),
63                        ));
64                    }
65                }
66                true
67            }));
68            WIDGET.sub_event(&POPUP_CLOSE_REQUESTED_EVENT);
69        }
70    })
71}
72
73/// Dialog backdrop default style.
74#[widget($crate::backdrop::DefaultStyle)]
75pub struct DefaultStyle(Style);
76impl DefaultStyle {
77    fn widget_intrinsic(&mut self) {
78        widget_set! {
79            self;
80
81            #[easing(250.ms())]
82            background_color = colors::BLACK.transparent();
83            zng_wgt_layer::popup::close_delay = 250.ms();
84            when *#is_inited && !*#zng_wgt_layer::popup::is_close_delaying {
85                background_color = colors::BLACK.with_alpha(20.pct());
86            }
87        }
88    }
89}