ui: Refactor modal dialog into separate Dialog class
This is the basic dialog actor implementation, which will allow us to use the same implementation on the session-global modal dialogs. The ModalDialog class now uses it underneath, and so do all users of it. https://bugzilla.gnome.org/show_bug.cgi?id=762083
This commit is contained in:
parent
74bd009c86
commit
1c7a3ee61b
@ -47,6 +47,7 @@
|
|||||||
<file>ui/ctrlAltTab.js</file>
|
<file>ui/ctrlAltTab.js</file>
|
||||||
<file>ui/dash.js</file>
|
<file>ui/dash.js</file>
|
||||||
<file>ui/dateMenu.js</file>
|
<file>ui/dateMenu.js</file>
|
||||||
|
<file>ui/dialog.js</file>
|
||||||
<file>ui/dnd.js</file>
|
<file>ui/dnd.js</file>
|
||||||
<file>ui/edgeDragAction.js</file>
|
<file>ui/edgeDragAction.js</file>
|
||||||
<file>ui/endSessionDialog.js</file>
|
<file>ui/endSessionDialog.js</file>
|
||||||
|
131
js/ui/dialog.js
Normal file
131
js/ui/dialog.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
|
||||||
|
const Dialog = new Lang.Class({
|
||||||
|
Name: 'Dialog',
|
||||||
|
Extends: St.Widget,
|
||||||
|
|
||||||
|
_init: function (parentActor, styleClass) {
|
||||||
|
this.parent({ layout_manager: new Clutter.BinLayout() });
|
||||||
|
this.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
|
||||||
|
this._pressedKey = null;
|
||||||
|
this._buttonKeys = {};
|
||||||
|
this._createDialog();
|
||||||
|
this.add_child(this._dialog);
|
||||||
|
|
||||||
|
if (styleClass != null)
|
||||||
|
this._dialog.add_style_class_name(styleClass);
|
||||||
|
|
||||||
|
this._parentActor = parentActor;
|
||||||
|
this._eventId = this._parentActor.connect('event', Lang.bind(this, this._modalEventHandler));
|
||||||
|
this._parentActor.add_child(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
_createDialog: function () {
|
||||||
|
this._dialog = new St.BoxLayout({ style_class: 'modal-dialog',
|
||||||
|
x_align: Clutter.ActorAlign.CENTER,
|
||||||
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
|
vertical: true });
|
||||||
|
|
||||||
|
// modal dialogs are fixed width and grow vertically; set the request
|
||||||
|
// mode accordingly so wrapped labels are handled correctly during
|
||||||
|
// size requests.
|
||||||
|
this._dialog.request_mode = Clutter.RequestMode.HEIGHT_FOR_WIDTH;
|
||||||
|
|
||||||
|
this.contentLayout = new St.BoxLayout({ vertical: true,
|
||||||
|
style_class: "modal-dialog-content-box" });
|
||||||
|
this._dialog.add(this.contentLayout,
|
||||||
|
{ expand: true,
|
||||||
|
x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
x_align: St.Align.MIDDLE,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout({ homogeneous:true }) });
|
||||||
|
this._dialog.add(this.buttonLayout,
|
||||||
|
{ x_align: St.Align.MIDDLE,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDestroy: function () {
|
||||||
|
if (this._eventId != 0)
|
||||||
|
this._parentActor.disconnect(this._eventId);
|
||||||
|
this._eventId = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
_modalEventHandler: function (actor, event) {
|
||||||
|
if (event.type() == Clutter.EventType.KEY_PRESS) {
|
||||||
|
this._pressedKey = event.get_key_symbol();
|
||||||
|
} else if (event.type() == Clutter.EventType.KEY_RELEASE) {
|
||||||
|
let pressedKey = this._pressedKey;
|
||||||
|
this._pressedKey = null;
|
||||||
|
|
||||||
|
let symbol = event.get_key_symbol();
|
||||||
|
if (symbol != pressedKey)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
|
let buttonInfo = this._buttonKeys[symbol];
|
||||||
|
if (!buttonInfo)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
|
let { button, action } = buttonInfo;
|
||||||
|
|
||||||
|
if (action && button.reactive) {
|
||||||
|
action();
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
},
|
||||||
|
|
||||||
|
addContent: function (actor) {
|
||||||
|
this.contentLayout.add (actor, { expand: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
addButton: function (buttonInfo) {
|
||||||
|
let { label, action, key } = buttonInfo;
|
||||||
|
let isDefault = buttonInfo['default'];
|
||||||
|
let keys;
|
||||||
|
|
||||||
|
if (key)
|
||||||
|
keys = [key];
|
||||||
|
else if (isDefault)
|
||||||
|
keys = [Clutter.KEY_Return, Clutter.KEY_KP_Enter, Clutter.KEY_ISO_Enter];
|
||||||
|
else
|
||||||
|
keys = [];
|
||||||
|
|
||||||
|
let button = new St.Button({ style_class: 'modal-dialog-linked-button',
|
||||||
|
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||||
|
reactive: true,
|
||||||
|
can_focus: true,
|
||||||
|
x_expand: true,
|
||||||
|
y_expand: true,
|
||||||
|
label: label });
|
||||||
|
button.connect('clicked', action);
|
||||||
|
|
||||||
|
buttonInfo['button'] = button;
|
||||||
|
|
||||||
|
if (isDefault)
|
||||||
|
button.add_style_pseudo_class('default');
|
||||||
|
|
||||||
|
if (!this._initialKeyFocusDestroyId)
|
||||||
|
this._initialKeyFocus = button;
|
||||||
|
|
||||||
|
for (let i in keys)
|
||||||
|
this._buttonKeys[keys[i]] = buttonInfo;
|
||||||
|
|
||||||
|
this.buttonLayout.add_actor(button);
|
||||||
|
|
||||||
|
return button;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearButtons: function () {
|
||||||
|
this.buttonLayout.destroy_all_children();
|
||||||
|
this._buttonKeys = {};
|
||||||
|
},
|
||||||
|
});
|
@ -14,6 +14,7 @@ const Atk = imports.gi.Atk;
|
|||||||
|
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
|
const Dialog = imports.ui.dialog;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -61,11 +62,6 @@ const ModalDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
||||||
|
|
||||||
this._pressedKey = null;
|
|
||||||
this._buttonKeys = {};
|
|
||||||
this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
|
||||||
this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
|
|
||||||
|
|
||||||
this.backgroundStack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
this.backgroundStack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||||
this._backgroundBin = new St.Bin({ child: this.backgroundStack,
|
this._backgroundBin = new St.Bin({ child: this.backgroundStack,
|
||||||
x_fill: true, y_fill: true });
|
x_fill: true, y_fill: true });
|
||||||
@ -73,17 +69,9 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._backgroundBin.add_constraint(this._monitorConstraint);
|
this._backgroundBin.add_constraint(this._monitorConstraint);
|
||||||
this._group.add_actor(this._backgroundBin);
|
this._group.add_actor(this._backgroundBin);
|
||||||
|
|
||||||
this.dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
|
this.dialogLayout = new Dialog.Dialog(this.backgroundStack, params.styleClass);
|
||||||
x_align: Clutter.ActorAlign.CENTER,
|
this.contentLayout = this.dialogLayout.contentLayout;
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
this.buttonLayout = this.dialogLayout.buttonLayout;
|
||||||
vertical: true });
|
|
||||||
// modal dialogs are fixed width and grow vertically; set the request
|
|
||||||
// mode accordingly so wrapped labels are handled correctly during
|
|
||||||
// size requests.
|
|
||||||
this.dialogLayout.request_mode = Clutter.RequestMode.HEIGHT_FOR_WIDTH;
|
|
||||||
|
|
||||||
if (params.styleClass != null)
|
|
||||||
this.dialogLayout.add_style_class_name(params.styleClass);
|
|
||||||
|
|
||||||
if (!this._shellReactive) {
|
if (!this._shellReactive) {
|
||||||
this._lightbox = new Lightbox.Lightbox(this._group,
|
this._lightbox = new Lightbox.Lightbox(this._group,
|
||||||
@ -94,22 +82,6 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._eventBlocker = new Clutter.Actor({ reactive: true });
|
this._eventBlocker = new Clutter.Actor({ reactive: true });
|
||||||
this.backgroundStack.add_actor(this._eventBlocker);
|
this.backgroundStack.add_actor(this._eventBlocker);
|
||||||
}
|
}
|
||||||
this.backgroundStack.add_actor(this.dialogLayout);
|
|
||||||
|
|
||||||
|
|
||||||
this.contentLayout = new St.BoxLayout({ vertical: true,
|
|
||||||
style_class: "modal-dialog-content-box" });
|
|
||||||
this.dialogLayout.add(this.contentLayout,
|
|
||||||
{ expand: true,
|
|
||||||
x_fill: true,
|
|
||||||
y_fill: true,
|
|
||||||
x_align: St.Align.MIDDLE,
|
|
||||||
y_align: St.Align.START });
|
|
||||||
|
|
||||||
this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout ({ homogeneous:true }) });
|
|
||||||
this.dialogLayout.add(this.buttonLayout,
|
|
||||||
{ x_align: St.Align.MIDDLE,
|
|
||||||
y_align: St.Align.END });
|
|
||||||
|
|
||||||
global.focus_manager.add_group(this.dialogLayout);
|
global.focus_manager.add_group(this.dialogLayout);
|
||||||
this._initialKeyFocus = this.dialogLayout;
|
this._initialKeyFocus = this.dialogLayout;
|
||||||
@ -122,8 +94,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
clearButtons: function() {
|
clearButtons: function() {
|
||||||
this.buttonLayout.destroy_all_children();
|
this.dialogLayout.clearButtons();
|
||||||
this._buttonKeys = {};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setButtons: function(buttons) {
|
setButtons: function(buttons) {
|
||||||
@ -146,72 +117,8 @@ const ModalDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addButton: function(buttonInfo) {
|
addButton: function (buttonInfo) {
|
||||||
let label = buttonInfo['label']
|
return this.dialogLayout.addButton(buttonInfo);
|
||||||
let action = buttonInfo['action'];
|
|
||||||
let key = buttonInfo['key'];
|
|
||||||
let isDefault = buttonInfo['default'];
|
|
||||||
|
|
||||||
let keys;
|
|
||||||
|
|
||||||
if (key)
|
|
||||||
keys = [key];
|
|
||||||
else if (isDefault)
|
|
||||||
keys = [Clutter.KEY_Return, Clutter.KEY_KP_Enter, Clutter.KEY_ISO_Enter];
|
|
||||||
else
|
|
||||||
keys = [];
|
|
||||||
|
|
||||||
let button = new St.Button({ style_class: 'modal-dialog-linked-button',
|
|
||||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
|
||||||
reactive: true,
|
|
||||||
can_focus: true,
|
|
||||||
x_expand: true,
|
|
||||||
y_expand: true,
|
|
||||||
label: label });
|
|
||||||
button.connect('clicked', action);
|
|
||||||
|
|
||||||
buttonInfo['button'] = button;
|
|
||||||
|
|
||||||
if (isDefault)
|
|
||||||
button.add_style_pseudo_class('default');
|
|
||||||
|
|
||||||
if (!this._initialKeyFocusDestroyId)
|
|
||||||
this._initialKeyFocus = button;
|
|
||||||
|
|
||||||
for (let i in keys)
|
|
||||||
this._buttonKeys[keys[i]] = buttonInfo;
|
|
||||||
|
|
||||||
this.buttonLayout.add_actor(button);
|
|
||||||
|
|
||||||
return button;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onKeyPressEvent: function(object, event) {
|
|
||||||
this._pressedKey = event.get_key_symbol();
|
|
||||||
return Clutter.EVENT_PROPAGATE;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onKeyReleaseEvent: function(object, event) {
|
|
||||||
let pressedKey = this._pressedKey;
|
|
||||||
this._pressedKey = null;
|
|
||||||
|
|
||||||
let symbol = event.get_key_symbol();
|
|
||||||
if (symbol != pressedKey)
|
|
||||||
return Clutter.EVENT_PROPAGATE;
|
|
||||||
|
|
||||||
let buttonInfo = this._buttonKeys[symbol];
|
|
||||||
if (!buttonInfo)
|
|
||||||
return Clutter.EVENT_PROPAGATE;
|
|
||||||
|
|
||||||
let button = buttonInfo['button'];
|
|
||||||
let action = buttonInfo['action'];
|
|
||||||
|
|
||||||
if (action && button.reactive) {
|
|
||||||
action();
|
|
||||||
return Clutter.EVENT_STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Clutter.EVENT_PROPAGATE;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onGroupDestroy: function() {
|
_onGroupDestroy: function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user