dash: Animate item and size changes
In general, all changes in the shell interface should be backed by animations to give the interface a more natural feel and provide feedback of what's happening. Currently the dash violates that principle, as items simply appear/disappear or change size abruptly, so add animations for application list and icon size changes. https://bugzilla.gnome.org/show_bug.cgi?id=636156
This commit is contained in:
parent
29e97a5f88
commit
d6020f1402
167
js/ui/dash.js
167
js/ui/dash.js
@ -14,8 +14,11 @@ const AppFavorites = imports.ui.appFavorites;
|
|||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
const Workspace = imports.ui.workspace;
|
const Workspace = imports.ui.workspace;
|
||||||
|
|
||||||
|
const DASH_ANIMATION_TIME = 0.2;
|
||||||
|
|
||||||
// A container like StBin, but taking the child's scale into account
|
// A container like StBin, but taking the child's scale into account
|
||||||
// when requesting a size
|
// when requesting a size
|
||||||
function DashItemContainer() {
|
function DashItemContainer() {
|
||||||
@ -34,6 +37,8 @@ DashItemContainer.prototype = {
|
|||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this.child = null;
|
this.child = null;
|
||||||
|
this._childScale = 1;
|
||||||
|
this._childOpacity = 255;
|
||||||
},
|
},
|
||||||
|
|
||||||
_allocate: function(actor, box, flags) {
|
_allocate: function(actor, box, flags) {
|
||||||
@ -90,6 +95,67 @@ DashItemContainer.prototype = {
|
|||||||
|
|
||||||
this.child = actor;
|
this.child = actor;
|
||||||
this.actor.add_actor(this.child);
|
this.actor.add_actor(this.child);
|
||||||
|
},
|
||||||
|
|
||||||
|
animateIn: function() {
|
||||||
|
if (this.child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.childScale = 0;
|
||||||
|
this.childOpacity = 0;
|
||||||
|
Tweener.addTween(this,
|
||||||
|
{ childScale: 1.0,
|
||||||
|
childOpacity: 255,
|
||||||
|
time: DASH_ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
animateOutAndDestroy: function() {
|
||||||
|
if (this.child == null) {
|
||||||
|
this.actor.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.childScale = 1.0;
|
||||||
|
Tweener.addTween(this,
|
||||||
|
{ childScale: 0.0,
|
||||||
|
childOpacity: 0,
|
||||||
|
time: DASH_ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: Lang.bind(this, function() {
|
||||||
|
this.actor.destroy();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
set childScale(scale) {
|
||||||
|
this._childScale = scale;
|
||||||
|
|
||||||
|
if (this.child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.child.set_scale_with_gravity(scale, scale,
|
||||||
|
Clutter.Gravity.CENTER);
|
||||||
|
this.actor.queue_relayout();
|
||||||
|
},
|
||||||
|
|
||||||
|
get childScale() {
|
||||||
|
return this._childScale;
|
||||||
|
},
|
||||||
|
|
||||||
|
set childOpacity(opacity) {
|
||||||
|
this._childOpacity = opacity;
|
||||||
|
|
||||||
|
if (this.child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.child.set_opacity(opacity);
|
||||||
|
this.actor.queue_redraw();
|
||||||
|
},
|
||||||
|
|
||||||
|
get childOpacity() {
|
||||||
|
return this._childOpacity;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -113,6 +179,12 @@ RemoveFavoriteIcon.prototype = {
|
|||||||
this._iconBin._delegate = this;
|
this._iconBin._delegate = this;
|
||||||
|
|
||||||
this.setChild(this._iconBin);
|
this.setChild(this._iconBin);
|
||||||
|
this.hiding = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
animateOutAndDestroy: function() {
|
||||||
|
DashItemContainer.prototype.animateOutAndDestroy.call(this);
|
||||||
|
this.hiding = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_createIcon: function(size) {
|
_createIcon: function(size) {
|
||||||
@ -181,6 +253,7 @@ Dash.prototype = {
|
|||||||
|
|
||||||
this._dragPlaceholder = null;
|
this._dragPlaceholder = null;
|
||||||
this._dragPlaceholderPos = -1;
|
this._dragPlaceholderPos = -1;
|
||||||
|
this._animatingPlaceholdersCount = 0;
|
||||||
this._favRemoveTarget = null;
|
this._favRemoveTarget = null;
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ name: 'dash',
|
this._box = new St.BoxLayout({ name: 'dash',
|
||||||
@ -234,9 +307,15 @@ Dash.prototype = {
|
|||||||
_onDragEnd: function() {
|
_onDragEnd: function() {
|
||||||
this._clearDragPlaceholder();
|
this._clearDragPlaceholder();
|
||||||
if (this._favRemoveTarget) {
|
if (this._favRemoveTarget) {
|
||||||
this._favRemoveTarget.actor.destroy();
|
this._favRemoveTarget.actor.hide();
|
||||||
this._adjustIconSize();
|
this._adjustIconSize();
|
||||||
|
this._favRemoveTarget.actor.show();
|
||||||
|
|
||||||
|
this._favRemoveTarget.animateOutAndDestroy();
|
||||||
|
this._favRemoveTarget.actor.connect('destroy', Lang.bind(this,
|
||||||
|
function() {
|
||||||
this._favRemoveTarget = null;
|
this._favRemoveTarget = null;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
DND.removeMonitor(this._dragMonitor);
|
DND.removeMonitor(this._dragMonitor);
|
||||||
},
|
},
|
||||||
@ -261,6 +340,7 @@ Dash.prototype = {
|
|||||||
this._favRemoveTarget.icon.setIconSize(this._iconSize);
|
this._favRemoveTarget.icon.setIconSize(this._iconSize);
|
||||||
this._box.add(this._favRemoveTarget.actor);
|
this._box.add(this._favRemoveTarget.actor);
|
||||||
this._adjustIconSize();
|
this._adjustIconSize();
|
||||||
|
this._favRemoveTarget.animateIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
let favRemoveHovered = false;
|
let favRemoveHovered = false;
|
||||||
@ -343,11 +423,29 @@ Dash.prototype = {
|
|||||||
if (newIconSize == this._iconSize)
|
if (newIconSize == this._iconSize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let oldIconSize = this._iconSize;
|
||||||
this._iconSize = newIconSize;
|
this._iconSize = newIconSize;
|
||||||
|
|
||||||
|
let scale = oldIconSize / newIconSize;
|
||||||
for (let i = 0; i < iconChildren.length; i++) {
|
for (let i = 0; i < iconChildren.length; i++) {
|
||||||
let icon = iconChildren[i]._delegate.child._delegate.icon;
|
let icon = iconChildren[i]._delegate.child._delegate.icon;
|
||||||
|
|
||||||
|
// Set the new size immediately, to keep the icons' sizes
|
||||||
|
// in sync with this._iconSize
|
||||||
icon.setIconSize(this._iconSize);
|
icon.setIconSize(this._iconSize);
|
||||||
|
let [targetWidth, targetHeight] = icon.icon.get_size();
|
||||||
|
|
||||||
|
// Scale the icon's texture to the previous size and
|
||||||
|
// tween to the new size
|
||||||
|
icon.icon.set_size(icon.icon.width * scale,
|
||||||
|
icon.icon.height * scale);
|
||||||
|
|
||||||
|
Tweener.addTween(icon.icon,
|
||||||
|
{ width: targetWidth,
|
||||||
|
height: targetHeight,
|
||||||
|
time: DASH_ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -452,15 +550,33 @@ Dash.prototype = {
|
|||||||
this._box.insert_actor(addedItems[i].item.actor,
|
this._box.insert_actor(addedItems[i].item.actor,
|
||||||
addedItems[i].pos);
|
addedItems[i].pos);
|
||||||
|
|
||||||
|
// Hide removed actors to not take them into account
|
||||||
|
// when adjusting the icon size ...
|
||||||
for (let i = 0; i < removedActors.length; i++)
|
for (let i = 0; i < removedActors.length; i++)
|
||||||
removedActors[i].destroy();
|
removedActors[i].hide();
|
||||||
|
|
||||||
|
// ... and do the same for the remove target if necessary
|
||||||
|
if (this._favRemoveTarget && this._favRemoveTarget.hiding)
|
||||||
|
this._favRemoveTarget.actor.hide();
|
||||||
|
|
||||||
this._adjustIconSize();
|
this._adjustIconSize();
|
||||||
|
|
||||||
|
if (this._favRemoveTarget && this._favRemoveTarget.hiding)
|
||||||
|
this._favRemoveTarget.actor.show();
|
||||||
|
|
||||||
|
for (let i = 0; i < removedActors.length; i++) {
|
||||||
|
removedActors[i].show();
|
||||||
|
let item = removedActors[i]._delegate;
|
||||||
|
item.animateOutAndDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < addedItems.length; i++)
|
||||||
|
addedItems[i].item.animateIn();
|
||||||
},
|
},
|
||||||
|
|
||||||
_clearDragPlaceholder: function() {
|
_clearDragPlaceholder: function() {
|
||||||
if (this._dragPlaceholder) {
|
if (this._dragPlaceholder) {
|
||||||
this._dragPlaceholder.actor.destroy();
|
this._dragPlaceholder.animateOutAndDestroy();
|
||||||
this._dragPlaceholder = null;
|
this._dragPlaceholder = null;
|
||||||
this._dragPlaceholderPos = -1;
|
this._dragPlaceholderPos = -1;
|
||||||
}
|
}
|
||||||
@ -482,7 +598,8 @@ Dash.prototype = {
|
|||||||
|
|
||||||
let favPos = favorites.indexOf(app);
|
let favPos = favorites.indexOf(app);
|
||||||
|
|
||||||
let numChildren = this._box.get_children().length;
|
let children = this._box.get_children();
|
||||||
|
let numChildren = children.length;
|
||||||
let boxHeight = this._box.height;
|
let boxHeight = this._box.height;
|
||||||
|
|
||||||
// Keep the placeholder out of the index calculation; assuming that
|
// Keep the placeholder out of the index calculation; assuming that
|
||||||
@ -496,17 +613,49 @@ Dash.prototype = {
|
|||||||
let pos = Math.round(y * numChildren / boxHeight);
|
let pos = Math.round(y * numChildren / boxHeight);
|
||||||
|
|
||||||
if (pos != this._dragPlaceholderPos && pos <= numFavorites) {
|
if (pos != this._dragPlaceholderPos && pos <= numFavorites) {
|
||||||
|
if (this._animatingPlaceholdersCount > 0) {
|
||||||
|
let appChildren = children.filter(function(actor) {
|
||||||
|
return actor._delegate &&
|
||||||
|
actor._delegate.child &&
|
||||||
|
actor._delegate.child._delegate &&
|
||||||
|
actor._delegate.child._delegate.app;
|
||||||
|
});
|
||||||
|
this._dragPlaceholderPos = children.indexOf(appChildren[pos]);
|
||||||
|
} else {
|
||||||
this._dragPlaceholderPos = pos;
|
this._dragPlaceholderPos = pos;
|
||||||
if (this._dragPlaceholder)
|
}
|
||||||
this._dragPlaceholder.actor.destroy();
|
|
||||||
|
|
||||||
// Don't allow positioning before or after self
|
// Don't allow positioning before or after self
|
||||||
if (favPos != -1 && (pos == favPos || pos == favPos + 1))
|
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
|
||||||
|
if (this._dragPlaceholder) {
|
||||||
|
this._dragPlaceholder.animateOutAndDestroy();
|
||||||
|
this._animatingPlaceholdersCount++;
|
||||||
|
this._dragPlaceholder.actor.connect('destroy',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._animatingPlaceholdersCount--;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
this._dragPlaceholder = null;
|
||||||
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the placeholder already exists, we just move
|
||||||
|
// it, but if we are adding it, expand its size in
|
||||||
|
// an animation
|
||||||
|
let fadeIn;
|
||||||
|
if (this._dragPlaceholder) {
|
||||||
|
this._dragPlaceholder.actor.destroy();
|
||||||
|
fadeIn = false;
|
||||||
|
} else {
|
||||||
|
fadeIn = true;
|
||||||
|
}
|
||||||
|
|
||||||
this._dragPlaceholder = new DragPlaceholderItem();
|
this._dragPlaceholder = new DragPlaceholderItem();
|
||||||
this._box.insert_actor(this._dragPlaceholder.actor,
|
this._box.insert_actor(this._dragPlaceholder.actor,
|
||||||
this._dragPlaceholderPos);
|
this._dragPlaceholderPos);
|
||||||
|
if (fadeIn)
|
||||||
|
this._dragPlaceholder.animateIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
let srcIsFavorite = (favPos != -1);
|
let srcIsFavorite = (favPos != -1);
|
||||||
@ -540,6 +689,10 @@ Dash.prototype = {
|
|||||||
let favPos = 0;
|
let favPos = 0;
|
||||||
let children = this._box.get_children();
|
let children = this._box.get_children();
|
||||||
for (let i = 0; i < this._dragPlaceholderPos; i++) {
|
for (let i = 0; i < this._dragPlaceholderPos; i++) {
|
||||||
|
if (this._dragPlaceholder &&
|
||||||
|
children[i] == this._dragPlaceholder.actor)
|
||||||
|
continue;
|
||||||
|
|
||||||
let childId = children[i]._delegate.child._delegate.app.get_id();
|
let childId = children[i]._delegate.child._delegate.app.get_id();
|
||||||
if (childId == id)
|
if (childId == id)
|
||||||
continue;
|
continue;
|
||||||
|
Loading…
Reference in New Issue
Block a user