17c46c2452
The last patch in the sequence. Every place that was previously setting prototype has been ported to Lang.Class, to make code more concise and allow for better toString(). https://bugzilla.gnome.org/show_bug.cgi?id=664436
198 lines
6.9 KiB
JavaScript
198 lines
6.9 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
const Lang = imports.lang;
|
|
const Meta = imports.gi.Meta;
|
|
const St = imports.gi.St;
|
|
|
|
const Params = imports.misc.params;
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
/**
|
|
* Lightbox:
|
|
* @container: parent Clutter.Container
|
|
* @params: (optional) additional parameters:
|
|
* - inhibitEvents: whether to inhibit events for @container
|
|
* - width: shade actor width
|
|
* - height: shade actor height
|
|
* - fadeTime: seconds used to fade in/out
|
|
*
|
|
* Lightbox creates a dark translucent "shade" actor to hide the
|
|
* contents of @container, and allows you to specify particular actors
|
|
* in @container to highlight by bringing them above the shade. It
|
|
* tracks added and removed actors in @container while the lightboxing
|
|
* is active, and ensures that all actors are returned to their
|
|
* original stacking order when the lightboxing is removed. (However,
|
|
* if actors are restacked by outside code while the lightboxing is
|
|
* active, the lightbox may later revert them back to their original
|
|
* order.)
|
|
*
|
|
* By default, the shade window will have the height and width of
|
|
* @container and will track any changes in its size. You can override
|
|
* this by passing an explicit width and height in @params.
|
|
*/
|
|
const Lightbox = new Lang.Class({
|
|
Name: 'Lightbox',
|
|
|
|
_init : function(container, params) {
|
|
params = Params.parse(params, { inhibitEvents: false,
|
|
width: null,
|
|
height: null,
|
|
fadeTime: null
|
|
});
|
|
|
|
this._container = container;
|
|
this._children = container.get_children();
|
|
this._fadeTime = params.fadeTime;
|
|
this.actor = new St.Bin({ x: 0,
|
|
y: 0,
|
|
style_class: 'lightbox',
|
|
reactive: params.inhibitEvents });
|
|
|
|
container.add_actor(this.actor);
|
|
this.actor.raise_top();
|
|
this.actor.hide();
|
|
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
if (params.width && params.height) {
|
|
this.actor.width = params.width;
|
|
this.actor.height = params.height;
|
|
this._allocationChangedSignalId = 0;
|
|
} else {
|
|
this.actor.width = container.width;
|
|
this.actor.height = container.height;
|
|
this._allocationChangedSignalId = container.connect('allocation-changed', Lang.bind(this, this._allocationChanged));
|
|
}
|
|
|
|
this._actorAddedSignalId = container.connect('actor-added', Lang.bind(this, this._actorAdded));
|
|
this._actorRemovedSignalId = container.connect('actor-removed', Lang.bind(this, this._actorRemoved));
|
|
|
|
this._highlighted = null;
|
|
},
|
|
|
|
_allocationChanged : function(container, box, flags) {
|
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
|
this.actor.width = this.width;
|
|
this.actor.height = this.height;
|
|
return false;
|
|
}));
|
|
this.width = this._container.width;
|
|
this.height = this._container.height;
|
|
},
|
|
|
|
_actorAdded : function(container, newChild) {
|
|
let children = this._container.get_children();
|
|
let myIndex = children.indexOf(this.actor);
|
|
let newChildIndex = children.indexOf(newChild);
|
|
|
|
if (newChildIndex > myIndex) {
|
|
// The child was added above the shade (presumably it was
|
|
// made the new top-most child). Move it below the shade,
|
|
// and add it to this._children as the new topmost actor.
|
|
newChild.lower(this.actor);
|
|
this._children.push(newChild);
|
|
} else if (newChildIndex == 0) {
|
|
// Bottom of stack
|
|
this._children.unshift(newChild);
|
|
} else {
|
|
// Somewhere else; insert it into the correct spot
|
|
let prevChild = this._children.indexOf(children[newChildIndex - 1]);
|
|
if (prevChild != -1) // paranoia
|
|
this._children.splice(prevChild + 1, 0, newChild);
|
|
}
|
|
},
|
|
|
|
show: function() {
|
|
if (this._fadeTime) {
|
|
this.actor.opacity = 0;
|
|
Tweener.addTween(this.actor,
|
|
{ opacity: 255,
|
|
time: this._fadeTime,
|
|
transition: 'easeOutQuad'
|
|
});
|
|
} else {
|
|
this.actor.opacity = 255;
|
|
}
|
|
this.actor.show();
|
|
},
|
|
|
|
hide: function() {
|
|
if (this._fadeTime) {
|
|
Tweener.addTween(this.actor,
|
|
{ opacity: 0,
|
|
time: this._fadeTime,
|
|
transition: 'easeOutQuad',
|
|
onComplete: Lang.bind(this, function() {
|
|
this.actor.hide();
|
|
})
|
|
});
|
|
} else {
|
|
this.actor.hide();
|
|
}
|
|
},
|
|
|
|
_actorRemoved : function(container, child) {
|
|
let index = this._children.indexOf(child);
|
|
if (index != -1) // paranoia
|
|
this._children.splice(index, 1);
|
|
|
|
if (child == this._highlighted)
|
|
this._highlighted = null;
|
|
},
|
|
|
|
/**
|
|
* highlight:
|
|
* @window: actor to highlight
|
|
*
|
|
* Highlights the indicated actor and unhighlights any other
|
|
* currently-highlighted actor. With no arguments or a false/null
|
|
* argument, all actors will be unhighlighted.
|
|
*/
|
|
highlight : function(window) {
|
|
if (this._highlighted == window)
|
|
return;
|
|
|
|
// Walk this._children raising and lowering actors as needed.
|
|
// Things get a little tricky if the to-be-raised and
|
|
// to-be-lowered actors were originally adjacent, in which
|
|
// case we may need to indicate some *other* actor as the new
|
|
// sibling of the to-be-lowered one.
|
|
|
|
let below = this.actor;
|
|
for (let i = this._children.length - 1; i >= 0; i--) {
|
|
if (this._children[i] == window)
|
|
this._children[i].raise_top();
|
|
else if (this._children[i] == this._highlighted)
|
|
this._children[i].lower(below);
|
|
else
|
|
below = this._children[i];
|
|
}
|
|
|
|
this._highlighted = window;
|
|
},
|
|
|
|
/**
|
|
* destroy:
|
|
*
|
|
* Destroys the lightbox.
|
|
*/
|
|
destroy : function() {
|
|
this.actor.destroy();
|
|
},
|
|
|
|
/**
|
|
* _onDestroy:
|
|
*
|
|
* This is called when the lightbox' actor is destroyed, either
|
|
* by destroying its container or by explicitly calling this.destroy().
|
|
*/
|
|
_onDestroy: function() {
|
|
if (this._allocationChangedSignalId != 0)
|
|
this._container.disconnect(this._allocationChangedSignalId);
|
|
this._container.disconnect(this._actorAddedSignalId);
|
|
this._container.disconnect(this._actorRemovedSignalId);
|
|
|
|
this.highlight(null);
|
|
}
|
|
});
|