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
|
// Show new workspacesView
|
||||||
this._group.add_actor(this._workspaces.actor);
|
this._group.add_actor(this._workspaces.actor);
|
||||||
this._dash.actor.raise(this._workspaces.actor);
|
this._dash.actor.raise(this._workspaces.actor);
|
||||||
|
|
||||||
// Set new position and scale to workspaces.
|
|
||||||
this.emit('showing');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_recalculateGridSizes: function () {
|
_recalculateGridSizes: function () {
|
||||||
|
@ -1212,6 +1212,9 @@ Workspace.prototype = {
|
|||||||
cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
|
cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
|
||||||
cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
|
cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
|
||||||
|
|
||||||
|
if (!this._windowOverlaysGroup.visible)
|
||||||
|
this._windowOverlaysGroup.show();
|
||||||
|
|
||||||
if (overlay) {
|
if (overlay) {
|
||||||
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
|
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
|
||||||
overlay.fadeIn();
|
overlay.fadeIn();
|
||||||
|
@ -55,7 +55,10 @@ GenericWorkspacesView.prototype = {
|
|||||||
let node = this.actor.get_theme_node();
|
let node = this.actor.get_theme_node();
|
||||||
let [a, spacing] = node.get_length('spacing', false);
|
let [a, spacing] = node.get_length('spacing', false);
|
||||||
this._spacing = spacing;
|
this._spacing = spacing;
|
||||||
this._positionWorkspaces();
|
if (Main.overview.animationInProgress)
|
||||||
|
this._positionWorkspaces();
|
||||||
|
else
|
||||||
|
this._transitionWorkspaces();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._width = width;
|
this._width = width;
|
||||||
@ -248,6 +251,10 @@ GenericWorkspacesView.prototype = {
|
|||||||
throw new Error("Not implemented");
|
throw new Error("Not implemented");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_transitionWorkspaces: function() {
|
||||||
|
throw new Error("Not implemented");
|
||||||
|
},
|
||||||
|
|
||||||
_positionWorkspaces: function() {
|
_positionWorkspaces: function() {
|
||||||
throw new Error("Not implemented");
|
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) {
|
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces, lostWorkspaces) {
|
||||||
let oldScale = this._workspaces[0].scale;
|
let oldScale = this._workspaces[0].scale;
|
||||||
let oldGridWidth = Math.ceil(Math.sqrt(oldNumWorkspaces));
|
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;
|
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) {
|
_scrollToActive: function(showAnimation) {
|
||||||
let active = global.screen.get_active_workspace_index();
|
let active = global.screen.get_active_workspace_index();
|
||||||
|
|
||||||
@ -1228,11 +1323,9 @@ function WorkspacesControls() {
|
|||||||
WorkspacesControls.prototype = {
|
WorkspacesControls.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ style_class: 'workspaces-bar' });
|
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._gconf = Shell.GConf.get_default();
|
||||||
this._addButton = null;
|
|
||||||
this._removeButton = null;
|
|
||||||
|
|
||||||
let view = this._gconf.get_string(WORKSPACES_VIEW_KEY).toUpperCase();
|
let view = this._gconf.get_string(WORKSPACES_VIEW_KEY).toUpperCase();
|
||||||
if (view in WorkspacesViewType)
|
if (view in WorkspacesViewType)
|
||||||
@ -1240,30 +1333,7 @@ WorkspacesControls.prototype = {
|
|||||||
else
|
else
|
||||||
this._currentViewType = WorkspacesViewType.SINGLE;
|
this._currentViewType = WorkspacesViewType.SINGLE;
|
||||||
|
|
||||||
this._nWorkspacesNotifyId =
|
this._currentView = null;
|
||||||
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();
|
|
||||||
|
|
||||||
// View switcher button
|
// View switcher button
|
||||||
this._toggleViewButton = new St.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 });
|
this.actor.add(this._toggleViewButton, { y_fill: false, y_align: St.Align.START });
|
||||||
|
|
||||||
// View specific controls
|
// View specific controls
|
||||||
let viewControls = currentView.createControllerBar();
|
this._viewControls = new St.Bin({ x_fill: true, y_fill: true });
|
||||||
if (!viewControls)
|
this.actor.add(this._viewControls, { expand: true, x_fill: true });
|
||||||
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 });
|
|
||||||
|
|
||||||
// Add/remove workspace buttons
|
// Add/remove workspace buttons
|
||||||
this._removeButton = new St.Button({ style_class: 'workspace-controls remove' });
|
this._removeButton = new St.Button({ style_class: 'workspace-controls remove' });
|
||||||
this._removeButton.connect('clicked', Lang.bind(this, function() {
|
this._removeButton.connect('clicked', Lang.bind(this, function() {
|
||||||
currentView.removeWorkspace();
|
this._currentView.removeWorkspace();
|
||||||
}));
|
}));
|
||||||
this.actor.add(this._removeButton, { y_fill: false,
|
this.actor.add(this._removeButton, { y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
this._addButton = new St.Button({ style_class: 'workspace-controls add' });
|
this._addButton = new St.Button({ style_class: 'workspace-controls add' });
|
||||||
this._addButton.connect('clicked', Lang.bind(this, function() {
|
this._addButton.connect('clicked', Lang.bind(this, function() {
|
||||||
currentView.addWorkspace()
|
this._currentView.addWorkspace()
|
||||||
}));
|
}));
|
||||||
this._addButton._delegate = this._addButton;
|
this._addButton._delegate = this._addButton;
|
||||||
this._addButton._delegate.acceptDrop = Lang.bind(this,
|
this._addButton._delegate.acceptDrop = Lang.bind(this,
|
||||||
function(source, actor, x, y, time) {
|
function(source, actor, x, y, time) {
|
||||||
let view = currentView;
|
return this._currentView._acceptNewWorkspaceDrop(source, actor, x, y, time);
|
||||||
return view._acceptNewWorkspaceDrop(source, actor, x, y, time);
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
this.actor.add(this._addButton, { y_fill: false,
|
this.actor.add(this._addButton, { y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
this._nWorkspacesNotifyId =
|
||||||
|
global.screen.connect('notify::n-workspaces',
|
||||||
|
Lang.bind(this, this._workspacesChanged));
|
||||||
|
|
||||||
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) {
|
setCanRemove: function(canRemove) {
|
||||||
this._setButtonSensitivity(this._removeButton, canRemove);
|
this._setButtonSensitivity(this._removeButton, canRemove);
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user