[gnome-shell/wip/paging-release2: 24/24] appDisplay, iconGrid, searchDisplay: Adapt spacing and icons size to available screen size.



commit f0469fd840c56397605dbf5ba205c5d1895b0727
Author: Carlos Soriano <carlos soriano89 gmail com>
Date:   Thu Aug 15 10:38:17 2013 +0200

    appDisplay, iconGrid, searchDisplay: Adapt spacing and icons size to available screen size.
    
    Add a convenient function in IconGrid to calculate the responsive grid
    before any view allocation.
    This function use dynamic paddings on the views and scale the icons
    if the size given to the IconGrid is too small to fit a minimum of
    icons rows/columns
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706081

 js/ui/appDisplay.js    |   36 +++++++++----
 js/ui/iconGrid.js      |  139 ++++++++++++++++++++++++++++++++++++++----------
 js/ui/searchDisplay.js |    2 +-
 3 files changed, 138 insertions(+), 39 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index e7add85..618d28a 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -131,7 +131,7 @@ const BaseAppView = new Lang.Class({
             let id = this._getItemId(this._allItems[i]);
             if (!id)
                 continue;
-            this._grid.addItem(this._items[id].actor);
+            this._grid.addItem(this._items[id]);
         }
     }
 });
@@ -583,10 +583,9 @@ const AllView = new Lang.Class({
 
         // Update the adjustments based on display height
         this.updateAdjustment(availHeight);
+
         // Update grid dinamyc spacing based on display width
-        this._grid.updateSpacingForSize(availWidth, availHeight);
-        // Calculate pagination values
-        this._grid.computePages(availWidth, availHeight);
+        this._grid.calculateResponsiveGrid(availWidth, availHeight);
 
         if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != 
this._grid.nPages()) {
             this._verticalAdjustment.value = 0;
@@ -624,7 +623,7 @@ const FrequentView = new Lang.Class({
             if (!mostUsed[i].get_app_info().should_show())
                 continue;
             let appIcon = new AppIcon(mostUsed[i]);
-            this._grid.addItem(appIcon.actor, -1);
+            this._grid.addItem(appIcon, -1);
         }
     },
 
@@ -639,7 +638,7 @@ const FrequentView = new Lang.Class({
         box = this._grid.actor.get_theme_node().get_content_box(box);
         let availWidth = box.x2 - box.x1;
         let availHeight = box.y2 - box.y1;
-        this._grid.updateSpacingForSize(availWidth, availHeight);
+        this._grid.calculateResponsiveGrid(availWidth, availHeight);
     }
 });
 
@@ -976,7 +975,7 @@ const FolderView = new Lang.Class({
         this._parentAvailableWidth = width;
         this._parentAvailableHeight = height;
 
-        this._grid.updateSpacingForSize(width, height);
+        this._grid.calculateResponsiveGrid(width, height);
 
         // Set extra padding to avoid popup or close button being cut off
         this._grid.topPadding = Math.max(this._grid.topPadding - this._offsetForEachSide, 0);
@@ -1043,7 +1042,7 @@ const FolderIcon = new Lang.Class({
 
         let label = this._dir.get_name();
         this.icon = new IconGrid.BaseIcon(label,
-                                          { createIcon: Lang.bind(this, this._createIcon) });
+                                          { createIcon: Lang.bind(this, this._createIcon), setSizeManually: 
true });
         this.actor.set_child(this.icon.actor);
         this.actor.label_actor = this.icon.label;
 
@@ -1066,8 +1065,16 @@ const FolderIcon = new Lang.Class({
         }));
     },
 
-    _createIcon: function(size) {
-        return this.view.createFolderIcon(size, this);
+    _createIcon: function(iconSize) {
+        return this.view.createFolderIcon(iconSize, this);
+    },
+
+    getIconSize: function() {
+        return this.icon.iconSize;
+    },
+
+    setIconSize: function(size) {
+        this.icon.setIconSize(size);
     },
 
     _popupHeight: function() {
@@ -1283,6 +1290,7 @@ const AppIcon = new Lang.Class({
             iconParams = {};
 
         iconParams['createIcon'] = Lang.bind(this, this._createIcon);
+        iconParams['setSizeManually'] = true;
         this.icon = new IconGrid.BaseIcon(app.get_name(), iconParams);
         this.actor.set_child(this.icon.actor);
 
@@ -1330,6 +1338,14 @@ const AppIcon = new Lang.Class({
         return this.app.create_icon_texture(iconSize);
     },
 
+    getIconSize: function() {
+        return this.icon.iconSize;
+    },
+
+    setIconSize: function(size) {
+        this.icon.setIconSize(size);
+    },
+
     _removeMenuTimeout: function() {
         if (this._menuTimeoutId > 0) {
             Mainloop.source_remove(this._menuTimeoutId);
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index 77036ae..cdf6b5d 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -3,12 +3,13 @@
 const Clutter = imports.gi.Clutter;
 const Shell = imports.gi.Shell;
 const St = imports.gi.St;
+const Meta = imports.gi.Meta;
 
 const Lang = imports.lang;
 const Params = imports.misc.params;
 
-const ICON_SIZE = 48;
-
+const ICON_SIZE = 96;
+const MIN_ICON_SIZE = 16;
 
 const BaseIcon = new Lang.Class({
     Name: 'BaseIcon',
@@ -201,10 +202,11 @@ const IconGrid = new Lang.Class({
 
         this.actor = new St.BoxLayout({ style_class: 'icon-grid',
                                         vertical: true });
-
+        this._items = [];
         // Pulled from CSS, but hardcode some defaults here
         this._spacing = 0;
         this._hItemSize = this._vItemSize = ICON_SIZE;
+        this._fixedHItemSize = this._fixedVItemSize = undefined;
         this._grid = new Shell.GenericContainer();
         this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
         this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
@@ -228,8 +230,8 @@ const IconGrid = new Lang.Class({
         // Kind of a lie, but not really an issue right now.  If
         // we wanted to support some sort of hidden/overflow that would
         // need higher level design
-        alloc.min_size = this._hItemSize + this.leftPadding + this.rightPadding;
-        alloc.natural_size = nColumns * this._hItemSize + totalSpacing + this.leftPadding + 
this.rightPadding;
+        alloc.min_size = this.getHItemSize() + this.leftPadding + this.rightPadding;
+        alloc.natural_size = nColumns * this.getHItemSize() + totalSpacing + this.leftPadding + 
this.rightPadding;
     },
 
     _getVisibleChildren: function() {
@@ -261,7 +263,7 @@ const IconGrid = new Lang.Class({
         if (this._rowLimit)
             nRows = Math.min(nRows, this._rowLimit);
         let totalSpacing = Math.max(0, nRows - 1) * this._getSpacing();
-        let height = nRows * this._vItemSize + totalSpacing + this.topPadding + this.bottomPadding;
+        let height = nRows * this.getVItemSize() + totalSpacing + this.topPadding + this.bottomPadding;
         alloc.min_size = height;
         alloc.natural_size = height;
     },
@@ -314,10 +316,10 @@ const IconGrid = new Lang.Class({
             }
 
             if (columnIndex == 0) {
-                y += this._vItemSize + spacing;
+                y += this.getVItemSize() + spacing;
                 x = box.x1 + leftEmptySpace + this.leftPadding;
             } else {
-                x += this._hItemSize + spacing;
+                x += this.getHItemSize() + spacing;
             }
         }
     },
@@ -327,9 +329,9 @@ const IconGrid = new Lang.Class({
              child.get_preferred_size();
 
         /* Center the item in its allocation horizontally */
-        let width = Math.min(this._hItemSize, childNaturalWidth);
+        let width = Math.min(this.getHItemSize(), childNaturalWidth);
         let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
-        let height = Math.min(this._vItemSize, childNaturalHeight);
+        let height = Math.min(this.getVItemSize(), childNaturalHeight);
         let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
 
         let childBox = new Clutter.ActorBox();
@@ -363,8 +365,8 @@ const IconGrid = new Lang.Class({
         let spacing = this._getSpacing();
 
         while ((this._colLimit == null || nColumns < this._colLimit) &&
-               (usedWidth + this._hItemSize <= forWidth)) {
-            usedWidth += this._hItemSize + spacing;
+               (usedWidth + this.getHItemSize() <= forWidth)) {
+            usedWidth += this.getHItemSize() + spacing;
             nColumns += 1;
         }
 
@@ -383,7 +385,7 @@ const IconGrid = new Lang.Class({
     },
 
     rowHeight: function() {
-        return this._vItemSize + this._getSpacing();
+        return this.getVItemSize() + this._getSpacing();
     },
 
     nRows: function(forWidth) {
@@ -396,28 +398,36 @@ const IconGrid = new Lang.Class({
     },
 
     rowsForHeight: function(forHeight) {
-        return Math.floor((forHeight -(this.topPadding + this.bottomPadding) + this._getSpacing()) / 
(this._vItemSize + this._getSpacing()));
+        return Math.floor((forHeight -(this.topPadding + this.bottomPadding) + this._getSpacing()) / 
(this.getVItemSize() + this._getSpacing()));
     },
 
     usedHeightForNRows: function(nRows) {
-        return (this._vItemSize + this._getSpacing()) * nRows - this._getSpacing() + this.topPadding + 
this.bottomPadding;
+        return (this.getVItemSize() + this._getSpacing()) * nRows - this._getSpacing() + this.topPadding + 
this.bottomPadding;
     },
 
     usedWidth: function(forWidth) {
-        let usedWidth = this.columnsForWidth(forWidth) * (this._hItemSize + this._getSpacing());
+        let usedWidth = this.columnsForWidth(forWidth) * (this.getHItemSize() + this._getSpacing());
+        usedWidth -= this._getSpacing();
+        return usedWidth + this.leftPadding + this.rightPadding;
+    },
+
+    usedWidthForNColumns: function(columns) {
+        let usedWidth = columns  * (this.getHItemSize() + this._getSpacing());
         usedWidth -= this._getSpacing();
         return usedWidth + this.leftPadding + this.rightPadding;
     },
 
     removeAll: function() {
+        this._items = [];
         this._grid.destroy_all_children();
     },
 
-    addItem: function(actor, index) {
+    addItem: function(item, index) {
+        this._items.push(item);
         if (index !== undefined)
-            this._grid.insert_child_at_index(actor, index);
+            this._grid.insert_child_at_index(item.actor, index);
         else
-            this._grid.add_actor(actor);
+            this._grid.add_actor(item.actor);
     },
 
     getItemAtIndex: function(index) {
@@ -436,13 +446,21 @@ const IconGrid = new Lang.Class({
         return this._fixedSpacing ? this._fixedSpacing : this._spacing;
     },
 
+    getHItemSize: function() {
+        return this._fixedHItemSize ? this._fixedHItemSize : this._hItemSize;
+    },
+
+    getVItemSize: function() {
+        return this._fixedVItemSize ? this._fixedVItemSize : this._vItemSize;
+    },
+
     /**
      * This function must to be called before iconGrid allocation,
      * to know how much spacing can the grid has
      */
     updateSpacingForSize: function(availWidth, availHeight) {
-        let maxEmptyVArea = availHeight - this._minRows * this._vItemSize;
-        let maxEmptyHArea = availWidth - this._minColumns * this._hItemSize;
+        let maxEmptyVArea = availHeight - this._minRows * this.getVItemSize();
+        let maxEmptyHArea = availWidth - this._minColumns * this.getHItemSize();
         let maxHSpacing, maxVSpacing;
 
         if (this._padWithSpacing) {
@@ -464,13 +482,74 @@ const IconGrid = new Lang.Class({
 
         let maxSpacing = Math.min(maxHSpacing, maxVSpacing);
         // Limit spacing to the item size
-        maxSpacing = Math.min(maxSpacing, Math.min(this._vItemSize, this._hItemSize));
-        // The minimum spacing, regardless of whether it satisfies the row/column minima,
+        maxSpacing = Math.min(maxSpacing, Math.min(this.getVItemSize(), this.getHItemSize()));
+        // The minimum spacing, regardless of whether it satisfies the row/columng minima,
         // is the spacing we get from CSS.
         let spacing = Math.max(this._spacing, maxSpacing);
         this.setSpacing(spacing);
         if (this._padWithSpacing)
             this.topPadding = this.rightPadding = this.bottomPadding = this.leftPadding = spacing;
+    },
+
+    calculateResponsiveGrid: function(availWidth, availHeight) {
+        this._fixedHItemSize = this._hItemSize;
+        this._fixedVItemSize = this._vItemSize;
+        this.updateSpacingForSize(availWidth, availHeight);
+        let spacing = this._getSpacing();
+        if (this._useSurroundingSpacing)
+            this.topPadding = this.rightPadding = this.bottomPadding = this.leftPadding = spacing;
+
+        let count = 0;
+        if (this.columnsForWidth(availWidth) < this._minColumns || this.rowsForHeight(availHeight) < 
this._minRows) {
+            let neededWidth, neededHeight;
+            if (this._useSurroundingSpacing)
+                neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth ;
+            else
+                neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth ;
+
+            if (this._useSurroundingSpacing)
+                neededHeight = this.usedHeightForNRows(this._minRows) - availHeight;
+            else
+                neededHeight = this.usedHeightForNRows(this._minRows) - availHeight ;
+
+            if (neededWidth > neededHeight) {
+                let neededSpaceForEachItem = Math.ceil(neededWidth / this._minColumns);
+                this._fixedHItemSize = this._hItemSize - neededSpaceForEachItem;
+                this._fixedVItemSize = this._vItemSize - neededSpaceForEachItem;
+            } else {
+                let neededSpaceForEachItem = Math.ceil(neededHeight / this._minRows);
+                this._fixedHItemSize = this._hItemSize - neededSpaceForEachItem;
+                this._fixedVItemSize = this._vItemSize - neededSpaceForEachItem;
+            }
+
+            if (this._fixedHItemSize < MIN_ICON_SIZE)
+                this._fixedHItemSize = MIN_ICON_SIZE;
+            if (this._fixedVItemSize < MIN_ICON_SIZE)
+                this._fixedVItemSize = MIN_ICON_SIZE;
+
+            this.updateSpacingForSize(availWidth, availHeight);
+            if (this._useSurroundingSpacing)
+                this.topPadding = this.rightPadding = this.bottomPadding = this.leftPadding = spacing;
+        }
+        let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, 
this._vItemSize);
+        this.updateChildrenScale(scale);
+    },
+
+    /**
+     * We are supossing that the this._items contain some item that we can set its size. 
+     * Also, we suposse that they are icons, and the original size is ICON_SIZE, to let the good icon size 
when updating the size.
+     * Also, we supose that we need a Meta.later, since when we call calculateResponsiveGrid that calls 
updateChildrenScale
+     * we are inside the allocation of the AppDisplay, and modifinyg icon size can cause allocation cycles
+     * So this functions is not intentded to be called outside this class, lets think a little about that. 
Now reescaling icons
+     * works fine at least.
+     */
+    updateChildrenScale: function(scale) {
+        Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
+            for (let i in this._items) {
+                let newIconSize = Math.floor(ICON_SIZE * scale);
+                this._items[i].setIconSize(newIconSize);
+            }
+        }));
     }
 });
 
@@ -532,13 +611,12 @@ const PaginatedIconGrid = new Lang.Class({
                 rowIndex++;
             }
             if (columnIndex == 0) {
-                y += this._vItemSize + spacing;
+                y += this.getVItemSize() + spacing;
                 if ((i + 1) % this._childrenPerPage == 0)
-                    y += this._spaceBetweenPages - spacing  + this.bottomPadding + this.topPadding;
+                    y +=  this._spaceBetweenPages - spacing + this.bottomPadding + this.topPadding;
                 x = box.x1 + leftEmptySpace + this.leftPadding;
-            } else {
-                x += this._hItemSize + spacing;
-            }
+            } else
+                x += this.getHItemSize() + spacing;
         }
     },
 
@@ -561,6 +639,11 @@ const PaginatedIconGrid = new Lang.Class({
         this._childrenPerPage = nColumns * this._rowsPerPage;
     },
 
+    calculateResponsiveGrid: function(availWidth, availHeight) {
+        this.parent(availWidth, availHeight);
+        this.computePages(availWidth, availHeight);
+    },
+
     rowsPerPage: function() {
         return this._rowsPerPage;
     },
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
index 9d47e44..a7a1cde 100644
--- a/js/ui/searchDisplay.js
+++ b/js/ui/searchDisplay.js
@@ -327,7 +327,7 @@ const GridSearchResults = new Lang.Class({
         for (let i = 0; i < metas.length; i++) {
             let display = new GridSearchResult(this.provider, metas[i], this._terms);
             display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
-            this._grid.addItem(display.actor);
+            this._grid.addItem(display);
         }
     },
 


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