diff --git a/crates/feedback/src/feedback_modal.rs b/crates/feedback/src/feedback_modal.rs index 31ff5989f3ae28b1f62739938cc2bfd9598fed57..18e762030e153db298cc28eabf913839dcf98e6c 100644 --- a/crates/feedback/src/feedback_modal.rs +++ b/crates/feedback/src/feedback_modal.rs @@ -17,7 +17,7 @@ use regex::Regex; use serde_derive::Serialize; use ui::{prelude::*, Button, ButtonStyle, IconPosition, Tooltip}; use util::{http::HttpClient, ResultExt}; -use workspace::{ModalView, Toast, Workspace}; +use workspace::{DismissDecision, ModalView, Toast, Workspace}; use crate::{system_specs::SystemSpecs, GiveFeedback, OpenZedRepo}; @@ -85,16 +85,16 @@ impl FocusableView for FeedbackModal { impl EventEmitter for FeedbackModal {} impl ModalView for FeedbackModal { - fn on_before_dismiss(&mut self, cx: &mut ViewContext) -> bool { + fn on_before_dismiss(&mut self, cx: &mut ViewContext) -> DismissDecision { self.update_email_in_store(cx); if self.dismiss_modal { - return true; + return DismissDecision::Dismiss(true); } let has_feedback = self.feedback_editor.read(cx).text_option(cx).is_some(); if !has_feedback { - return true; + return DismissDecision::Dismiss(true); } let answer = cx.prompt(PromptLevel::Info, "Discard feedback?", None, &["Yes", "No"]); @@ -110,7 +110,7 @@ impl ModalView for FeedbackModal { }) .detach(); - false + DismissDecision::Pending } } diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index e670aa550ac503b8115679b6daafd808ee4d7017..29682262beaa7d4a022914f7253c2a459660e827 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -20,7 +20,7 @@ use std::{ use theme::{color_alpha, ActiveTheme, ThemeSettings}; use ui::{prelude::*, ListItem, ListItemSpacing}; use util::ResultExt; -use workspace::ModalView; +use workspace::{DismissDecision, ModalView}; actions!(outline, [Toggle]); @@ -55,10 +55,10 @@ impl FocusableView for OutlineView { impl EventEmitter for OutlineView {} impl ModalView for OutlineView { - fn on_before_dismiss(&mut self, cx: &mut ViewContext) -> bool { + fn on_before_dismiss(&mut self, cx: &mut ViewContext) -> DismissDecision { self.picker .update(cx, |picker, cx| picker.delegate.restore_active_editor(cx)); - true + DismissDecision::Dismiss(true) } } diff --git a/crates/workspace/src/modal_layer.rs b/crates/workspace/src/modal_layer.rs index c30ca35a68578cc3c8a77f4bbf3fa702291181fa..f67b78f7d1981e8d681afdec4cd06a7756159e0c 100644 --- a/crates/workspace/src/modal_layer.rs +++ b/crates/workspace/src/modal_layer.rs @@ -4,19 +4,24 @@ use gpui::{ }; use ui::{h_flex, v_flex}; +pub enum DismissDecision { + Dismiss(bool), + Pending, +} + pub trait ModalView: ManagedView { - fn on_before_dismiss(&mut self, _: &mut ViewContext) -> bool { - true + fn on_before_dismiss(&mut self, _: &mut ViewContext) -> DismissDecision { + DismissDecision::Dismiss(true) } } trait ModalViewHandle { - fn on_before_dismiss(&mut self, cx: &mut WindowContext) -> bool; + fn on_before_dismiss(&mut self, cx: &mut WindowContext) -> DismissDecision; fn view(&self) -> AnyView; } impl ModalViewHandle for View { - fn on_before_dismiss(&mut self, cx: &mut WindowContext) -> bool { + fn on_before_dismiss(&mut self, cx: &mut WindowContext) -> DismissDecision { self.update(cx, |this, cx| this.on_before_dismiss(cx)) } @@ -34,11 +39,15 @@ pub struct ActiveModal { pub struct ModalLayer { active_modal: Option, + dismiss_on_focus_lost: bool, } impl ModalLayer { pub fn new() -> Self { - Self { active_modal: None } + Self { + active_modal: None, + dismiss_on_focus_lost: false, + } } pub fn toggle_modal(&mut self, cx: &mut ViewContext, build_view: B) @@ -69,7 +78,9 @@ impl ModalLayer { this.hide_modal(cx); }), cx.on_focus_out(&focus_handle, |this, cx| { - this.hide_modal(cx); + if this.dismiss_on_focus_lost { + this.hide_modal(cx); + } }), ], previous_focus_handle: cx.focused(), @@ -81,12 +92,21 @@ impl ModalLayer { fn hide_modal(&mut self, cx: &mut ViewContext) -> bool { let Some(active_modal) = self.active_modal.as_mut() else { + self.dismiss_on_focus_lost = false; return false; }; - let dismiss = active_modal.modal.on_before_dismiss(cx); - if !dismiss { - return false; + match active_modal.modal.on_before_dismiss(cx) { + DismissDecision::Dismiss(dismiss) => { + self.dismiss_on_focus_lost = !dismiss; + if !dismiss { + return false; + } + } + DismissDecision::Pending => { + self.dismiss_on_focus_lost = false; + return false; + } } if let Some(active_modal) = self.active_modal.take() {