modal_layer.rs

  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// }