[gnome-shell/wip/paging-release2: 18/22] appDisplay: Make space on grid to fit collection when opening



commit 78680c54ccb3c00b1c0d1626edd7001c089737ab
Author: Carlos Soriano <carlos soriano89 gmail com>
Date:   Tue Jul 9 15:11:03 2013 +0200

    appDisplay: Make space on grid to fit collection when opening
    
    Add properly functions in AllView and FolderView to animate
    the FolderView popup opening and give enough space on the parent
    view to fit the popup of the folder view
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706081

 js/ui/appDisplay.js |  135 ++++++++++++++++++++++++++++++++++++++++++++++++---
 js/ui/iconGrid.js   |   17 ++++++
 2 files changed, 144 insertions(+), 8 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 13e1643..62d907d 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -34,7 +34,7 @@ const MIN_COLUMNS = 4;
 const MIN_ROWS = 4;
 
 const INACTIVE_GRID_OPACITY = 77;
-const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.15;
+const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.40;
 const FOLDER_SUBICON_FRACTION = .4;
 
 const INDICATORS_ANIMATION_TIME = 0.6;
@@ -48,6 +48,8 @@ const INDICATOR_MOVE_OFFSET = 60;
 const PAGE_SWITCH_TRESHOLD = 0.2;
 const PAGE_SWITCH_TIME = 0.3;
 
+const POPUP_FOLDER_VIEW_ANIMATION = 0.25;
+
 // Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
 function _loadCategory(dir, view) {
     let iter = dir.iter();
@@ -283,6 +285,8 @@ const AllView = new Lang.Class({
         }));
         this._eventBlocker.add_action(this._clickAction);
 
+        this._displayingPopup = false;
+
         this._availWidth = 0;
         this._availHeight = 0;
 
