[gnome-shell/wip/paging-release: 11/43] Make space to the folder view panning the items inside the iconGrid



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

    Make space to the folder view panning the items inside the iconGrid
    
    testing moving items to make space for popup
    
    forgot to add the relayout
    
    Pan view for collections working
    
    Fixed bad calculations to rowsup and rowsdown at expanding collection
    view
    
    I think fixed some issue when closing folder views and make scroll
    movement while animating makes view push down a bit

 js/ui/appDisplay.js |  195 +++++++++++++++++++++++++++++++++++++++++++++------
 js/ui/iconGrid.js   |   27 +++++++-
 2 files changed, 200 insertions(+), 22 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 14346ea..9a14157 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -42,7 +42,9 @@ const MAX_APPS_PAGES = 20;
 const PAGE_SWITCH_TRESHOLD = 0.2;
 const PAGE_SWITCH_TIME = 0.3;
 
-// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
+const POPUP_FOLDER_VIEW_ANIMATION = 0.3;
+
+//Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
 function _loadCategory(dir, view) {
     let iter = dir.iter();
     let appSystem = Shell.AppSystem.get_default();
@@ -128,6 +130,7 @@ const AppPages = new Lang.Class({
         this.actor = this._grid.actor;
         this._parent = parent;
         this._folderIcons = [];
+        this.doingTransitions = false;
     },
 
     _getItemId: function(item) {
@@ -196,6 +199,130 @@ const AppPages = new Lang.Class({
     addFolderPopup: function(popup) {
         this._parent.addFolderPopup(popup);
     },
+    /**
+     * 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 constrianed to be at maximum of main grid rows least one, to ensure we have
+     * enough space to show the folder view.
+     */
+    makeSpaceForPopUp: function(iconActor, side, folderNVisibleRowsAtOnce) {
+        global.log("#### makeSpaceForPopUp ####");
+        let rowsUp = [];
+        let rowsDown = [];
+        let mainIconYPosition = iconActor.actor.y;
+        let currentPage = this._parent.currentPage();
+        let mainIconRowReached = false;
+        let isMainIconRow = false;
+        let rows = this._grid.pageRows(currentPage);
+        this._translatedRows = rows;
+        //global.log(" ROWS " + rows);
+        for(let rowIndex in rows) {
+            global.log("row " + rows[rowIndex]);
+            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 = folderNVisibleRowsAtOnce + 1 - 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._panViewForFolderView(rowsUp, rowsDown, panViewUpNRows, panViewDownNRows, iconActor);
+        this.updateIconOpacities(true);
+        global.log("#### END makeSpaceForPopUp ####");
+    },
+    
+    returnSpaceToOriginalPosition: function() {
+        if(this._translatedRows) {
+            for(let rowId in this._translatedRows) {
+                for(let childrenId in this._translatedRows[rowId]) {
+                    if(this._translatedRows[rowId][childrenId].translate_y){
+                        let tweenerParams = { translate_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);
+                    }
+                }
+            }
+        }
+        this.updateIconOpacities(false);
+    },
+    
+    _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].translate_y = 0;
+                    //global.log("children up y " + rowsUp[rowId][childrenId].translate_y);
+                    let tweenerParams = { translate_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);
+                    //rowsUp[rowId][childrenId].translate_y = - height;
+                    //rowsUp[rowId][childrenId].queue_relayout();
+                    //global.log("after children up y " + rowsUp[rowId][childrenId].translate_y);
+                }
+            }
+        }
+        if(panViewDownNRows > 0) {
+            this.displayingPopup = true;
+            let height = rowHeight * panViewDownNRows;
+            for(let rowId in rowsDown) {
+                for(let childrenId in rowsDown[rowId]) {
+                    //global.log("children down y " + rowsDown[rowId][childrenId].translate_y);
+                    rowsDown[rowId][childrenId].translate_y = 0;
+                    let tweenerParams = { translate_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);
+                    //rowsDown[rowId][childrenId].translate_y = height;
+                    //rowsDown[rowId][childrenId].queue_relayout();
+                    //global.log("after children down y " + rowsDown[rowId][childrenId].translate_y);
+                }
+            }
+        }
+    },
     
     removeAll: function() {
         this._folderIcons = [];
@@ -251,6 +378,11 @@ const PaginationScrollView = new Lang.Class({
         this._currentPage = 0;
         this._parent = parent;
         
+        // When the number of pages change (i.e. when changing screen resolution or during clutter false 
allocations)
+        // 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.connect('scroll-event', Lang.bind(this, this._onScroll));
         
         let panAction = new Clutter.PanAction({ interpolate: false });
@@ -299,9 +431,17 @@ const PaginationScrollView = new Lang.Class({
         
         this._verticalAdjustment.page_size = availHeight;
         this._verticalAdjustment.upper = this._stack.height;
+        if(this.invalidatePagination)
+            this.goToPage(0);
+        this.invalidatePagination = false;
     },
 
     goToPage: function(pageNumber, action) {
+        if(this._currentPage != pageNumber && this._pages.displayingPopup) {
+            this._currentPopup.popdown();
+        } else if(this._pages.displayingPopup){
+            return;
+        }
         let velocity;
         if(!action)
             velocity = 0;
@@ -320,8 +460,7 @@ const PaginationScrollView = new Lang.Class({
         if(this._currentPage != pageNumber) {
             let min_velocity = totalHeight / (PAGE_SWITCH_TIME * 1000);
             velocity = Math.max(min_velocity, velocity);
-            time = (diffFromPage / velocity) / 1000;
-            
+            time = (diffFromPage / velocity) / 1000;            
         } else
             time = PAGE_SWITCH_TIME * diffFromPage / totalHeight;
         // Take care when we are changing more than one page, maximum time
@@ -371,6 +510,8 @@ const PaginationScrollView = new Lang.Class({
     },
 
     _onScroll: function(actor, event) {
+        if(this._pages.displayingPopup)
+            return;
         let direction = event.get_scroll_direction();
         let nextPage;
         if (direction == Clutter.ScrollDirection.UP)
@@ -391,12 +532,13 @@ const PaginationScrollView = new Lang.Class({
                 function(popup, isOpen) {
                     this._eventBlocker.reactive = isOpen;
                     this._currentPopup = isOpen ? popup : null;
-                    this._pages.updateIconOpacities(isOpen);
                 }));
     },
     
     _onPan: function(action) {
         this._clickAction.release();
+        if(this._pages.displayingPopup)
+            return;
         let [dist, dx, dy] = action.get_motion_delta(0);
         let adjustment = this._verticalAdjustment;
         adjustment.value -= (dy / this.height) * adjustment.page_size;
@@ -404,6 +546,8 @@ const PaginationScrollView = new Lang.Class({
     },
     
     _onPanEnd: function(action) {
+        if(this._pages.displayingPopup)
+            return;
         let diffCurrentPage = this._diffToPage(this._currentPage);
         if(diffCurrentPage > this.height * PAGE_SWITCH_TRESHOLD) {
             if(action.get_velocity(0)[2] > 0 && this._currentPage > 0) {
@@ -526,16 +670,10 @@ const PaginationIndicator = new Lang.Class({
             this.actor.set_skip_paint(children[i], false);
         }
     },
-
-    vfunc_set_container: function(container) {
-        if(this._styleChangedId) {
-            this._container.disconnect(this._styleChangedId);
-            this._styleChangedId = 0;
-        }        
-        if(container != null)
-            this._styleChangedId = container.connect('style-changed', Lang.bind(this,
-                    function() { this.spacing = this._container.get_theme_node().get_length('spacing'); }));
-        this._container = container;
+   
+    _styleChanged: function() {
+        this._spacing = this.actor.get_theme_node().get_length('spacing');
+        this.actor.queue_relayout();
     }
 });
 
@@ -551,6 +689,7 @@ const AllView = new Lang.Class({
         let layout = new Clutter.BinLayout();
         this.actor = new St.Widget({ layout_manager: layout, 
                                      x_expand:true, y_expand:true });
+        //FIXME Clutter align properties
         layout.add(this._paginationView, 2,2);
         if(Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
             layout.add(this._paginationIndicator.actor, 2,2);
@@ -713,6 +852,8 @@ const AppDisplayActor = new Lang.Class({
     vfunc_allocate: function (actor, box, flags) {
         let availWidth = box.x2 - box.x1;
         let availHeight = box.y2 - box.y1;
+        // Prepare children of all views for the upcomming allocation, calculate all
+        // the needed values in the responsive design we are trying to emulate
         this.emit('allocated-size-changed', availWidth, availHeight);
         this.parent(actor, box, flags);
     },
@@ -1119,13 +1260,16 @@ const FolderIcon = new Lang.Class({
         this.actor.connect('clicked', Lang.bind(this,
             function() {
                 this._ensurePopup();
-                this._popup.toggle();
             }));
         this.actor.connect('notify::mapped', Lang.bind(this,
             function() {
                 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) {
@@ -1179,11 +1323,17 @@ const FolderIcon = new Lang.Class({
     },
 
     makeSpaceForPopUp: function() {
-        //this._parentView.makeSpaceForPopUp(this._side, rows);
+        this._parentView.makeSpaceForPopUp(this, this._side, this.view.nRowsDisplayedAtOnce());
+    },
+    
+    returnSpaceToOriginalPosition: function() {
+        global.log("Original position");
+        this._parentView.returnSpaceToOriginalPosition();
     },
     
-    onCompletemakeSpaceForPopUp: function() {
-        this._popup.toggle();
+    onCompleteMakeSpaceForPopUp: function() {
+        //Mainloop.timeout_add(0.1, Lang.bind(this, function() {
+        this._popup.popup();
     },
     
     _ensurePopup: function() {
@@ -1247,13 +1397,16 @@ const FolderIcon = new Lang.Class({
             let usedHeight = this._popUpHeight();
             global.log("Used height " + usedHeight);
             this.view.actor.set_height(this._popUpHeight());
+            this._popup.actor.fixed_height = this._popup.actor.height;
 
-            this._updatePopupPosition();
-
+            
+            this.makeSpaceForPopUp();
             this._popup.connect('open-state-changed', Lang.bind(this,
                     function(popup, isOpen) {
-                if (!isOpen)
+                if (!isOpen) {
                     this.actor.checked = false;
+                    this.returnSpaceToOriginalPosition();
+                }
             }));
         }
     },
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index ed7a16b..3060019 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -444,7 +444,7 @@ const IconGrid = new Lang.Class({
     },
     
     usedHeightForNRows: function(nRows) {
-        let spacePerRow = this._vItemSize + this.getSpacing();
+        let spacePerRow = this.rowHeight();
         return spacePerRow * nRows;
     },
     
@@ -525,5 +525,30 @@ const IconGrid = new Lang.Class({
         return this._fixedSpacing ? this._fixedSpacing : this._spacing;
     },
     
+    pageRows: function(pageNumber) {
+        let pagePosition = this.getPagePosition(pageNumber);
+        let currentRowItemsYPosition = pagePosition;
+        let rows = [];
+        let currentItem = this._firstPagesItems[pageNumber];
+        let children = this._grid.get_children();
+        let index = 0;
+        // Positioning to the first element of the page
+        while(children[index] != this._firstPagesItems[pageNumber])
+            index++;
+        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;
+    },
+    
+    rowHeight: function() {
+        return this._vItemSize + this.getSpacing();
+    }
+    
 });
 Signals.addSignalMethods(IconGrid.prototype);


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