[gnome-shell] [appDisplay] Factor out WellGrid/AppIcon



commit 8c1bf346a9e13ca9658060e5551c43ebb36fed5a
Author: Florian Müllner <fmuellner gnome org>
Date:   Wed Jul 21 04:22:19 2010 +0200

    [appDisplay] Factor out WellGrid/AppIcon
    
    All mockups now use a representation for documents/places similar to
    the one used for applications. Rename AppIcon to BaseIcon and move its
    code together with WellGrid out of appDisplay to stress their general
    usefulness.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=625887

 data/theme/gnome-shell.css |    2 +-
 js/Makefile.am             |    3 +-
 js/ui/appDisplay.js        |  182 +++----------------------------------
 js/ui/iconGrid.js          |  219 ++++++++++++++++++++++++++++++++++++++++++++
 js/ui/panel.js             |   10 +-
 5 files changed, 240 insertions(+), 176 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index cd70ec3..0e96be8 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -547,7 +547,7 @@ StTooltip {
     width: 440px;
 }
 
-#dashAppWell {
+.icon-grid {
     spacing: 6px;
     -shell-grid-item-size: 70px;
 }
diff --git a/js/Makefile.am b/js/Makefile.am
index 6412c71..bcafa50 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -21,6 +21,7 @@ nobase_dist_js_DATA = 	\
 	ui/environment.js	\
 	ui/extensionSystem.js	\
 	ui/genericDisplay.js	\
+	ui/iconGrid.js		\
 	ui/lightbox.js		\
 	ui/link.js		\
 	ui/lookingGlass.js	\
@@ -46,4 +47,4 @@ nobase_dist_js_DATA = 	\
 	ui/windowManager.js	\
 	ui/workspace.js		\
 	ui/workspacesView.js	\
-	ui/workspaceSwitcherPopup.js
\ No newline at end of file
+	ui/workspaceSwitcherPopup.js
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index a23d170..55d0768 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -12,6 +12,7 @@ const _ = Gettext.gettext;
 
 const AppFavorites = imports.ui.appFavorites;
 const DND = imports.ui.dnd;
+const IconGrid = imports.ui.iconGrid;
 const Main = imports.ui.main;
 const Overview = imports.ui.overview;
 const PopupMenu = imports.ui.popupMenu;
@@ -20,8 +21,7 @@ const Tweener = imports.ui.tweener;
 const Workspace = imports.ui.workspace;
 const Params = imports.misc.params;
 
-const APPICON_SIZE = 48;
-const WELL_MAX_COLUMNS = 8;
+const WELL_MAX_COLUMNS = 16;
 const WELL_MAX_SEARCH_ROWS = 1;
 const MENU_POPUP_TIMEOUT = 600;
 