@@ -297,6 +301,11 @@ const AllView = new Lang.Class({
     },
 
     goToPage: function(pageNumber) {
+        if (this._currentPage == pageNumber && this.displayingPopup && this._currentPopup)
+            return;
+        if (this.displayingPopup && this._currentPopup)
+            this._currentPopup.popdown();
+
         let velocity;
         if (!this._panning)
             velocity = 0;
@@ -338,7 +347,103 @@ const AllView = new Lang.Class({
         return Math.abs(currentScrollPosition - this._grid.getPageY(pageNumber));
     },
 
+    /**
+    * makeSpaceForPopUp:
+    * @y: The base position to move rows
+    * @side: The movement direction
+    * @nRows: Displacement quantity
+    * Pan view with items to make space for the folder view
+    */
+    makeSpaceForPopup: function(y, side, nRows) {
+        let mainIconYPosition = y;
+        let rows = this._grid.pageRows(this._currentPage);
+        let rowsAbove = [];
+        let rowsBelow = [];
+        let rowsArray;
+        for (let rowIndex in rows) {
+            if (mainIconYPosition == rows[rowIndex][0].y)
+                rowsArray = (side == St.Side.BOTTOM) ? rowsBelow : rowsAbove;
+            else
+                rowsArray = (mainIconYPosition < rows[rowIndex][0].y) ? rowsBelow: rowsAbove;
+            rowsArray.push(rows[rowIndex]);
+        }
+        //The last page can have space without rows
+        let emptyRows = this._grid.rowsPerPage() - rows.length ;
+        let nRowsUp;
+        let nRowsDown;
+        if(side == St.Side.BOTTOM) {
+            nRowsUp = Math.min(rowsAbove.length, nRows);
+            nRowsDown = nRows - nRowsUp;
+        } else {
+            nRowsDown = Math.min(rowsBelow.length + emptyRows, nRows);
+            nRowsUp = nRows - nRowsDown;
+        }
+        this._updateIconOpacities(true);
+        this._displayingPopup = true;
+        // Special case: On the last row with no rows below the icon, there's no
+        // need to move any rows either up or down
+        let dontExpand = (rowsBelow.length == 0 && nRowsUp == 0);
+        if (dontExpand) {
+            this._translatedChildren = [];
+            this.emit('space-ready');
+        } else {
+            let rowHeight = this._grid.rowHeight();
+
+            let childrenUp = [];
+            if (nRowsUp > 0) {
+                let translationY = -rowHeight * nRowsUp;
+                childrenUp = rowsAbove.reduce(function(prev, cur) { return prev.concat(cur); });
+                this._translateChildren(childrenUp, translationY);
+            }
+
+            let childrenDown = [];
+            if (nRowsDown > 0) {
+                let translationY = rowHeight * nRowsDown;
+                childrenDown = rowsBelow.reduce(function(prev, cur) { return prev.concat(cur); });
+                this._translateChildren(childrenDown, translationY);
+            }
+
+            this._translatedChildren = childrenUp.concat(childrenDown);
+        }
+    },
+
+    _translateChildren: function(children, translationY) {
+        for (let i = 0; i < children.length; i++) {
+            children[i].translation_y = 0;
+            let params = { translation_y: translationY,
+                           time: POPUP_FOLDER_VIEW_ANIMATION,
+                           onUpdate: function() { this.queue_relayout(); },
+                           transition: 'easeInOutQuad'
+                         };
+            if (i == (children.length - 1))
+                params.onComplete = Lang.bind(this, function() { this.emit('space-ready'); });
+            Tweener.addTween(children[i], params);
+        }
+    },
+
+    returnSpaceToOriginalPosition: function() {
+        this._updateIconOpacities(false);
+        if (!this._translatedChildren || !this._translatedChildren.length) {
+            this._displayingPopup = false;
+            return;
+        }
+
+        for (let i = 0; i < this._translatedChildren.length; i++) {
+            if (!this._translatedChildren[i].translation_y)
+                continue;
+            Tweener.addTween(this._translatedChildren[i],
+                             { translation_y: 0,
+                               time: POPUP_FOLDER_VIEW_ANIMATION,
+                               onUpdate: function() { this.queue_relayout(); },
+                               transition: 'easeInOutQuad',
+                               onComplete: Lang.bind(this, function() { this._displayingPopup = false; })
+                             });
+        }
+    },
+
     _onScroll: function(actor, event) {
+         if(this._displayingPopup)
+            return;
         let direction = event.get_scroll_direction();
         if (direction == Clutter.ScrollDirection.UP) {
             if (this._currentPage > 0)
@@ -352,6 +457,8 @@ const AllView = new Lang.Class({
     },
 
     _onPan: function(action) {
+        if (this._displayingPopup)
+            return false;
         this._panning = true;
         this._clickAction.release();
         let [dist, dx, dy] = action.get_motion_delta(0);
@@ -361,6 +468,8 @@ const AllView = new Lang.Class({
     },
 
     _onPanEnd: function(action) {
+         if (this._displayingPopup)
+            return;
         let diffCurrentPage = this._diffToPage(this._currentPage);
         if (diffCurrentPage > this._pagesBin.height * PAGE_SWITCH_TRESHOLD) {
             if (action.get_velocity(0)[2] > 0 && this._currentPage > 0)
@@ -426,6 +535,8 @@ const AllView = new Lang.Class({
                 this._eventBlocker.reactive = isOpen;
                 this._currentPopup = isOpen ? popup : null;
                 this._updateIconOpacities(isOpen);
+                if(!isOpen)
+                    this.returnSpaceToOriginalPosition();
             }));
     },
 
@@ -488,6 +599,7 @@ const AllView = new Lang.Class({
             this._folderIcons[i].adaptToSize(availWidth, availHeight);
     }
 });
+Signals.addSignalMethods(AllView.prototype);
 
 const FrequentView = new Lang.Class({
     Name: 'FrequentView',
@@ -919,8 +1031,8 @@ const FolderIcon = new Lang.Class({
         this.actor.connect('clicked', Lang.bind(this,
             function() {
                 this._ensurePopup();
-                this._popup.toggle();
                 this.view.actor.vscroll.adjustment.value = 0;
+                this._makeSpaceForPopup();
             }));
         this.actor.connect('notify::mapped', Lang.bind(this,
             function() {
@@ -938,6 +1050,15 @@ const FolderIcon = new Lang.Class({
         return usedHeight;
     },
 
+    _makeSpaceForPopup: function() {
+        let id = this._parentView.connect('space-ready', Lang.bind(this, function() {
+                        this._parentView.disconnect(id);
+                        this._popup.popup();
+                        this._updatePopupPosition();
+                    }));
+        this._parentView.makeSpaceForPopup(this.actor.y, this._boxPointerArrowside, 
this.view.nRowsDisplayedAtOnce());
+    },
+
     _calculateBoxPointerArrowSide: function() {
         let spaceTop = this.actor.y - this._parentView.getCurrentPageY();
         let spaceBottom = this._parentView.actor.height - (spaceTop + this.actor.height);
@@ -963,12 +1084,9 @@ const FolderIcon = new Lang.Class({
 
         if (this._boxPointerArrowside == St.Side.BOTTOM) {
             let closeButtonOffset = -this._popup.closeButton.translation_y;
-            // We use this function since this.actor.height doesn't return a corrrect value,
-            // due to the way the AppFolderPopup manages it
-            let y = this.actor.y - this._popupHeight();
-            this._popup.actor.y = y
+            this._popup.actor.y = this.actor.allocation.y1 + this.actor.translation_y - this._popupHeight();
         } else {
-            this._popup.actor.y = this.actor.y + this.actor.height;
+            this._popup.actor.y = this.actor.allocation.y1 + this.actor.translation_y + this.actor.height;
         }
     },
 
@@ -1074,11 +1192,12 @@ const AppFolderPopup = new Lang.Class({
             return;
 
         this.actor.show();
-        this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 
         this._boxPointer.setArrowActor(this._source.actor);
         this._boxPointer.show(BoxPointer.PopupAnimation.FADE |
                               BoxPointer.PopupAnimation.SLIDE);
+        
+        this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 
         this._isOpen = true;
         this.emit('open-state-changed', true);
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index f76c2a5..9304d41 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -552,6 +552,23 @@ const PaginatedIconGrid = new Lang.Class({
         this._childrenPerPage = nColumns * this._rowsPerPage;
     },
 
+    rowsPerPage: function() {
+        return this._rowsPerPage;
+    },
+
+    pageRows: function(pageNumber) {
+        let rows = [];
+        let pageOffset = pageNumber * this._childrenPerPage;
+        let childrenPerRow = this._childrenPerPage / this._rowsPerPage;
+        let children = this._grid.get_children();
+        for (let i = 0; i < this._rowsPerPage; i++) {
+            rows[i] = children.slice(pageOffset + i * childrenPerRow, pageOffset + (i + 1) * childrenPerRow);
+            if (rows[i].length < childrenPerRow)
+                break;
+        }
+        return rows;
+    },
+
     _availableHeightPerPageForItems: function() {
         return this.usedHeightForNRows(this._rowsPerPage) - (this.topPadding + this.bottomPadding);
     },


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