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.
This commit is contained in:
Ben Gotow 2016-03-26 18:12:25 -07:00
parent 8d08c3241d
commit c87c49f4c8
6 changed files with 54 additions and 5 deletions

View file

@ -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, void ShowOpenDialog(const std::string& title,
const base::FilePath& default_path, const base::FilePath& default_path,
const file_dialog::Filters& filters, const file_dialog::Filters& filters,
@ -112,6 +116,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
dict.SetMethod("showMessageBox", &ShowMessageBox); dict.SetMethod("showMessageBox", &ShowMessageBox);
dict.SetMethod("showErrorBox", &atom::ShowErrorBox); dict.SetMethod("showErrorBox", &atom::ShowErrorBox);
dict.SetMethod("showOpenDialog", &ShowOpenDialog); dict.SetMethod("showOpenDialog", &ShowOpenDialog);
dict.SetMethod("setSheetOffset", &SetSheetOffset);
dict.SetMethod("showSaveDialog", &ShowSaveDialog); dict.SetMethod("showSaveDialog", &ShowSaveDialog);
} }

View file

@ -201,6 +201,14 @@ gfx::Size NativeWindow::GetContentSize() {
return WindowSizeToContentSize(GetSize()); return WindowSizeToContentSize(GetSize());
} }
void NativeWindow::SetSheetOffset(const double offset) {
sheet_offset_ = offset;
}
double NativeWindow::GetSheetOffset() {
return sheet_offset_;
}
void NativeWindow::SetSizeConstraints( void NativeWindow::SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) { const extensions::SizeConstraints& window_constraints) {
extensions::SizeConstraints content_constraints; extensions::SizeConstraints content_constraints;

View file

@ -190,6 +190,9 @@ class NativeWindow : public base::SupportsUserData,
gfx::Size GetAspectRatioExtraSize(); gfx::Size GetAspectRatioExtraSize();
void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size); void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
void SetSheetOffset(const double offset);
double GetSheetOffset();
base::WeakPtr<NativeWindow> GetWeakPtr() { base::WeakPtr<NativeWindow> GetWeakPtr() {
return weak_factory_.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. // it should be cancelled when we can prove that the window is responsive.
base::CancelableClosure window_unresposive_closure_; 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 // Used to maintain the aspect ratio of a view which is inside of the
// content view. // content view.
double aspect_ratio_; double aspect_ratio_;

View file

@ -243,6 +243,12 @@ bool ScopedDisableResize::disable_resize_ = false;
return NO; 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 @end
@interface AtomNSWindow : NSWindow { @interface AtomNSWindow : NSWindow {

View file

@ -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; 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 ## Methods
The `dialog` module has the following 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 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, before the app `ready`event on Linux, the message will be emitted to stderr,
and no GUI dialog will appear. 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 ...
```

View file

@ -49,7 +49,11 @@ var checkAppInitialized = function () {
} }
module.exports = { module.exports = {
showOpenDialog: function (...args) { setSheetOffset: function(window, offset) {
return binding.setSheetOffset(window, offset)
},
showOpenDialog: function(...args) {
var prop, properties, value, wrappedCallback var prop, properties, value, wrappedCallback
checkAppInitialized() checkAppInitialized()
let [window, options, callback] = parseArgs.apply(null, args) let [window, options, callback] = parseArgs.apply(null, args)