@@ -32,7 +32,7 @@ function AlphabeticalView() {
 AlphabeticalView.prototype = {
     _init: function() {
         this.actor = new St.BoxLayout({ vertical: true });
-        this._grid = new WellGrid();
+        this._grid = new IconGrid.IconGrid();
         this._appSystem = Shell.AppSystem.get_default();
         this.actor.add(this._grid.actor, { y_align: St.Align.START, expand: true });
     },
@@ -222,7 +222,7 @@ AppSearchResultDisplay.prototype = {
 
     _init: function (provider) {
         Search.SearchResultDisplay.prototype._init.call(this, provider);
-        this._grid = new WellGrid({ rowLimit: WELL_MAX_SEARCH_ROWS });
+        this._grid = new IconGrid.IconGrid({ rowLimit: WELL_MAX_SEARCH_ROWS });
         this.actor = new St.Bin({ name: 'dashAppSearchResults',
                                   x_align: St.Align.START });
         this.actor.set_child(this._grid.actor);
@@ -368,23 +368,18 @@ function AppIcon(app) {
 }
 
 AppIcon.prototype = {
+    __proto__:  IconGrid.BaseIcon.prototype,
+
     _init : function(app) {
         this.app = app;
 
-        this.actor = new St.Bin({ style_class: 'app-icon',
-                                  x_fill: true,
-                                  y_fill: true });
-        this.actor._delegate = this;
-
-        let box = new St.BoxLayout({ vertical: true });
-        this.actor.set_child(box);
+        let label = this.app.get_name();
 
-        this.icon = this.app.create_icon_texture(APPICON_SIZE);
-
-        box.add(this.icon, { expand: true, x_fill: false, y_fill: false });
+        IconGrid.BaseIcon.prototype._init.call(this, label);
+    },
 
-        this._name = new St.Label({ text: this.app.get_name() });
-        box.add_actor(this._name);
+    createIcon: function(iconSize) {
+        return this.app.create_icon_texture(iconSize);
     }
 };
 
@@ -587,7 +582,7 @@ AppWellIcon.prototype = {
     },
 
     getDragActor: function() {
-        return this.app.create_icon_texture(APPICON_SIZE);
+        return this.app.create_icon_texture(this._icon.iconSize);
     },
 
     // Returns the original actor that should align with the actor
@@ -763,157 +758,6 @@ AppIconMenu.prototype = {
 };
 Signals.addSignalMethods(AppIconMenu.prototype);
 
-function WellGrid(params) {
-    this._init(params);
-}
-
-WellGrid.prototype = {
-    _init: function(params) {
-        params = Params.parse(params, { rowLimit: null });
-        this._rowLimit = params.rowLimit;
-
-        this.actor = new St.BoxLayout({ name: 'dashAppWell', vertical: true });
-        // Pulled from CSS, but hardcode some defaults here
-        this._spacing = 0;
-        this._item_size = 48;
-        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));
-
-        this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
-        this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
-        this._grid.connect('allocate', Lang.bind(this, this._allocate));
-    },
-
-    _getPreferredWidth: function (grid, forHeight, alloc) {
-        let children = this._grid.get_children();
-        let nColumns = children.length;
-        let totalSpacing = Math.max(0, nColumns - 1) * this._spacing;
-        // 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._item_size;
-        alloc.natural_size = nColumns * this._item_size + totalSpacing;
-    },
-
-    _getPreferredHeight: function (grid, forWidth, alloc) {
-        let children = this._grid.get_children();
-        let [nColumns, usedWidth] = this._computeLayout(forWidth);
-        let nRows;
-        if (nColumns > 0)
-            nRows = Math.ceil(children.length / nColumns);
-        else
-            nRows = 0;
-        if (this._rowLimit)
-            nRows = Math.min(nRows, this._rowLimit);
-        let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
-        let height = nRows * this._item_size + totalSpacing;
-        alloc.min_size = height;
-        alloc.natural_size = height;
-    },
-
-    _allocate: function (grid, box, flags) {
-        let children = this._grid.get_children();
-        let availWidth = box.x2 - box.x1;
-        let availHeight = box.y2 - box.y1;
-
-        let [nColumns, usedWidth] = this._computeLayout(availWidth);
-
-        let overallPaddingX = Math.floor((availWidth - usedWidth) / 2);
-
-        let x = box.x1 + overallPaddingX;
-        let y = box.y1;
-        let columnIndex = 0;
-        let rowIndex = 0;
-        for (let i = 0; i < children.length; i++) {
-            let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight]
-                = children[i].get_preferred_size();
-
-            /* Center the item in its allocation horizontally */
-            let width = Math.min(this._item_size, childNaturalWidth);
-            let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
-            let height = Math.min(this._item_size, childNaturalHeight);
-            let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
-
-            let childBox = new Clutter.ActorBox();
-            if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
-                let _x = box.x2 - (x + width);
-                childBox.x1 = Math.floor(_x - childXSpacing);
-            } else {
-                childBox.x1 = Math.floor(x + childXSpacing);
-            }
-            childBox.y1 = Math.floor(y + childYSpacing);
-            childBox.x2 = childBox.x1 + width;
-            childBox.y2 = childBox.y1 + height;
-
-            if (this._rowLimit && rowIndex >= this._rowLimit) {
-                this._grid.set_skip_paint(children[i], true);
-            } else {
-                children[i].allocate(childBox, flags);
-                this._grid.set_skip_paint(children[i], false);
-            }
-
-            columnIndex++;
-            if (columnIndex == nColumns) {
-                columnIndex = 0;
-                rowIndex++;
-            }
-
-            if (columnIndex == 0) {
-                y += this._item_size + this._spacing;
-                x = box.x1 + overallPaddingX;
-            } else {
-                x += this._item_size + this._spacing;
-            }
-        }
-    },
-
-    _computeLayout: function (forWidth) {
-        let children = this._grid.get_children();
-        let nColumns = 0;
-        let usedWidth = 0;
-        while (nColumns < WELL_MAX_COLUMNS &&
-                (usedWidth + this._item_size <= forWidth)) {
-            usedWidth += this._item_size + this._spacing;
-            nColumns += 1;
-        }
-
-        if (nColumns > 0)
-            usedWidth -= this._spacing;
-
-        return [nColumns, usedWidth];
-    },
-
-    _onStyleChanged: function() {
-        let themeNode = this.actor.get_theme_node();
-        let [success, len] = themeNode.get_length('spacing', false);
-        if (success)
-            this._spacing = len;
-        [success, len] = themeNode.get_length('-shell-grid-item-size', false);
-        if (success)
-            this._item_size = len;
-        this._grid.queue_relayout();
-    },
-
-    removeAll: function () {
-        this._grid.get_children().forEach(Lang.bind(this, function (child) {
-            child.destroy();
-        }));
-    },
-
-    addItem: function(actor) {
-        this._grid.add_actor(actor);
-    },
-
-    getItemAtIndex: function(index) {
-        return this._grid.get_children()[index];
-    },
-
-    visibleItemsCount: function() {
-        return this._grid.get_children().length - this._grid.get_n_skip_paint();
-    }
-};
-
 function AppWell() {
     this._init();
 }
