From 6a802e2fdab675512fc63fe6484f7f31583206fa Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Wed, 8 Nov 2023 14:45:36 -0700 Subject: [PATCH] Make Modals dismissable in theory --- crates/go_to_line2/src/go_to_line.rs | 14 ++++-- crates/menu2/src/menu2.rs | 2 +- crates/workspace2/src/modal_layer.rs | 75 +++++++++++++++------------- crates/workspace2/src/workspace2.rs | 8 +-- 4 files changed, 57 insertions(+), 42 deletions(-) diff --git a/crates/go_to_line2/src/go_to_line.rs b/crates/go_to_line2/src/go_to_line.rs index f6481fdbd9599b597134455b00b016f93464f499..9d14e2d2d64a72124028eb6411dbf6505a0b1095 100644 --- a/crates/go_to_line2/src/go_to_line.rs +++ b/crates/go_to_line2/src/go_to_line.rs @@ -7,7 +7,7 @@ use text::Point; use theme::ActiveTheme; use ui::{h_stack, modal, v_stack, Label, LabelColor}; use util::paths::FILE_ROW_COLUMN_DELIMITER; -use workspace::ModalRegistry; +use workspace::{ModalRegistry, Modal, ModalEvent}; actions!(Toggle); @@ -33,7 +33,7 @@ pub enum Event { } impl EventEmitter for GoToLine { - type Event = ModalEvent; + type Event = Event; } impl GoToLine { @@ -100,7 +100,7 @@ impl GoToLine { cx.emit(Event::Dismissed); } - fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { + fn confirm(&mut self, _: &menu::Confirm, _cx: &mut ViewContext) { // // if let Some(point) = self.point_from_query(cx) { // // self.active_editor.update(cx, |active_editor, cx| { // // let snapshot = active_editor.snapshot(cx).display_snapshot; @@ -119,6 +119,14 @@ impl GoToLine { } } +impl Modal for GoToLine { + fn to_modal_event(&self, e: &Self::Event) -> Option { + match e { + Event::Dismissed => Some(ModalEvent::Dismissed), + } + } +} + impl Render for GoToLine { type Element = Div; diff --git a/crates/menu2/src/menu2.rs b/crates/menu2/src/menu2.rs index eafb1e295f7a1d8295cdb8002f94ccd4956a4f74..44ebffcca2de58e43f5452d6975cb54462ed33bb 100644 --- a/crates/menu2/src/menu2.rs +++ b/crates/menu2/src/menu2.rs @@ -1,4 +1,4 @@ -use gpui::{actions, ctor}; +use gpui::actions; // todo!(remove this) // https://github.com/rust-lang/rust/issues/47384 diff --git a/crates/workspace2/src/modal_layer.rs b/crates/workspace2/src/modal_layer.rs index 55edab353be69daca5434546f4fb0deac762ae65..c46e8f7acc14ef180c9f59caa339d7d2def95976 100644 --- a/crates/workspace2/src/modal_layer.rs +++ b/crates/workspace2/src/modal_layer.rs @@ -1,7 +1,7 @@ use crate::Workspace; use gpui::{ - div, px, AnyView, AppContext, Component, Div, ParentElement, Render, StatelessInteractive, - Styled, View, ViewContext, EventEmitter, + div, px, AnyView, AppContext, Component, Div, EventEmitter, ParentElement, Render, + StatelessInteractive, Styled, Subscription, View, ViewContext, WeakView, }; use std::{any::TypeId, sync::Arc}; use ui::v_stack; @@ -10,11 +10,10 @@ pub struct ModalRegistry { registered_modals: Vec<(TypeId, Box) -> Div>)>, } -pub trait Modal {} - -#[derive(Clone)] pub struct ModalLayer { + workspace: WeakView, open_modal: Option, + subscription: Option, } pub fn init_modal_registry(cx: &mut AppContext) { @@ -23,23 +22,19 @@ pub fn init_modal_registry(cx: &mut AppContext) { }); } -struct ToggleModal { - name: String, -} - -pub enum ModalEvents { - Dismissed +pub enum ModalEvent { + Dismissed, } -trait Modal: EventEmitter + Render { - fn to_modal_events(&Self::Event) -> Option; +pub trait Modal: EventEmitter + Render { + fn to_modal_event(&self, _: &Self::Event) -> Option; } impl ModalRegistry { pub fn register_modal(&mut self, action: A, build_view: B) where V: Modal, - B: Fn(&Workspace, &mut ViewContext) -> Option> + 'static, + B: Fn(&mut Workspace, &mut ViewContext) -> Option> + 'static, { let build_view = Arc::new(build_view); @@ -48,35 +43,47 @@ impl ModalRegistry { Box::new(move |mut div| { let build_view = build_view.clone(); - div.on_action( - move |workspace: &mut Workspace, event: &A, cx: &mut ViewContext| { - let Some(new_modal) = (build_view)(workspace, cx) else { - return; + div.on_action(move |workspace, event: &A, cx| { + let Some(new_modal) = + (build_view)(workspace, cx) else { + return }; - workspace.modal_layer.update(cx, |modal_layer, _| { - modal_layer.open_modal = Some(new_modal.into()); - }); - cx.subscribe(new_modal, |e, modal, cx| { - match modal.to_modal_events(e) { - Some(Dismissed) => - dismissed -> whatever - } - }) - - cx.notify(); - }, - ) + workspace.modal_layer.update(cx, |modal_layer, cx| { + modal_layer.show_modal(new_modal, cx); + }) + }) }), )); } } impl ModalLayer { - pub fn new() -> Self { - Self { open_modal: None } + pub fn new(workspace: WeakView) -> Self { + Self { + workspace, + open_modal: None, + subscription: None, + } + } + + pub fn show_modal(&mut self, new_modal: View, cx: &mut ViewContext) { + self.subscription = Some(cx.subscribe(&new_modal, |this, modal, e, cx| { + match modal.read(cx).to_modal_event(e) { + Some(ModalEvent::Dismissed) => this.hide_modal(cx), + None => {} + } + })); + self.open_modal = Some(new_modal.into()); + cx.notify(); + } + + pub fn hide_modal(&mut self, cx: &mut ViewContext) { + self.open_modal.take(); + self.subscription.take(); + cx.notify(); } - pub fn render(&self, workspace: &Workspace, cx: &ViewContext) -> Div { + pub fn render(&self, cx: &ViewContext) -> Div { let mut parent = div().relative().size_full(); for (_, action) in cx.global::().registered_modals.iter() { diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 42751ed632740bcb95cd08f7658db0837eb05afb..4eda0e2af64f8d9c02700c6ac3d47246302d2d20 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -46,8 +46,7 @@ use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, use itertools::Itertools; use language2::LanguageRegistry; use lazy_static::lazy_static; -pub use modal_layer::ModalRegistry; -use modal_layer::{init_modal_registry, ModalLayer}; +pub use modal_layer::*; use node_runtime::NodeRuntime; use notifications::{simple_message_notification::MessageNotification, NotificationHandle}; pub use pane::*; @@ -697,7 +696,8 @@ impl Workspace { status_bar }); - let modal_layer = cx.build_view(|cx| ModalLayer::new()); + let workspace_handle = cx.view().downgrade(); + let modal_layer = cx.build_view(|cx| ModalLayer::new(workspace_handle)); // todo!() // cx.update_default_global::, _, _>(|drag_and_drop, _| { @@ -3709,7 +3709,7 @@ impl Render for Workspace { .child( self.modal_layer .read(cx) - .render(self, cx) + .render(cx) .relative() .flex_1() .w_full()