moly_kit/widgets/
moly_modal.rs

1//! Copy of the original modal from the main Moly app which draws its content
2//! over the whole app (from its root).
3
4use makepad_widgets::*;
5
6live_design! {
7    use link::theme::*;
8    use link::shaders::*;
9    use link::widgets::*;
10
11    pub MolyModal = {{MolyModal}} {
12        width: Fill
13        height: Fill
14        flow: Overlay
15        align: {x: 0.5, y: 0.5}
16
17        draw_bg: {
18            fn pixel(self) -> vec4 {
19                return vec4(0., 0., 0., 0.0)
20            }
21        }
22
23        bg_view: <View> {
24            width: Fill
25            height: Fill
26            show_bg: true
27            draw_bg: {
28                fn pixel(self) -> vec4 {
29                    return vec4(0., 0., 0., 0.7)
30                }
31            }
32        }
33
34        content: <View> {
35            flow: Overlay
36            width: Fit
37            height: Fit
38        }
39    }
40}
41
42#[derive(Clone, Debug, DefaultNone)]
43pub enum MolyModalAction {
44    None,
45    Dismissed,
46}
47
48#[derive(Live, Widget)]
49pub struct MolyModal {
50    #[live]
51    #[find]
52    content: View,
53    #[live]
54    #[area]
55    bg_view: View,
56
57    #[redraw]
58    #[rust(DrawList2d::new(cx))]
59    draw_list: DrawList2d,
60
61    #[live]
62    draw_bg: DrawQuad,
63    #[layout]
64    layout: Layout,
65    #[walk]
66    walk: Walk,
67
68    #[live(true)]
69    dismiss_on_focus_lost: bool,
70
71    #[rust]
72    opened: bool,
73}
74
75impl LiveHook for MolyModal {
76    fn after_apply(&mut self, cx: &mut Cx, _apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
77        self.draw_list.redraw(cx);
78    }
79}
80
81impl Widget for MolyModal {
82    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
83        if !self.opened {
84            return;
85        }
86
87        // When passing down events we need to suspend the sweep lock
88        // because regular View instances won't respond to events if the sweep lock is active.
89        cx.sweep_unlock(self.draw_bg.area());
90        self.content.handle_event(cx, event, scope);
91        cx.sweep_lock(self.draw_bg.area());
92
93        if self.dismiss_on_focus_lost {
94            // Check if there was a click outside of the content (bg), then close if true.
95            let content_rec = self.content.area().rect(cx);
96            if let Hit::FingerUp(fe) =
97                event.hits_with_sweep_area(cx, self.draw_bg.area(), self.draw_bg.area())
98            {
99                if !content_rec.contains(fe.abs) {
100                    let widget_uid = self.content.widget_uid();
101                    cx.widget_action(widget_uid, &scope.path, MolyModalAction::Dismissed);
102                    self.close(cx);
103                }
104            }
105        }
106    }
107
108    fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
109        self.draw_list.begin_overlay_reuse(cx);
110
111        cx.begin_root_turtle_for_pass(self.layout);
112        self.draw_bg.begin(cx, self.walk, self.layout);
113
114        if self.opened {
115            let _ = self
116                .bg_view
117                .draw_walk(cx, scope, walk.with_abs_pos(DVec2 { x: 0., y: 0. }));
118            let _ = self.content.draw_all(cx, scope);
119        }
120
121        self.draw_bg.end(cx);
122
123        cx.end_pass_sized_turtle();
124        self.draw_list.end(cx);
125
126        DrawStep::done()
127    }
128}
129
130impl MolyModal {
131    pub fn open(&mut self, cx: &mut Cx) {
132        self.opened = true;
133        self.draw_bg.redraw(cx);
134        cx.sweep_lock(self.draw_bg.area());
135    }
136
137    pub fn close(&mut self, cx: &mut Cx) {
138        self.opened = false;
139        self.draw_bg.redraw(cx);
140        cx.sweep_unlock(self.draw_bg.area())
141    }
142
143    pub fn dismissed(&self, actions: &Actions) -> bool {
144        matches!(
145            actions.find_widget_action(self.widget_uid()).cast(),
146            MolyModalAction::Dismissed
147        )
148    }
149}
150
151impl MolyModalRef {
152    pub fn open(&self, cx: &mut Cx) {
153        if let Some(mut inner) = self.borrow_mut() {
154            inner.open(cx);
155        }
156    }
157
158    pub fn close(&self, cx: &mut Cx) {
159        if let Some(mut inner) = self.borrow_mut() {
160            inner.close(cx);
161        }
162    }
163
164    pub fn dismissed(&self, actions: &Actions) -> bool {
165        if let Some(inner) = self.borrow() {
166            inner.dismissed(actions)
167        } else {
168            false
169        }
170    }
171}