@@ -926,7 +770,7 @@ AppWell.prototype = {
 
         this._favorites = [];
 
-        this._grid = new WellGrid();
+        this._grid = new IconGrid.IconGrid();
         this.actor = this._grid.actor;
         this.actor._delegate = this;
 
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
new file mode 100644
index 0000000..e728caf
--- /dev/null
+++ b/js/ui/iconGrid.js
@@ -0,0 +1,219 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Clutter = imports.gi.Clutter;
+const Shell = imports.gi.Shell;
+const St = imports.gi.St;
+
+const Lang = imports.lang;
+const Params = imports.misc.params;
+
+const ICON_SIZE = 48;
+
+
+function BaseIcon(label, createIcon) {
+    this._init(label, createIcon);
+}
+
+BaseIcon.prototype = {
+    _init : function(label, createIcon) {
+        this.actor = new St.Bin({ style_class: 'overview-icon',
+                                  x_fill: true,
+                                  y_fill: true });
+        this.actor._delegate = this;
+
+        this.actor.connect('style-changed',
+                           Lang.bind(this, this._onStyleChanged));
+
+        let box = new St.BoxLayout({ vertical: true });
+        this.actor.set_child(box);
+
+        this.iconSize = ICON_SIZE;
+        this._iconBin = new St.Bin();
+
+        box.add(this._iconBin, { expand: true, x_fill: false, y_fill: false });
+
+        this._name = new St.Label({ text: label });
+        box.add_actor(this._name);
+
+        if (createIcon)
+            this.createIcon = createIcon;
+
+        this.icon = this.createIcon(this.iconSize);
+        this._iconBin.set_child(this.icon);
+    },
+
+    // This can be overridden by a subclass, or by the createIcon
+    // parameter to _init()
+    createIcon: function(size) {
+        throw new Error('no implementation of createIcon in ' + this);
+    },
+
+    _onStyleChanged: function() {
+        let node = this.actor.get_theme_node();
+        let [success, len] = node.get_length('icon-size', false);
+        if (success) {
+            if (len == this.iconSize)
+                return;
+
+            this.icon.destroy();
+            this.iconSize = len;
+            this.icon = this.createIcon(this.iconSize);
+            this._iconBin.set_child(this.icon);
+        }
+    }
+};
+
+function IconGrid(params) {
+    this._init(params);
+}
+
+IconGrid.prototype = {
+    _init: function(params) {
+        params = Params.parse(params, { rowLimit: null, columnLimit: null });
+        this._rowLimit = params.rowLimit;
+        this._colLimit = params.columnLimit;
+
+        this.actor = new St.BoxLayout({ style_class: 'icon-grid',
+                                        vertical: true });
+        // Pulled from CSS, but hardcode some defaults here
+        this._spacing = 0;
+        this._item_size = ICON_SIZE;
+        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));
+
+        this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
+        this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
+        this._grid.connect('allocate', Lang.bind(this, this._allocate));
+    },
+
+    _getPreferredWidth: function (grid, forHeight, alloc) {
+        let children = this._grid.get_children();
+        let nColumns = this._colLimit ? Math.min(this._colLimit,
+                                                 children.length)
+                                      : children.length;
+        let totalSpacing = Math.max(0, nColumns - 1) * this._spacing;
+        // 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._item_size;
+        alloc.natural_size = nColumns * this._item_size + totalSpacing;
+    },
+
+    _getPreferredHeight: function (grid, forWidth, alloc) {
+        let children = this._grid.get_children();
+        let [nColumns, usedWidth] = this._computeLayout(forWidth);
+        let nRows;
+        if (nColumns > 0)
+            nRows = Math.ceil(children.length / nColumns);
+        else
+            nRows = 0;
+        if (this._rowLimit)
+            nRows = Math.min(nRows, this._rowLimit);
+        let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
+        let height = nRows * this._item_size + totalSpacing;
+        alloc.min_size = height;
+        alloc.natural_size = height;
+    },
+
+    _allocate: function (grid, box, flags) {
+        let children = this._grid.get_children();
+        let availWidth = box.x2 - box.x1;
+        let availHeight = box.y2 - box.y1;
+
+        let [nColumns, usedWidth] = this._computeLayout(availWidth);
+
+        let overallPaddingX = Math.floor((availWidth - usedWidth) / 2);
+
+        let x = box.x1 + overallPaddingX;
+        let y = box.y1;
+        let columnIndex = 0;
+        let rowIndex = 0;
+        for (let i = 0; i < children.length; i++) {
+            let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight]
+                = children[i].get_preferred_size();
+
+            /* Center the item in its allocation horizontally */
+            let width = Math.min(this._item_size, childNaturalWidth);
+            let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
+            let height = Math.min(this._item_size, childNaturalHeight);
+            let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
+
+            let childBox = new Clutter.ActorBox();
+            if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
+                let _x = box.x2 - (x + width);
+                childBox.x1 = Math.floor(_x - childXSpacing);
+            } else {
+                childBox.x1 = Math.floor(x + childXSpacing);
+            }
+            childBox.y1 = Math.floor(y + childYSpacing);
+            childBox.x2 = childBox.x1 + width;
+            childBox.y2 = childBox.y1 + height;
+
+            if (this._rowLimit && rowIndex >= this._rowLimit) {
+                this._grid.set_skip_paint(children[i], true);
+            } else {
+                children[i].allocate(childBox, flags);
+                this._grid.set_skip_paint(children[i], false);
+            }
+
+            columnIndex++;
+            if (columnIndex == nColumns) {
+                columnIndex = 0;
+                rowIndex++;
+            }
+
+            if (columnIndex == 0) {
+                y += this._item_size + this._spacing;
+                x = box.x1 + overallPaddingX;
+            } else {
+                x += this._item_size + this._spacing;
+            }
+        }
+    },
+
+    _computeLayout: function (forWidth) {
+        let children = this._grid.get_children();
+        let nColumns = 0;
+        let usedWidth = 0;
+        while ((this._colLimit == null || nColumns < this._colLimit) &&
+               (usedWidth + this._item_size <= forWidth)) {
+            usedWidth += this._item_size + this._spacing;
+            nColumns += 1;
+        }
+
+        if (nColumns > 0)
+            usedWidth -= this._spacing;
+
+        return [nColumns, usedWidth];
+    },
+
+    _onStyleChanged: function() {
+        let themeNode = this.actor.get_theme_node();
+        let [success, len] = themeNode.get_length('spacing', false);
+        if (success)
+            this._spacing = len;
+        [success, len] = themeNode.get_length('-shell-grid-item-size', false);
+        if (success)
+            this._item_size = len;
+        this._grid.queue_relayout();
+    },
+
+    removeAll: function () {
+        this._grid.get_children().forEach(Lang.bind(this, function (child) {
+            child.destroy();
+        }));
+    },
+
+    addItem: function(actor) {
+        this._grid.add_actor(actor);
+    },
+
+    getItemAtIndex: function(index) {
+        return this._grid.get_children()[index];
+    },
+
+    visibleItemsCount: function() {
+        return this._grid.get_children().length - this._grid.get_n_skip_paint();
+    }
+};
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 057e0e1..1f05710 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -11,7 +11,6 @@ const Signals = imports.signals;
 const Gettext = imports.gettext.domain('gnome-shell');
 const _ = Gettext.gettext;
 
