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