1use crate::Workspace;
2use gpui::{
3 div, px, AnyView, Component, Div, EventEmitter, ParentElement, Render, StatelessInteractive,
4 Styled, Subscription, View, ViewContext,
5};
6use std::{any::TypeId, sync::Arc};
7use ui::v_stack;
8
9pub struct ModalLayer {
10 open_modal: Option<AnyView>,
11 subscription: Option<Subscription>,
12 registered_modals: Vec<(TypeId, Box<dyn Fn(Div<Workspace>) -> Div<Workspace>>)>,
13}
14
15pub enum ModalEvent {
16 Dismissed,
17}
18
19impl ModalLayer {
20 pub fn new() -> Self {
21 Self {
22 open_modal: None,
23 subscription: None,
24 registered_modals: Vec::new(),
25 }
26 }
27
28 pub fn register_modal<A: 'static, V, B>(&mut self, action: A, build_view: B)
29 where
30 V: EventEmitter<ModalEvent> + Render,
31 B: Fn(&mut Workspace, &mut ViewContext<Workspace>) -> Option<View<V>> + 'static,
32 {
33 let build_view = Arc::new(build_view);
34
35 self.registered_modals.push((
36 TypeId::of::<A>(),
37 Box::new(move |mut div| {
38 let build_view = build_view.clone();
39
40 div.on_action(move |workspace, event: &A, cx| {
41 let Some(new_modal) = (build_view)(workspace, cx) else {
42 return;
43 };
44 workspace.modal_layer().show_modal(new_modal, cx);
45 })
46 }),
47 ));
48 }
49
50 pub fn show_modal<V>(&mut self, new_modal: View<V>, cx: &mut ViewContext<Workspace>)
51 where
52 V: EventEmitter<ModalEvent> + Render,
53 {
54 self.subscription = Some(cx.subscribe(&new_modal, |this, modal, e, cx| match e {
55 ModalEvent::Dismissed => this.modal_layer().hide_modal(cx),
56 }));
57 self.open_modal = Some(new_modal.into());
58 cx.notify();
59 }
60
61 pub fn hide_modal(&mut self, cx: &mut ViewContext<Workspace>) {
62 self.open_modal.take();
63 self.subscription.take();
64 cx.notify();
65 }
66
67 pub fn wrapper_element(&self, cx: &ViewContext<Workspace>) -> Div<Workspace> {
68 let mut parent = div().relative().size_full();
69
70 for (_, action) in self.registered_modals.iter() {
71 parent = (action)(parent);
72 }
73
74 parent.when_some(self.open_modal.as_ref(), |parent, open_modal| {
75 let container1 = div()
76 .absolute()
77 .flex()
78 .flex_col()
79 .items_center()
80 .size_full()
81 .top_0()
82 .left_0()
83 .z_index(400);
84
85 // transparent layer
86 let container2 = v_stack().h(px(0.0)).relative().top_20();
87
88 parent.child(container1.child(container2.child(open_modal.clone())))
89 })
90 }
91}
92
93// impl Render for ModalLayer {
94// type Element = Div<Self>;
95
96// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
97// let mut div = div();
98// for (type_id, build_view) in cx.global::<ModalRegistry>().registered_modals {
99// div = div.useful_on_action(
100// type_id,
101// Box::new(|this, _: dyn Any, phase, cx: &mut ViewContext<Self>| {
102// if phase == DispatchPhase::Capture {
103// return;
104// }
105// self.workspace.update(cx, |workspace, cx| {
106// self.open_modal = Some(build_view(workspace, cx));
107// });
108// cx.notify();
109// }),
110// )
111// }
112
113// div
114// }
115// }