-const AppDisplay = imports.ui.appDisplay;
 const Calendar = imports.ui.calendar;
 const Overview = imports.ui.overview;
 const PopupMenu = imports.ui.popupMenu;
@@ -219,10 +218,11 @@ AppMenuButton.prototype = {
 
         this._updateId = 0;
         this._animationStep = 0;
-        this._clipWidth = AppDisplay.APPICON_SIZE / 2;
+        this._clipWidth = PANEL_ICON_SIZE;
         this._direction = SPINNER_SPEED;
 
-        this._spinner = new AnimatedIcon('process-working.png', 24);
+        this._spinner = new AnimatedIcon('process-working.png',
+                                         PANEL_ICON_SIZE);
         this._container.add_actor(this._spinner.actor);
         this._spinner.actor.lower_bottom();
 
@@ -304,7 +304,7 @@ AppMenuButton.prototype = {
         }
         if (this._animationStep > 1)
             this._animationStep = 1;
-        this._clipWidth = this._label.actor.width - (this._label.actor.width - AppDisplay.APPICON_SIZE / 2) * (1 - this._animationStep);
+        this._clipWidth = this._label.actor.width - (this._label.actor.width - PANEL_ICON_SIZE) * (1 - this._animationStep);
         if (this.actor.get_direction() == St.TextDirection.LTR) {
             this._label.actor.set_clip(0, 0, this._clipWidth + this._shadow.width, this.actor.height);
         } else {
@@ -454,7 +454,7 @@ AppMenuButton.prototype = {
 
         let targetApp = this._focusedApp != null ? this._focusedApp : this._lastStartedApp;
         if (targetApp != null) {
-            let icon = targetApp.get_faded_icon(AppDisplay.APPICON_SIZE);
+            let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
 
             this._label.setText(targetApp.get_name());
             // TODO - _quit() doesn't really work on apps in state STARTING yet



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