diff --git a/src/appkit/app/enums.rs b/src/appkit/app/enums.rs index 140515cc..f8710730 100644 --- a/src/appkit/app/enums.rs +++ b/src/appkit/app/enums.rs @@ -1,6 +1,6 @@ //! Various types used at the AppController level. -use crate::foundation::NSUInteger; +use crate::foundation::{NSInteger, NSUInteger}; /// Used for determining how an application should handle quitting/terminating. /// You return this in your `AppController` `should_terminate` method. @@ -156,3 +156,68 @@ impl From<&PresentationOption> for NSUInteger { } } } + +/// Represents a modal response for macOS modal dialogs. +#[derive(Copy, Clone, Debug)] +pub enum ModalResponse { + /// The user hit the "Ok" button. + Ok, + + /// Continue. + Continue, + + /// Canceled. + Canceled, + + /// Stopped. + Stopped, + + /// Aborted. + Aborted, + + /// The first button in the dialog was clicked. + FirstButtonReturned, + + /// The second button in the dialog was clicked. + SecondButtonReturned, + + /// The third button in the dialog was clicked. + ThirdButtonReturned +} + +impl From for ModalResponse { + fn from(i: NSInteger) -> Self { + match i { + 1 => ModalResponse::Ok, + 0 => ModalResponse::Canceled, + 1000 => ModalResponse::FirstButtonReturned, + 1001 => ModalResponse::SecondButtonReturned, + 1002 => ModalResponse::ThirdButtonReturned, + -1000 => ModalResponse::Stopped, + -1001 => ModalResponse::Aborted, + -1002 => ModalResponse::Continue, + + // @TODO: Definitely don't panic here, wtf was I thinking? + // Probably make this a ModalResponse::Unknown or something so a user can + // gracefully handle. + e => { + panic!("Unknown NSModalResponse sent back! {}", e); + } + } + } +} + +impl Into for ModalResponse { + fn into(self) -> NSInteger { + match self { + ModalResponse::Ok => 1, + ModalResponse::Canceled => 0, + ModalResponse::FirstButtonReturned => 1000, + ModalResponse::SecondButtonReturned => 1001, + ModalResponse::ThirdButtonReturned => 1002, + ModalResponse::Stopped => -1000, + ModalResponse::Aborted => -1001, + ModalResponse::Continue => -1002 + } + } +} diff --git a/src/appkit/app/mod.rs b/src/appkit/app/mod.rs index 8b57f576..59ab47ea 100644 --- a/src/appkit/app/mod.rs +++ b/src/appkit/app/mod.rs @@ -44,7 +44,7 @@ use objc::runtime::Object; use objc::{class, msg_send, msg_send_id, sel}; use crate::appkit::menu::Menu; -use crate::foundation::{id, nil, AutoReleasePool, NSUInteger, NO, YES}; +use crate::foundation::{id, nil, AutoReleasePool, NSInteger, NSUInteger, NO, YES}; use crate::invoker::TargetActionHandler; use crate::notification_center::Dispatcher; use crate::utils::activate_cocoa_multithreading; @@ -63,7 +63,7 @@ pub use enums::*; mod traits; pub use traits::AppDelegate; -use super::window::Window; +use super::window::{Window, WindowDelegate}; pub(crate) static APP_PTR: &str = "rstAppPtr"; @@ -319,4 +319,31 @@ impl App { let _: () = msg_send![app, terminate: nil]; }); } + + /// Starts a modal event loop for the given window. + /// + /// This method runs a modal event loop for the specified window synchronously. + /// It displays the specified window, makes it key, starts the run loop, and + /// processes events for that window. + /// + /// Modern MacOS modal views should really be using the sheets API, but this + /// is still part of AppKit, so provided for completeness. As with + /// begin_sheet, a WindowDelegate is required. + pub fn run_modal_for_window(window: &Window) -> ModalResponse + where + W: WindowDelegate + 'static + { + shared_application(|app| unsafe { + let modal_response: NSInteger = msg_send![app, runModalForWindow: &*window.objc]; + modal_response.into() + }) + } + + /// Stop the current modal window, returning the given code. + pub fn stop_modal_with_code(modal_response: ModalResponse) { + shared_application(|app| unsafe { + let response: NSInteger = modal_response.into(); + let _: () = msg_send![app, stopModalWithCode: response]; + }); + } } diff --git a/src/filesystem/enums.rs b/src/filesystem/enums.rs index 0834ec2c..91e4cdbf 100644 --- a/src/filesystem/enums.rs +++ b/src/filesystem/enums.rs @@ -2,56 +2,6 @@ use crate::foundation::{NSInteger, NSUInteger}; -/// Represents a modal response for macOS modal dialogs. -#[derive(Copy, Clone, Debug)] -pub enum ModalResponse { - /// The user hit the "Ok" button. - Ok, - - /// Continue. - Continue, - - /// Canceled. - Canceled, - - /// Stopped. - Stopped, - - /// Aborted. - Aborted, - - /// The first button in the dialog was clicked. - FirstButtonReturned, - - /// The second button in the dialog was clicked. - SecondButtonReturned, - - /// The third button in the dialog was clicked. - ThirdButtonReturned -} - -impl From for ModalResponse { - fn from(i: NSInteger) -> Self { - match i { - 1 => ModalResponse::Ok, - 0 => ModalResponse::Canceled, - 1000 => ModalResponse::FirstButtonReturned, - 1001 => ModalResponse::SecondButtonReturned, - 1002 => ModalResponse::ThirdButtonReturned, - -1000 => ModalResponse::Stopped, - -1001 => ModalResponse::Aborted, - -1002 => ModalResponse::Continue, - - // @TODO: Definitely don't panic here, wtf was I thinking? - // Probably make this a ModalResponse::Unknown or something so a user can - // gracefully handle. - e => { - panic!("Unknown NSModalResponse sent back! {}", e); - } - } - } -} - /// Represents a type of search path used in file manager calls. #[derive(Copy, Clone, Debug)] pub enum SearchPathDomainMask { diff --git a/src/filesystem/select.rs b/src/filesystem/select.rs index b30fc51c..ef056113 100644 --- a/src/filesystem/select.rs +++ b/src/filesystem/select.rs @@ -10,7 +10,7 @@ use objc::rc::{Id, Shared}; use objc::runtime::Object; use objc::{class, msg_send, msg_send_id, sel}; -use crate::filesystem::enums::ModalResponse; +use crate::appkit::ModalResponse; use crate::foundation::{id, nil, NSInteger, NSString, NO, NSURL, YES}; #[cfg(feature = "appkit")]