moly_kit/widgets/
moly_modal.rs1use 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 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 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}