appDisplay: Animate appIcon for new window of apps

Following design mockups, animate the icons on AllView, FrequentView,
Dash and Search to zoom out when opening a new window of the app or when
the app is not running and the user execute it.

https://bugzilla.gnome.org/show_bug.cgi?id=734726
This commit is contained in:
Carlos Soriano 2014-06-17 21:31:53 +02:00
parent 67c216a6fe
commit 62786c09a8
3 changed files with 68 additions and 0 deletions

View File

@ -1699,6 +1699,9 @@ const AppIcon = new Lang.Class({
this.app.state == Shell.AppState.RUNNING || this.app.state == Shell.AppState.RUNNING ||
button && button == 2; button && button == 2;
if (this.app.state == Shell.AppState.STOPPED || openNewWindow)
this.animateLaunch();
if (openNewWindow) if (openNewWindow)
this.app.open_new_window(-1); this.app.open_new_window(-1);
else else
@ -1707,6 +1710,10 @@ const AppIcon = new Lang.Class({
Main.overview.hide(); Main.overview.hide();
}, },
animateLaunch: function() {
this.icon.animateZoomOut();
},
shellWorkspaceLaunch : function(params) { shellWorkspaceLaunch : function(params) {
params = Params.parse(params, { workspace: -1, params = Params.parse(params, { workspace: -1,
timestamp: 0 }); timestamp: 0 });
@ -1788,6 +1795,9 @@ const AppIconMenu = new Lang.Class({
if (this._source.app.can_open_new_window()) { if (this._source.app.can_open_new_window()) {
this._newWindowMenuItem = this._appendMenuItem(_("New Window")); this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
this._newWindowMenuItem.connect('activate', Lang.bind(this, function() { this._newWindowMenuItem.connect('activate', Lang.bind(this, function() {
if (this._source.app.state == Shell.AppState.STOPPED)
this._source.animateLaunch();
this._source.app.open_new_window(-1); this._source.app.open_new_window(-1);
this.emit('activate-window', null); this.emit('activate-window', null);
})); }));

View File

@ -30,6 +30,9 @@ const AnimationDirection = {
OUT: 1 OUT: 1
}; };
const APPICON_ANIMATION_OUT_SCALE = 3;
const APPICON_ANIMATION_OUT_TIME = 0.25;
const BaseIcon = new Lang.Class({ const BaseIcon = new Lang.Class({
Name: 'BaseIcon', Name: 'BaseIcon',
@ -187,9 +190,55 @@ const BaseIcon = new Lang.Class({
_onIconThemeChanged: function() { _onIconThemeChanged: function() {
this._createIconTexture(this.iconSize); this._createIconTexture(this.iconSize);
},
animateZoomOut: function() {
// Animate only the child instead of the entire actor, so the
// styles like hover and running are not applied while
// animating.
zoomOutActor(this.actor.child);
} }
}); });
function clamp(value, min, max) {
return Math.max(Math.min(value, max), min);
};
function zoomOutActor(actor) {
let actorClone = new Clutter.Clone({ source: actor,
reactive: false });
let [width, height] = actor.get_transformed_size();
let [x, y] = actor.get_transformed_position();
actorClone.set_size(width, height);
actorClone.set_position(x, y);
actorClone.opacity = 255;
actorClone.set_pivot_point(0.5, 0.5);
Main.uiGroup.add_actor(actorClone);
// Avoid monitor edges to not zoom outside the current monitor
let monitor = Main.layoutManager.findMonitorForActor(actor);
let scaledWidth = width * APPICON_ANIMATION_OUT_SCALE;
let scaledHeight = height * APPICON_ANIMATION_OUT_SCALE;
let scaledX = x - (scaledWidth - width) / 2;
let scaledY = y - (scaledHeight - height) / 2;
let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth);
let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight);
Tweener.addTween(actorClone,
{ time: APPICON_ANIMATION_OUT_TIME,
scale_x: APPICON_ANIMATION_OUT_SCALE,
scale_y: APPICON_ANIMATION_OUT_SCALE,
translation_x: containedX - scaledX,
translation_y: containedY - scaledY,
opacity: 0,
transition: 'easeOutQuad',
onComplete: function() {
actorClone.destroy();
}
});
}
const IconGrid = new Lang.Class({ const IconGrid = new Lang.Class({
Name: 'IconGrid', Name: 'IconGrid',

View File

@ -6,6 +6,7 @@ const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
const Signals = imports.signals; const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St; const St = imports.gi.St;
const Atk = imports.gi.Atk; const Atk = imports.gi.Atk;
@ -397,6 +398,7 @@ const ListSearchResults = new Lang.Class({
this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn)); this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this.providerIcon.connect('clicked', Lang.bind(this, this.providerIcon.connect('clicked', Lang.bind(this,
function() { function() {
this.providerIcon.animateLaunch();
provider.launchSearch(this._terms); provider.launchSearch(this._terms);
Main.overview.toggle(); Main.overview.toggle();
})); }));
@ -708,5 +710,12 @@ const ProviderIcon = new Lang.Class({
gicon: provider.appInfo.get_icon() }); gicon: provider.appInfo.get_icon() });
this._content.add_actor(icon); this._content.add_actor(icon);
this._content.add_actor(this.moreIcon); this._content.add_actor(this.moreIcon);
},
animateLaunch: function() {
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app(this.provider.appInfo.get_id());
if (app.state == Shell.AppState.STOPPED)
IconGrid.zoomOutActor(this._content);
} }
}); });