[gnome-shell] Bug 584609 - Zoom the whole overlay when showing or hiding



commit 1f31e80c470db30e1569443629dcf8b9ef1fcbfb
Author: Sander Dijkhuis <sander dijkhuis gmail com>
Date:   Tue Aug 11 00:31:39 2009 +0200

    Bug 584609 - Zoom the whole overlay when showing or hiding
    
    Instead of only transforming the active workspace, create a
    zooming effect when showing or hiding the overlay. This makes
    the transitions simpler: the workspaces are now fixed to the
    overlay actor group and will not slide over the Dash.
    
    overlay.js: Add zoom animations, fade in/out Dash during those,
        remove obsolete Dash clipping and stacking logic, add public
        get[Scale|Position]() and getZoomedIn[Scale|Position]()
        functions.
    workspaces.js: Remove zoom animations, add fade animations for
        the remove button, add helper functions for the overlay
        zooming, keep the movement of windows linear to that of
        their workspaces, remove the updatePosition() and
        updateInOverlay() functions and fullSize variables that
        were left from the old overlay design.

 js/ui/overlay.js    |  139 ++++++++++++++++++++-------------------------
 js/ui/workspaces.js |  158 ++++++++++++++++++++++++---------------------------
 2 files changed, 137 insertions(+), 160 deletions(-)
