From c87c49f4c8f48668d7913f7da8b81e495dd4692e Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Sat, 26 Mar 2016 18:12:25 -0700 Subject: [PATCH] Allow sheets to be attached at a custom offset #4679 Adds a new "setSheetOffset" API to the `dialog` module, which allows you to change the attachment point for sheets on Mac OS X. I put the API on the dialog module, even though Mac OS X requires that the native window hold and return the desired offset. 1. I was originally hoping to make this an argument on the actual dialog.show* calls, but it seems the parameter set is defined in `libchromiumcontent` and I wasn't sure it would be appropriate to add there? 2. The API could also be on the BrowserWindow (eg `BrowserWindow.setSheetOffset`). I don't have a strong preference, but I think it's more discoverable on the `dialog` module. --- atom/browser/api/atom_api_dialog.cc | 5 +++++ atom/browser/native_window.cc | 8 ++++++++ atom/browser/native_window.h | 6 ++++++ atom/browser/native_window_mac.mm | 6 ++++++ docs/api/dialog.md | 28 ++++++++++++++++++++++++---- lib/browser/api/dialog.js | 6 +++++- 6 files changed, 54 insertions(+), 5 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 0a544c5646..965b928783 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -66,6 +66,10 @@ void ShowMessageBox(int type, } } +void SetSheetOffset(atom::NativeWindow* window, const double offset) { + window->SetSheetOffset(offset); +} + void ShowOpenDialog(const std::string& title, const base::FilePath& default_path, const file_dialog::Filters& filters, @@ -112,6 +116,7 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("showMessageBox", &ShowMessageBox); dict.SetMethod("showErrorBox", &atom::ShowErrorBox); dict.SetMethod("showOpenDialog", &ShowOpenDialog); + dict.SetMethod("setSheetOffset", &SetSheetOffset); dict.SetMethod("showSaveDialog", &ShowSaveDialog); } diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index d7ed86165b..37bf8f687e 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -201,6 +201,14 @@ gfx::Size NativeWindow::GetContentSize() { return WindowSizeToContentSize(GetSize()); } +void NativeWindow::SetSheetOffset(const double offset) { + sheet_offset_ = offset; +} + +double NativeWindow::GetSheetOffset() { + return sheet_offset_; +} + void NativeWindow::SetSizeConstraints( const extensions::SizeConstraints& window_constraints) { extensions::SizeConstraints content_constraints; diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index f91d041c05..d60ac209d8 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -190,6 +190,9 @@ class NativeWindow : public base::SupportsUserData, gfx::Size GetAspectRatioExtraSize(); void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size); + void SetSheetOffset(const double offset); + double GetSheetOffset(); + base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } @@ -326,6 +329,9 @@ class NativeWindow : public base::SupportsUserData, // it should be cancelled when we can prove that the window is responsive. base::CancelableClosure window_unresposive_closure_; + // Used to display sheets at the appropriate vertical offset + double sheet_offset_; + // Used to maintain the aspect ratio of a view which is inside of the // content view. double aspect_ratio_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index b24e828e57..dc2929f82e 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -243,6 +243,12 @@ bool ScopedDisableResize::disable_resize_ = false; return NO; } +- (NSRect)window:(NSWindow *)window willPositionSheet:(NSWindow *)sheet usingRect:(NSRect)rect { + rect.origin.y = window.contentView.frame.size.height - shell_->GetSheetOffset(); + return rect; +} + + @end @interface AtomNSWindow : NSWindow { diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 9fbc20dd83..f36850f310 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -18,10 +18,6 @@ The Dialog is opened from Electron's main thread. If you want to use the dialog const dialog = require('electron').remote.dialog; ``` -**Note for OS X**: If you want to present dialogs as sheets, the only thing you -have to do is provide a `BrowserWindow` reference in the `browserWindow` -parameter. - ## Methods The `dialog` module has the following methods: @@ -125,3 +121,27 @@ This API can be called safely before the `ready` event the `app` module emits, it is usually used to report errors in early stage of startup. If called before the app `ready`event on Linux, the message will be emitted to stderr, and no GUI dialog will appear. + + +## Sheets + +On Mac OS X, dialogs are presented as sheets attached to a window if you provide +a `BrowserWindow` reference in the `browserWindow` parameter, or modals if no +window is provided. + +### `dialog.setSheetOffset(browserWindow, offset)` + +* `browserWindow` BrowserWindow (optional) + +Changes the attachment point for sheets on Mac OS X. By default, sheets are attached +just below the window frame, but you may want to display them beneath a HTML-rendered +toolbar. For example: +``` +const {remote} = require('electron'); +const browserWindow = remote.getCurrentWindow(); + +var toolbarRect = document.getElementById('toolbar').getBoundingClientRect(); +remote.dialog.setSheetOffset(browserWindow, toolbarRect.height); + +... show dialog ... +``` diff --git a/lib/browser/api/dialog.js b/lib/browser/api/dialog.js index 6669d8cab8..f88d25cfbb 100644 --- a/lib/browser/api/dialog.js +++ b/lib/browser/api/dialog.js @@ -49,7 +49,11 @@ var checkAppInitialized = function () { } module.exports = { - showOpenDialog: function (...args) { + setSheetOffset: function(window, offset) { + return binding.setSheetOffset(window, offset) + }, + + showOpenDialog: function(...args) { var prop, properties, value, wrappedCallback checkAppInitialized() let [window, options, callback] = parseArgs.apply(null, args)