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



commit 95d1da0b768079bdf61ec42ba695ef9efc955e93
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
    
    AppPages: typo
    
    Fixed bad calculation of empty rows, causing moving the current row with
    the fodler icon when it can stay inn the position
    
    AppPages: doingtransitons not needed
    
    AppDisplay: Icon opacity animation time increased to match collection open animation time
    
    PaginationScrollView: popdown collection only if not null

 js/ui/appDisplay.js |  181 ++++++++++++++++++++++++++++++++++++++++++++------
 js/ui/iconGrid.js   |   27 +++++++-
 2 files changed, 185 insertions(+), 23 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 5e45e1c..6ebaffe 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -32,7 +32,7 @@ const MENU_POPUP_TIMEOUT = 600;
 const MAX_COLUMNS = 6;
 
 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;
@@ -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.25;
+
+//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._popupExpansionNeeded = true;
     },
 
     _getItemId: function(item) {
@@ -197,6 +200,119 @@ const AppPages = new Lang.Class({
         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) {
+        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;
+        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._panViewForFolderView(rowsUp, rowsDown, panViewUpNRows, panViewDownNRows, iconActor);
+        this.updateIconOpacities(true);
+    },
+    
+    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;
+                    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);
+                }
+            }
+        }
+        if(panViewDownNRows > 0) {
+            this.displayingPopup = true;
+            let height = rowHeight * panViewDownNRows;
+            for(let rowId in rowsDown) {
+                for(let childrenId in rowsDown[rowId]) {
+                    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);
+                }
+            }
+        }
+    },
+
     removeAll: function() {
         this._folderIcons = [];
         this.parent();
@@ -251,6 +367,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 });
         panAction.connect('pan', Lang.bind(this, this._onPan));
@@ -311,6 +432,11 @@ const PaginationScrollView = new Lang.Class({
     },
 
     goToPage: function(pageNumber, action) {
+        if(this._currentPage != pageNumber && this._pages.displayingPopup && this._currentPopup) {
+            this._currentPopup.popdown();
+        } else if(this._pages.displayingPopup && this._currentPopup){
+            return;
+        }
         let velocity;
         if(!action)
             velocity = 0;
@@ -329,8 +455,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
@@ -380,6 +505,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)
@@ -400,12 +527,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;
@@ -413,6 +541,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) {
@@ -525,16 +655,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();
     }
 });
 
@@ -548,6 +672,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);
@@ -717,6 +842,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);
     },
@@ -1121,13 +1248,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) {
@@ -1178,11 +1308,15 @@ const FolderIcon = new Lang.Class({
     },
 
     makeSpaceForPopUp: function() {
-        //this._parentView.makeSpaceForPopUp(this._side, rows);
+        this._parentView.makeSpaceForPopUp(this, this._side, this.view.nRowsDisplayedAtOnce());
+    },
+    
+    returnSpaceToOriginalPosition: function() {
+        this._parentView.returnSpaceToOriginalPosition();
     },
     
-    onCompletemakeSpaceForPopUp: function() {
-        this._popup.toggle();
+    onCompleteMakeSpaceForPopUp: function() {
+        this._popup.popup();
     },
     
     _ensurePopup: function() {
@@ -1243,13 +1377,16 @@ const FolderIcon = new Lang.Class({
              */
             let usedHeight = this._popUpHeight();
             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 048866c..6d330ff 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -448,7 +448,7 @@ const IconGrid = new Lang.Class({
     },
     
     usedHeightForNRows: function(nRows) {
-        let spacePerRow = this._vItemSize + this.getSpacing();
+        let spacePerRow = this.rowHeight();
         return spacePerRow * nRows;
     },
     
@@ -529,5 +529,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]