---
diff --git a/js/ui/overlay.js b/js/ui/overlay.js
index 26f436f..f195c90 100644
--- a/js/ui/overlay.js
+++ b/js/ui/overlay.js
@@ -218,6 +218,31 @@ Overlay.prototype = {
 
     //// Public methods ////
 
+    // Returns the scale the overlay has when we just start zooming out
+    // to overview mode. That is, when just the active workspace is showing.
+    getZoomedInScale : function() {
+        return 1 / this._workspaces.getScale();
+    },
+
+    // Returns the position the overlay has when we just start zooming out
+    // to overview mode. That is, when just the active workspace is showing.
+    getZoomedInPosition : function() {
+        let [posX, posY] = this._workspaces.getActiveWorkspacePosition();
+        let scale = this.getZoomedInScale();
+
+        return [- posX * scale, - posY * scale];
+    },
+
+    // Returns the current scale of the overlay.
+    getScale : function() {
+        return this._group.scaleX;
+    },
+
+    // Returns the current position of the overlay.
+    getPosition : function() {
+        return [this._group.x, this._group.y];
+    },
+
     show : function() {
         if (this.visible)
             return;
@@ -262,26 +287,29 @@ Overlay.prototype = {
         global.window_group.hide();
         this._group.show();
 
-        // Try to make the menu not too visible behind the empty space between
-        // the workspace previews by sliding in its clipping rectangle.
-        // We want to finish drawing the Dash just before the top workspace fully
-        // slides in on the top. Which means that we have more time to wait before
-        // drawing the dash if the active workspace is displayed on the bottom of
-        // the workspaces grid, and almost no time to wait if it is displayed in the top
-        // row of the workspaces grid. The calculations used below try to roughly
-        // capture the animation ratio for when workspaces are covering the top of the overlay
-        // vs. when workspaces are already below the top of the overlay, and apply it
-        // to clipping the dash. The clipping is removed in this._showDone().
-        this._dash.actor.set_clip(0, 0,
-                                      this._workspaces.getFullSizeX(),
-                                      this._dash.actor.height);
-        Tweener.addTween(this._dash.actor,
-                         { clipWidthRight: this._dash._width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
+        // Create a zoom out effect. First scale the overlay group up and
+        // position it so that the active workspace fills up the whole screen,
+        // then transform the group to its normal dimensions and position.
+        // The opposite transition is used in hide().
+        this._group.scaleX = this._group.scaleY = this.getZoomedInScale();
+        [this._group.x, this._group.y] = this.getZoomedInPosition();
+        Tweener.addTween(this._group,
+                         { x: 0,
+                           y: 0,
+                           scaleX: 1,
+                           scaleY: 1,
+                           transition: 'easeOutQuad',
                            time: ANIMATION_TIME,
-                           transition: "easeOutQuad",
                            onComplete: this._showDone,
                            onCompleteScope: this
+                          });
 
+        // Make Dash fade in so that it doesn't appear to big.
+        this._dash.actor.opacity = 0;
+        Tweener.addTween(this._dash.actor,
+                         { opacity: 255,
+                           transition: 'easeOutQuad',
+                           time: ANIMATION_TIME
                          });
 
         this.emit('showing');
@@ -297,27 +325,29 @@ Overlay.prototype = {
         this._hideInProgress = true;
         if (this._activeDisplayPane != null)
             this._activeDisplayPane.close();
-        // lower the panes, so that workspaces display is on top while sliding out
-        this._dash.actor.lower(this._workspaces.actor);
         this._workspaces.hide();
 
-        // Try to make the menu not too visible behind the empty space between
-        // the workspace previews by sliding in its clipping rectangle.
-        // The logic used is the same as described in this.show(). If the active workspace
-        // is displayed in the top row, than almost full animation time is needed for it
-        // to reach the top of the overlay and cover the Dash fully, while if the
-        // active workspace is in the lower row, than the top left workspace reaches the
-        // top of the overlay sooner as it is moving out of the way.
-        // The clipping is removed in this._hideDone().
-        this._dash.actor.set_clip(0, 0,
-                                      this._dash.actor.width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
-                                      this._dash.actor.height);
-        Tweener.addTween(this._dash.actor,
-                         { clipWidthRight: this._workspaces.getFullSizeX() + this._workspaces.getWidthToTopActiveWorkspace() - global.screen_width,
+        // Create a zoom in effect by transforming the overlay group so that
+        // the active workspace fills up the whole screen. The opposite
+        // transition is used in show().
+        let scale = this.getZoomedInScale();
+        let [posX, posY] = this.getZoomedInPosition();
+        Tweener.addTween(this._group,
+                         { x: posX,
+                           y: posY,
+                           scaleX: scale,
+                           scaleY: scale,
+                           transition: 'easeOutQuad',
                            time: ANIMATION_TIME,
-                           transition: "easeOutQuad",
                            onComplete: this._hideDone,
                            onCompleteScope: this
+                          });
+
+        // Make Dash fade out so that it doesn't appear to big.
+        Tweener.addTween(this._dash.actor,
+                         { opacity: 0,
+                           transition: 'easeOutQuad',
+                           time: ANIMATION_TIME
                          });
 
         this.emit('hiding');
@@ -347,21 +377,10 @@ Overlay.prototype = {
 
     //// Private methods ////
 
-    // Raises the Dash to the top, so that we can tell if the pointer is above one of its items.
-    // We need to do this once the workspaces are shown because the workspaces actor currently covers
-    // the whole screen, regardless of where the workspaces are actually displayed.
-    //
-    // Once we rework the workspaces actor to only cover the area it actually needs, we can
-    // remove this workaround. Also http://bugzilla.openedhand.com/show_bug.cgi?id=1513 requests being
-    // able to pick only a reactive actor at a certain position, rather than any actor. Being able
-    // to do that would allow us to not have to raise the Dash.
     _showDone: function() {
         if (this._hideInProgress)
             return;
 
-        this._dash.actor.raise_top();
-        this._dash.actor.remove_clip();
-
         this.animationInProgress = false;
 
         this.emit('shown');
@@ -375,7 +394,6 @@ Overlay.prototype = {
         this._workspaces.destroy();
         this._workspaces = null;
 
-        this._dash.actor.remove_clip();
         this._dash.hide();
         this._group.hide();
 
@@ -388,36 +406,3 @@ Overlay.prototype = {
     }
 };
 Signals.addSignalMethods(Overlay.prototype);
-
-Tweener.registerSpecialProperty("clipHeightBottom", _clipHeightBottomGet, _clipHeightBottomSet);
-
-function _clipHeightBottomGet(actor) {
-    let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
-    return clipHeight;
-}
-
-function _clipHeightBottomSet(actor, clipHeight) {
-    actor.set_clip(0, 0, actor.width, clipHeight);
-}
-
-Tweener.registerSpecialProperty("clipHeightTop", _clipHeightTopGet, _clipHeightTopSet);
-
-function _clipHeightTopGet(actor) {
-    let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
-    return clipHeight;
-}
-
-function _clipHeightTopSet(actor, clipHeight) {
-    actor.set_clip(0, actor.height - clipHeight, actor.width, clipHeight);
-}
-
-Tweener.registerSpecialProperty("clipWidthRight", _clipWidthRightGet, _clipWidthRightSet);
-
-function _clipWidthRightGet(actor) {
-    let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
-    return clipWidth;
-}
-
-function _clipWidthRightSet(actor, clipWidth) {
-    actor.set_clip(0, 0, clipWidth, actor.height);
-}
diff --git a/js/ui/workspaces.js b/js/ui/workspaces.js
index 82b7bcc..80ad993 100644
--- a/js/ui/workspaces.js
+++ b/js/ui/workspaces.js
@@ -590,27 +590,25 @@ Workspace.prototype = {
 
     // Animate the full-screen to overlay transition.
     zoomToOverlay : function() {
-        // Move the workspace into size/position
-        this.actor.set_position(this.fullSizeX, this.fullSizeY);
-        
-        this.updateInOverlay();
+        this.actor.set_position(this.gridX, this.gridY);
+        this.actor.set_scale(this.scale, this.scale);
 
-        this._visible = true;
-    },
+        // Position and scale the windows.
+        this.positionWindows(true);
 
-    // Animates the display of a workspace and its windows to have the current dimensions and position.
-    updateInOverlay : function() {
-        Tweener.addTween(this.actor,
-                         { x: this.gridX,
-                           y: this.gridY,
-                           scale_x: this.scale,
-                           scale_y: this.scale,
-                           time: Overlay.ANIMATION_TIME,
-                           transition: "easeOutQuad"
-                         });
+        // Fade in the remove button if available, so that it doesn't appear
+        // too abrubtly and doesn't start at a too big size.
+        if (this._removeButton) {
+            Tweener.removeTweens(this._removeButton);
+            this._removeButton.opacity = 0;
+            Tweener.addTween(this._removeButton,
+                             { opacity: 255,
+                               time: Overlay.ANIMATION_TIME,
+                               transition: 'easeOutQuad'
+                             });
+        }
 
-        // Likewise for each of the windows in the workspace.
-        this.positionWindows(true);
+        this._visible = true;
     },
 
     // Animates the return from overlay mode
@@ -619,17 +617,21 @@ Workspace.prototype = {
 
         this._hideAllIcons();
 
-        Tweener.addTween(this.actor,
-                         { x: this.fullSizeX,
-                           y: this.fullSizeY,
-                           scale_x: 1.0,
-                           scale_y: 1.0,
-                           time: Overlay.ANIMATION_TIME,
-                           transition: "easeOutQuad",
-                           onComplete: this._doneLeavingOverlay,
-                           onCompleteScope: this
-                         });
+        Main.overlay.connect('hidden', Lang.bind(this,
+                                                 this._doneLeavingOverlay));
+
+        // Fade out the remove button if available, so that it doesn't
+        // disappear too abrubtly and doesn't become too big.
+        if (this._removeButton) {
+            Tweener.removeTweens(this._removeButton);
+            Tweener.addTween(this._removeButton,
+                             { opacity: 0,
+                               time: Overlay.ANIMATION_TIME,
+                               transition: 'easeOutQuad'
+                             });
+        }
 
+        // Position and scale the windows.
         for (let i = 1; i < this._windows.length; i++) {
             let clone = this._windows[i];
             Tweener.addTween(clone.actor,
@@ -906,9 +908,15 @@ Workspaces.prototype = {
         let lastWorkspace = this._workspaces[this._workspaces.length - 1];
         lastWorkspace.updateRemovable(true);
 
-        // Position/scale the desktop windows and their children
-        for (let w = 0; w < this._workspaces.length; w++)
-            this._workspaces[w].zoomToOverlay();
+        // Position/scale the desktop windows and their children after the
+        // workspaces have been created. This cannot be done first because
+        // window movement depends on the Workspaces object being accessible
+        // as an Overlay member.
+        Main.overlay.connect('showing',
+                             Lang.bind(this, function() {
+            for (let w = 0; w < this._workspaces.length; w++)
+                this._workspaces[w].zoomToOverlay();
+        }));
 
         // Track changes to the number of workspaces
         this._nWorkspacesNotifyId =
@@ -945,17 +953,6 @@ Workspaces.prototype = {
         }
     },
 
-    // Updates position of the workspaces display based on the new coordinates.
-    // Preserves the old value for the coordinate, if the passed value is null.
-    updatePosition : function(x, y) {
-        if (x != null)
-            this._x = x;
-        if (y != null)
-            this._y = y;
-
-        this._updateInOverlay();
-    },
-
     hide : function() {
         let global = Shell.Global.get();
         let activeWorkspaceIndex = global.screen.get_active_workspace_index();
@@ -982,35 +979,17 @@ Workspaces.prototype = {
         global.window_manager.disconnect(this._switchWorkspaceNotifyId);
     },
 
-    getFullSizeX : function() {
-        return this._workspaces[0].fullSizeX;
+    getScale : function() {
+        return this._workspaces[0].scale;
     },
 
-    // If j-th workspace in the i-th row is active, returns the full width
-    // of j workspaces including empty space if i = 1, or the width of one
-    // workspace.
-    // Used in overlay.js to determine when it is ok to remove the sideshow
-    // during animations for entering and leaving the overlay.
-    getWidthToTopActiveWorkspace : function() {
+    // Get the grid position of the active workspace.
+    getActiveWorkspacePosition : function() {
         let global = Shell.Global.get();
         let activeWorkspaceIndex = global.screen.get_active_workspace_index();
         let activeWorkspace = this._workspaces[activeWorkspaceIndex];
 
-        if (activeWorkspace.gridRow == 0)
-            return (activeWorkspace.gridCol + 1) * global.screen_width + activeWorkspace.gridCol * GRID_SPACING;
-        else
-            return global.screen_width;
-    },
-
-    // Updates the workspaces display based on the current dimensions and position.
-    _updateInOverlay : function() {
-        let global = Shell.Global.get();  
-  
-        this._positionWorkspaces(global);
-
-        // Position/scale the desktop windows and their children
-        for (let w = 0; w < this._workspaces.length; w++)
-            this._workspaces[w].updateInOverlay();
+        return [activeWorkspace.gridX, activeWorkspace.gridY];
     },
 
     // Assign grid positions to workspaces. We can't just do a simple
@@ -1063,14 +1042,6 @@ Workspaces.prototype = {
                 }
             }
         }
-
-        // Now figure out their full-size coordinates
-        for (let w = 0; w < this._workspaces.length; w++) {
-            let workspace = this._workspaces[w];
-
-            workspace.fullSizeX = (workspace.gridCol - activeWorkspace.gridCol) * (global.screen_width + GRID_SPACING);
-            workspace.fullSizeY = (workspace.gridRow - activeWorkspace.gridRow) * (global.screen_height + GRID_SPACING);
-        }
     },
 
     _workspacesChanged : function() {
@@ -1167,28 +1138,49 @@ Workspaces.prototype = {
 Tweener.registerSpecialPropertyModifier("workspace_relative", _workspaceRelativeModifier, _workspaceRelativeGet);
 
 function _workspaceRelativeModifier(workspace) {
-    let endX, endY;
+    let [startX, startY] = Main.overlay.getPosition();
+    let overlayPosX, overlayPosY, overlayScale;
 
     if (!workspace)
         return [];
 
     if (workspace.leavingOverlay) {
-        endX = workspace.fullSizeX;
-        endY = workspace.fullSizeY;        
+        let [zoomedInX, zoomedInY] = Main.overlay.getZoomedInPosition();
+        overlayPosX = { begin: startX, end: zoomedInX };
+        overlayPosY = { begin: startY, end: zoomedInY };
+        overlayScale = { begin: Main.overlay.getScale(),
+                         end: Main.overlay.getZoomedInScale() };
     } else {
-        endX = workspace.gridX;
-        endY = workspace.gridY;
+        overlayPosX = { begin: startX, end: 0 };
+        overlayPosY = { begin: startY, end: 0 };
+        overlayScale = { begin: Main.overlay.getScale(), end: 1 };
     }
 
     return [ { name: "x",
-               parameters: { begin: workspace.actor.x, end: endX,
-                             cur: function() { return workspace.actor.x; } } },
+               parameters: { workspacePos: workspace.gridX,
+                             overlayPos: overlayPosX,
+                             overlayScale: overlayScale } },
              { name: "y",
-               parameters: { begin: workspace.actor.y, end: endY,
-                             cur: function() { return workspace.actor.y; } } }
+               parameters: { workspacePos: workspace.gridY,
+                             overlayPos: overlayPosY,
+                             overlayScale: overlayScale } }
            ];
 }
 
 function _workspaceRelativeGet(begin, end, time, params) {
-    return (begin + params.begin) + time * (end + params.end - (begin + params.begin)) - params.cur();
+    let curOverlayPos = (1 - time) * params.overlayPos.begin +
+                        time * params.overlayPos.end;
+    let curOverlayScale = (1 - time) * params.overlayScale.begin +
+                          time * params.overlayScale.end;
+
+    // Calculate the screen position of the window.
+    let screen = (1 - time) *
+                 ((begin + params.workspacePos) * params.overlayScale.begin +
+                  params.overlayPos.begin) +
+                 time *
+                 ((end + params.workspacePos) * params.overlayScale.end +
+                 params.overlayPos.end);
+
+    // Return the workspace coordinates.
+    return (screen - curOverlayPos) / curOverlayScale - params.workspacePos;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]