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