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