Animate workspace view switches
Replace the hard switch between linear and mosaic workspace view with a an animated transition between the views. https://bugzilla.gnome.org/show_bug.cgi?id=610191
This commit is contained in:
parent
a9fea8248c
commit
5a6c9f176e
@ -263,9 +263,6 @@ Overview.prototype = {
|
||||
// Show new workspacesView
|
||||
this._group.add_actor(this._workspaces.actor);
|
||||
this._dash.actor.raise(this._workspaces.actor);
|
||||
|
||||
// Set new position and scale to workspaces.
|
||||
this.emit('showing');
|
||||
},
|
||||
|
||||
_recalculateGridSizes: function () {
|
||||
|
@ -1212,6 +1212,9 @@ Workspace.prototype = {
|
||||
cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
|
||||
cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
|
||||
|
||||
if (!this._windowOverlaysGroup.visible)
|
||||
this._windowOverlaysGroup.show();
|
||||
|
||||
if (overlay) {
|
||||
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
|
||||
overlay.fadeIn();
|
||||
|
@ -55,7 +55,10 @@ GenericWorkspacesView.prototype = {
|
||||
let node = this.actor.get_theme_node();
|
||||
let [a, spacing] = node.get_length('spacing', false);
|
||||
this._spacing = spacing;
|
||||
if (Main.overview.animationInProgress)
|
||||
this._positionWorkspaces();
|
||||
else
|
||||
this._transitionWorkspaces();
|
||||
}));
|
||||
|
||||
this._width = width;
|
||||
@ -248,6 +251,10 @@ GenericWorkspacesView.prototype = {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
|
||||
_transitionWorkspaces: function() {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
|
||||
_positionWorkspaces: function() {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
@ -326,6 +333,54 @@ MosaicView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_transitionWorkspaces: function() {
|
||||
// update workspace parameters
|
||||
this._positionWorkspaces();
|
||||
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace = this._workspaces[active];
|
||||
// scale is the factor needed to translate from the new scale
|
||||
// (this view) to the currently active scale (previous view)
|
||||
let scale = this._workspaces[0].actor.scale_x / activeWorkspace.scale;
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++) {
|
||||
let workspace = this._workspaces[w];
|
||||
let originX, originY;
|
||||
let dx, dy;
|
||||
|
||||
// The correct transition would be a straightforward animation
|
||||
// of each workspace's old position/scale to the new one;
|
||||
// however, this looks overly busy, so we only use a zoom effect.
|
||||
// Unfortunately this implies that we cannot pretend to not knowing
|
||||
// the other view's layout at this point:
|
||||
// We position the workspaces in the grid, which we scale up so
|
||||
// that the active workspace fills the viewport.
|
||||
dx = workspace.gridX - activeWorkspace.gridX;
|
||||
dy = workspace.gridY - activeWorkspace.gridY;
|
||||
originX = this._x + scale * dx;
|
||||
originY = this._y + scale * dy;
|
||||
|
||||
workspace.actor.set_position(originX, originY);
|
||||
|
||||
workspace.positionWindows(Workspace.WindowPositionFlags.ANIMATE);
|
||||
workspace.setSelected(false);
|
||||
workspace.hideWindowsOverlays();
|
||||
|
||||
Tweener.addTween(workspace.actor,
|
||||
{ x: workspace.gridX,
|
||||
y: workspace.gridY,
|
||||
scale_x: workspace.scale,
|
||||
scale_y: workspace.scale,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
workspace.zoomToOverview(false);
|
||||
if (workspace.metaWorkspace.index() == active)
|
||||
workspace.setSelected(true);
|
||||
}});
|
||||
}
|
||||
},
|
||||
|
||||
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces, lostWorkspaces) {
|
||||
let oldScale = this._workspaces[0].scale;
|
||||
let oldGridWidth = Math.ceil(Math.sqrt(oldNumWorkspaces));
|
||||
@ -529,6 +584,46 @@ SingleView.prototype = {
|
||||
this._rightShadow.gridY = this._y + (this._height - this._rightShadow.height * scale) / 2;
|
||||
},
|
||||
|
||||
_transitionWorkspaces: function() {
|
||||
// update workspace parameters
|
||||
this._positionWorkspaces();
|
||||
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
let activeActor = this._workspaces[active].actor;
|
||||
// scale is the factor needed to translate from the currently
|
||||
// active scale (previous view) to the new scale (this view)
|
||||
let scale = this._workspaces[active].scale / activeActor.scale_x;
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++) {
|
||||
let workspace = this._workspaces[w];
|
||||
let targetX, targetY;
|
||||
|
||||
// The correct transition would be a straightforward animation
|
||||
// of each workspace's old position/scale to the new one;
|
||||
// however, this looks overly busy, so we only use a zoom effect.
|
||||
// Therefore we scale up each workspace's distance to the active
|
||||
// workspace, so the latter fills the viewport while the other
|
||||
// workspaces maintain their relative position
|
||||
targetX = this._x + scale * (workspace.actor.x - activeActor.x);
|
||||
targetY = this._y + scale * (workspace.actor.y - activeActor.y);
|
||||
|
||||
workspace.positionWindows(Workspace.WindowPositionFlags.ANIMATE);
|
||||
workspace.setSelected(false);
|
||||
workspace._hideAllOverlays();
|
||||
|
||||
Tweener.addTween(workspace.actor,
|
||||
{ x: targetX,
|
||||
y: targetY,
|
||||
scale_x: workspace.scale,
|
||||
scale_y: workspace.scale,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
workspace.zoomToOverview(false);
|
||||
}});
|
||||
}
|
||||
},
|
||||
|
||||
_scrollToActive: function(showAnimation) {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
|
||||
@ -1228,11 +1323,9 @@ function WorkspacesControls() {
|
||||
WorkspacesControls.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ style_class: 'workspaces-bar' });
|
||||
this._gconf = Shell.GConf.get_default();
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._toggleViewButton = null;
|
||||
this._addButton = null;
|
||||
this._removeButton = null;
|
||||
this._gconf = Shell.GConf.get_default();
|
||||
|
||||
let view = this._gconf.get_string(WORKSPACES_VIEW_KEY).toUpperCase();
|
||||
if (view in WorkspacesViewType)
|
||||
@ -1240,30 +1333,7 @@ WorkspacesControls.prototype = {
|
||||
else
|
||||
this._currentViewType = WorkspacesViewType.SINGLE;
|
||||
|
||||
this._nWorkspacesNotifyId =
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._workspacesChanged));
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
},
|
||||
|
||||
_updateToggleButtonStyle: function() {
|
||||
if (this._currentViewType == WorkspacesViewType.SINGLE)
|
||||
this._toggleViewButton.set_style_class_name('workspace-controls switch-mosaic');
|
||||
else
|
||||
this._toggleViewButton.set_style_class_name('workspace-controls switch-single');
|
||||
},
|
||||
|
||||
_setView: function(view) {
|
||||
if (this._currentViewType == view)
|
||||
return;
|
||||
this._currentViewType = view;
|
||||
this._updateToggleButtonStyle();
|
||||
this._gconf.set_string(WORKSPACES_VIEW_KEY, view);
|
||||
},
|
||||
|
||||
updateControls: function(currentView) {
|
||||
this.actor.remove_all();
|
||||
this._currentView = null;
|
||||
|
||||
// View switcher button
|
||||
this._toggleViewButton = new St.Button();
|
||||
@ -1279,40 +1349,79 @@ WorkspacesControls.prototype = {
|
||||
this.actor.add(this._toggleViewButton, { y_fill: false, y_align: St.Align.START });
|
||||
|
||||
// View specific controls
|
||||
let viewControls = currentView.createControllerBar();
|
||||
if (!viewControls)
|
||||
viewControls = new St.Bin();
|
||||
this.actor.add(viewControls, { expand: true,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
y_align: St.Align.MIDDLE,
|
||||
x_align: St.Align.START });
|
||||
this._viewControls = new St.Bin({ x_fill: true, y_fill: true });
|
||||
this.actor.add(this._viewControls, { expand: true, x_fill: true });
|
||||
|
||||
// Add/remove workspace buttons
|
||||
this._removeButton = new St.Button({ style_class: 'workspace-controls remove' });
|
||||
this._removeButton.connect('clicked', Lang.bind(this, function() {
|
||||
currentView.removeWorkspace();
|
||||
this._currentView.removeWorkspace();
|
||||
}));
|
||||
this.actor.add(this._removeButton, { y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._addButton = new St.Button({ style_class: 'workspace-controls add' });
|
||||
this._addButton.connect('clicked', Lang.bind(this, function() {
|
||||
currentView.addWorkspace()
|
||||
this._currentView.addWorkspace()
|
||||
}));
|
||||
this._addButton._delegate = this._addButton;
|
||||
this._addButton._delegate.acceptDrop = Lang.bind(this,
|
||||
function(source, actor, x, y, time) {
|
||||
let view = currentView;
|
||||
return view._acceptNewWorkspaceDrop(source, actor, x, y, time);
|
||||
return false;
|
||||
return this._currentView._acceptNewWorkspaceDrop(source, actor, x, y, time);
|
||||
});
|
||||
this.actor.add(this._addButton, { y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._nWorkspacesNotifyId =
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._workspacesChanged));
|
||||
|
||||
this._workspacesChanged();
|
||||
},
|
||||
|
||||
updateControls: function(view) {
|
||||
this._currentView = view;
|
||||
|
||||
let newControls = this._currentView.createControllerBar();
|
||||
if (newControls) {
|
||||
this._viewControls.child = newControls;
|
||||
this._viewControls.child.opacity = 0;
|
||||
Tweener.addTween(this._viewControls.child,
|
||||
{ opacity: 255,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
} else {
|
||||
if (this._viewControls.child)
|
||||
Tweener.addTween(this._viewControls.child,
|
||||
{ opacity: 0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this._viewControls.child.destroy();
|
||||
})});
|
||||
}
|
||||
},
|
||||
|
||||
_updateToggleButtonStyle: function() {
|
||||
if (this._currentViewType == WorkspacesViewType.SINGLE)
|
||||
this._toggleViewButton.set_style_class_name('workspace-controls switch-mosaic');
|
||||
else
|
||||
this._toggleViewButton.set_style_class_name('workspace-controls switch-single');
|
||||
},
|
||||
|
||||
_setView: function(view) {
|
||||
if (this._currentViewType == view)
|
||||
return;
|
||||
|
||||
if (WorkspacesViewType.SINGLE == view)
|
||||
this._toggleViewButton.set_style_class_name('workspace-controls switch-mosaic');
|
||||
else
|
||||
this._toggleViewButton.set_style_class_name('workspace-controls switch-single');
|
||||
|
||||
this._currentViewType = view;
|
||||
this._gconf.set_string(WORKSPACES_VIEW_KEY, view);
|
||||
},
|
||||
|
||||
setCanRemove: function(canRemove) {
|
||||
this._setButtonSensitivity(this._removeButton, canRemove);
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user