[gnome-shell/wip/paging-release2: 12/14] AppDisplay: Make space on grid to fit collection when opening



commit 48eaa701d6a8b183255b80345d224e2b540ebee5
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.

 js/ui/appDisplay.js |  159 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 js/ui/iconGrid.js   |   22 +++++++
 2 files changed, 178 insertions(+), 3 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index d66613e..00150fe 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 MAX_APPS_PAGES = 20;
@@ -44,6 +44,8 @@ const MAX_APPS_PAGES = 20;
 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();
@@ -344,6 +346,8 @@ const AllView = new Lang.Class({
         // we have to tell pagination that the adjustment is not correct (since the allocated size of 
pagination changed)
         // For that problem we return to the first page of pagination.
         this.invalidatePagination = false;
+        this._popupExpansionNeeded = true;
+        this.displayingPopup = false;
         // Always start at page 0 when we enter and quit overview
         Main.overview.connect('hidden', Lang.bind(this, function() {this.goToPage(0, true);}));
     },
@@ -356,6 +360,10 @@ const AllView = new Lang.Class({
     },
 
     goToPage: function(pageNumber, updateIndicators, action) {
+        if (this._currentPage != pageNumber && this.displayingPopup && this._currentPopup)
+            this._currentPopup.popdown();
+        else if(this.displayingPopup && this._currentPopup)
+                return;
         this.viewGoToPage(pageNumber, action);
         if (updateIndicators)
             this.indicatorsGoToPage(pageNumber);
@@ -416,7 +424,130 @@ const AllView = new Lang.Class({
         return Math.abs(currentScrollPosition - this._grid.getPagePosition(pageNumber)[1]);
     },
 
+    /**
+     * Pan view with items to make space for the folder view.
+     * @param folderNVisibleRowsAtOnce this parameter tell how many rows the folder view has, but,
+     * it is already constrained to be at maximum of main grid rows least one, to ensure we have
+     * enough space to show the folder view popup.
+     */
+    makeSpaceForPopUp: function(iconActor, side, folderNVisibleRowsAtOnce) {
+        let rowsUp = [];
+        let rowsDown = [];
+        let mainIconYPosition = iconActor.actor.y;
+        let mainIconRowReached = false;
+        let isMainIconRow = false;
+        let rows = this._grid.pageRows(this._currentPage);
+        this._translatedRows = rows;
+        for (let rowIndex in rows) {
+            isMainIconRow = mainIconYPosition == rows[rowIndex][0].y;
+            if (isMainIconRow)
+                mainIconRowReached = true;
+            if ( !mainIconRowReached)
+                rowsUp.push(rows[rowIndex]);
+            else {
+                if (isMainIconRow) {
+                    if (side == St.Side.BOTTOM)
+                        rowsDown.push(rows[rowIndex]);
+                    else
+                        rowsUp.push(rows[rowIndex]);
+                } else
+                    rowsDown.push(rows[rowIndex]);
+            }
+        }
+        //The last page can have space without rows
+        let emptyRows = this._grid.rowsPerPage() - rows.length ;
+        let panViewUpNRows = 0;
+        let panViewDownNRows = 0;
+        if(side == St.Side.BOTTOM) {
+            // There's not need to pan view down
+            if (rowsUp.length >= folderNVisibleRowsAtOnce)
+                panViewUpNRows = folderNVisibleRowsAtOnce;
+            else {
+                panViewUpNRows = rowsUp.length;
+                panViewDownNRows = folderNVisibleRowsAtOnce - rowsUp.length;
+            }
+        } else {
+            // There's not need to pan view up
+            if (rowsDown.length + emptyRows >= folderNVisibleRowsAtOnce)
+                panViewDownNRows = folderNVisibleRowsAtOnce;
+            else {
+                panViewDownNRows = rowsDown.length + emptyRows;
+                panViewUpNRows = folderNVisibleRowsAtOnce - rowsDown.length - emptyRows;
+            }
+        }
+        this._updateIconOpacities(true);
+        // Especial case, last page and no rows below the icon of the folder, no rows down neither rows up,
+        // we call directly the popup
+        if (panViewDownNRows > 0 && rowsDown.length == 0 && rowsUp.length == 0) {
+            this.displayingPopup = true;
+            this._popupExpansionNeeded = false;
+            iconActor.onCompleteMakeSpaceForPopUp();
+        } else {
+            this._popupExpansionNeeded = true;
+            this._panViewForFolderView(rowsUp, rowsDown, panViewUpNRows, panViewDownNRows, iconActor);
+        }
+    },
+
+    returnSpaceToOriginalPosition: function() {
+        this._updateIconOpacities(false);
+        if (!this._popupExpansionNeeded) {
+            this.displayingPopup = false;
+            return;
+        }
+        if (this._translatedRows) {
+            for (let rowId in this._translatedRows) {
+                for (let childrenId in this._translatedRows[rowId]) {
+                    if (this._translatedRows[rowId][childrenId].translation_y) {
+                        let tweenerParams = { translation_y: 0,
+                                              time: POPUP_FOLDER_VIEW_ANIMATION,
+                                              onUpdate: function() {this.queue_relayout();},
+                                              transition: 'easeInOutQuad',
+                                              onComplete: Lang.bind(this, function(){ this.displayingPopup = 
false; }) };
+                        Tweener.addTween(this._translatedRows[rowId][childrenId], tweenerParams);
+                    }
+                }
+            }
+        }
+    },
+
+    _panViewForFolderView: function(rowsUp, rowsDown, panViewUpNRows, panViewDownNRows, iconActor) {
+        let rowHeight = this._grid.rowHeight();
+        if (panViewUpNRows > 0) {
+            this.displayingPopup = true;
+            let height = rowHeight * panViewUpNRows;
+            for (let rowId in rowsUp) {
+                for (let childrenId in rowsUp[rowId]) {
+                    rowsUp[rowId][childrenId].translation_y = 0;
+                    let tweenerParams = { translation_y: - height,
+                                          time: POPUP_FOLDER_VIEW_ANIMATION,
+                                          onUpdate: function() { this.queue_relayout(); },
+                                          transition: 'easeInOutQuad' };
+                    if ((rowId == rowsUp.length - 1) && (childrenId == rowsUp[rowId].length - 1))
+                            tweenerParams['onComplete'] = Lang.bind(iconActor, 
iconActor.onCompleteMakeSpaceForPopUp);
+                    Tweener.addTween(rowsUp[rowId][childrenId], tweenerParams);
+                }
+            }
+        }
+        if (panViewDownNRows > 0) {
+            this.displayingPopup = true;
+            let height = rowHeight * panViewDownNRows;
+            for (let rowId in rowsDown) {
+                for (let childrenId in rowsDown[rowId]) {
+                    rowsDown[rowId][childrenId].translation_y = 0;
+                    let tweenerParams = { translation_y: height,
+                                          time: POPUP_FOLDER_VIEW_ANIMATION,
+                                          onUpdate: function() { this.queue_relayout(); } };
+                    if ((rowId == rowsDown.length - 1) && (childrenId == rowsDown[rowId].length - 1))
+                        tweenerParams['onComplete'] = Lang.bind(iconActor, 
iconActor.onCompleteMakeSpaceForPopUp);
+                    Tweener.addTween(rowsDown[rowId][childrenId], tweenerParams);
+                }
+            }
+        }
+    },
+
     _onScroll: function(actor, event) {
+         if(this.displayingPopup)
+            return;
         let direction = event.get_scroll_direction();
         let nextPage;
         if (direction == Clutter.ScrollDirection.UP)
@@ -432,6 +563,8 @@ const AllView = new Lang.Class({
     },
 
     _onPan: function(action) {
+        if (this.displayingPopup)
+            return;
         this._clickAction.release();
         let [dist, dx, dy] = action.get_motion_delta(0);
         let adjustment = this._verticalAdjustment;
@@ -440,6 +573,8 @@ const AllView = new Lang.Class({
     },
 
     _onPanEnd: function(action) {
+         if (this.displayingPopup)
+            return;
         let diffCurrentPage = this._diffToPage(this._currentPage);
         if (diffCurrentPage > this._paginationView.height * PAGE_SWITCH_TRESHOLD) {
             if (action.get_velocity(0)[2] > 0 && this._currentPage > 0)
@@ -1065,7 +1200,6 @@ const FolderIcon = new Lang.Class({
         this.actor.connect('clicked', Lang.bind(this,
             function() {
                 this._ensurePopup();
-                this._popup.toggle();
                 this.view.setScrollToStart();
             }));
         this.actor.connect('notify::mapped', Lang.bind(this,
@@ -1073,6 +1207,9 @@ const FolderIcon = new Lang.Class({
                 if (!this.actor.mapped && this._popup)
                     this._popup.popdown();
             }));
+        this.actor.connect('notify::allocation', Lang.bind(this, function() {
+            Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, this._updatePopupPosition));
+        }));
     },
 
     _createIcon: function(size) {
@@ -1094,6 +1231,18 @@ const FolderIcon = new Lang.Class({
         return usedHeight;   
     },
 
+    makeSpaceForPopUp: function() {
+        this._parentView.makeSpaceForPopUp(this, this._boxPointerArrowside, 
this.view.nRowsDisplayedAtOnce());
+    },
+
+    returnSpaceToOriginalPosition: function() {
+        this._parentView.returnSpaceToOriginalPosition();
+    },
+
+    onCompleteMakeSpaceForPopUp: function() {
+        this._popup.popup();
+    },
+
     _calculateBoxPointerArrowSide: function() {
         let absoluteActorYPosition = this.actor.get_transformed_position()[1];
         let spaceTop = absoluteActorYPosition;
@@ -1179,8 +1328,10 @@ const FolderIcon = new Lang.Class({
     },
 
     _ensurePopup: function() {
-        if (this._popup && !this.invalidatePopUp)
+        if (this._popup && !this.invalidatePopUp){
+            this.makeSpaceForPopUp();
             return;
+        }
         this._boxPointerArrowside = this._calculateBoxPointerArrowSide();
         if (!this._popup) {
             this._popup = new AppFolderPopup(this, this._boxPointerArrowside);
@@ -1189,12 +1340,14 @@ const FolderIcon = new Lang.Class({
                     function(popup, isOpen) {
                 if (!isOpen) {
                     this.actor.checked = false;
+                    this.returnSpaceToOriginalPosition();
                 }
             }));
         } else
             this._popup.updateBoxPointer(this._boxPointerArrowside);
         this._updatePopUpSize();
         this._updatePopupPosition();
+        this.makeSpaceForPopUp();
         this.invalidatePopUp = false; 
     },
 
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index 4c8eb3b..56a6dd0 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -588,6 +588,28 @@ const PaginatedIconGrid = new Lang.Class({
         }
     },
 
+    rowsPerPage: function() {
+        return this._rowsPerPage;
+    },
+
+    pageRows: function(pageNumber) {
+        let pagePosition = this.getPagePosition(pageNumber);
+        let currentRowItemsYPosition = pagePosition;
+        let rows = [];
+        let currentItem = this._getVisibleChildren()[pageNumber * this._childrenPerPage];
+        let children = this._grid.get_children();
+        let index = pageNumber * this._childrenPerPage;
+        for (let rowIndex = 0; rowIndex < this._rowsPerPage && index < children.length; rowIndex++) {
+            rows[rowIndex] = [];
+            while (index < children.length && children[index].y == currentItem.y) {
+                rows[rowIndex].push(children[index]);
+                index++;
+            }
+            currentItem = children[index];
+        }
+        return rows;
+    },
+
     _availableHeightPerPageForItems: function() {
         let spacePerRow = this._vItemSize + this._getSpacing();
         return this._rowsPerPage * spacePerRow - this._getSpacing() + this.top_padding + this.bottom_padding;


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