[gnome-shell/wip/paging-release: 2/85] Paggination
- From: Carlos Soriano <csoriano src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/paging-release: 2/85] Paggination
- Date: Mon, 12 Aug 2013 15:58:31 +0000 (UTC)
commit 61f314b3246a8a95593cd805b3c53abbd8db51b1
Author: Carlos Soriano <csoriano src gnome org>
Date: Fri Jun 14 11:58:50 2013 +0200
Paggination
First attempt of pagination with scrollActor.
Work done:
-Separate applications in pages
-Scroll changes between pages
First attempt of pagination with St.ScrollView
work done:
-Applications divided into pages
-Scroll working to change between pages
Some clean-up
Make iconGrid with pagination mode
js/ui/appDisplay.js | 239 ++++++++++++++++++++++++++++++++-------------------
js/ui/iconGrid.js | 134 ++++++++++++++++++++++------
2 files changed, 256 insertions(+), 117 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 41ecddc..6c519eb 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -36,7 +36,7 @@ const FOLDER_SUBICON_FRACTION = .4;
// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
-function _loadCategory(dir, view) {
+function _loadCategory(dir, list) {
let iter = dir.iter();
let appSystem = Shell.AppSystem.get_default();
let nextType;
@@ -45,11 +45,11 @@ function _loadCategory(dir, view) {
let entry = iter.get_entry();
let app = appSystem.lookup_app_by_tree_entry(entry);
if (!entry.get_app_info().get_nodisplay())
- view.addApp(app);
+ list.addApp(app);
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
let itemDir = iter.get_directory();
if (!itemDir.get_is_nodisplay())
- _loadCategory(itemDir, view);
+ _loadCategory(itemDir, list);
}
}
};
@@ -60,6 +60,7 @@ const AlphabeticalView = new Lang.Class({
_init: function() {
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.MIDDLE,
+ usePagination: true,
columnLimit: MAX_COLUMNS });
// Standard hack for ClutterBinLayout
@@ -156,80 +157,13 @@ const FolderView = new Lang.Class({
}
});
-const AllViewLayout = new Lang.Class({
- Name: 'AllViewLayout',
- Extends: Clutter.BinLayout,
-
- vfunc_get_preferred_height: function(container, forWidth) {
- let minBottom = 0;
- let naturalBottom = 0;
-
- for (let child = container.get_first_child();
- child;
- child = child.get_next_sibling()) {
- let childY = child.y;
- let [childMin, childNatural] = child.get_preferred_height(forWidth);
-
- if (childMin + childY > minBottom)
- minBottom = childMin + childY;
-
- if (childNatural + childY > naturalBottom)
- naturalBottom = childNatural + childY;
- }
- return [minBottom, naturalBottom];
- }
-});
-
-const AllView = new Lang.Class({
- Name: 'AllView',
+const AppPages = new Lang.Class({
+ Name: 'AppPages',
Extends: AlphabeticalView,
-
+
_init: function() {
this.parent();
-
- this._grid.actor.y_align = Clutter.ActorAlign.START;
- this._grid.actor.y_expand = true;
-
- let box = new St.BoxLayout({ vertical: true });
- this._stack = new St.Widget({ layout_manager: new AllViewLayout() });
- this._stack.add_actor(this._grid.actor);
- this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
- this._stack.add_actor(this._eventBlocker);
- box.add(this._stack, { y_align: St.Align.START, expand: true });
-
- this.actor = new St.ScrollView({ x_fill: true,
- y_fill: false,
- y_align: St.Align.START,
- x_expand: true,
- y_expand: true,
- overlay_scrollbars: true,
- style_class: 'all-apps vfade' });
- this.actor.add_actor(box);
- this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- let action = new Clutter.PanAction({ interpolate: true });
- action.connect('pan', Lang.bind(this, this._onPan));
- this.actor.add_action(action);
-
- this._clickAction = new Clutter.ClickAction();
- this._clickAction.connect('clicked', Lang.bind(this, function() {
- if (!this._currentPopup)
- return;
-
- let [x, y] = this._clickAction.get_coords();
- let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
- if (!this._currentPopup.actor.contains(actor))
- this._currentPopup.popdown();
- }));
- this._eventBlocker.add_action(this._clickAction);
- },
-
- _onPan: function(action) {
- this._clickAction.release();
-
- let [dist, dx, dy] = action.get_motion_delta(0);
- let adjustment = this.actor.vscroll.adjustment;
- adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
- return false;
+ this.actor = this._grid.actor;
},
_getItemId: function(item) {
@@ -240,7 +174,7 @@ const AllView = new Lang.Class({
else
return null;
},
-
+
_createItemIcon: function(item) {
if (item instanceof Shell.App)
return new AppIcon(item);
@@ -257,22 +191,147 @@ const AllView = new Lang.Class({
let nameB = GLib.utf8_collate_key(itemB.get_name(), -1);
return (nameA > nameB) ? 1 : (nameA < nameB ? -1 : 0);
},
+
+ addItem: function(item) {
+ this._addItem(item);
+ },
+
+ nPages: function() {
+ return this._grid.nPages();
+ },
+
+ goToPreviousPage: function() {
+ this._grid.goToPreviousPage();
+ },
+
+ goToNextPage: function() {
+ this._grid.goToNextPage();
+ },
+
+ goToFirstPage: function() {
+ this._grid.goToFirstPage();
+ },
+
+ currentPagePosition: function() {
+ return this._grid.currentPagePosition();
+ },
+
+ setGridParentSize: function(size) {
+ this._grid._parentSize = size;
+ }
+});
+const PaginationScrollActor = new Lang.Class({
+ Name: 'PaginationScrollActor',
+ Extends: St.ScrollView,
+
+ _init: function() {
+ this.parent();
+ this._box = new St.BoxLayout({vertical: true});
+ this._pages = new AppPages();
+ this._box.add_actor(this._pages.actor);
+ this.add_actor(this._box);
+
+ this.connect('scroll-event', Lang.bind(this, this._onScroll));
+ },
+
+ vfunc_get_preferred_height: function (container, forWidht) {
+ return [0, 0];
+ },
+
+ vfunc_get_preferred_width: function(container, forHeight) {
+ return [0, 0];
+ },
+
+ vfunc_allocate: function(box, flags) {
+ box = this.get_parent().allocation;
+ this.set_allocation(box, flags);
+ let availWidth = box.x2 - box.x1;
+ let availHeight = box.y2 - box.y1;
+
+ let childBox = new Clutter.ActorBox();
+ //Get the boxLayout inside scrollView
+ let child = this.get_children()[2];
+ let childWidth = child.get_preferred_width(availHeight)[1];
+
+ childBox.x1 = 0;
+ childBox.y1 = 0;
+ childBox.x2 = availWidth;
+ childBox.y2 = availHeight;
+
+ this._pages.setGridParentSize([availWidth, availHeight]);
+
+ child.allocate(childBox, flags);
+
+ if(this._pages.nPages > 0) {
+ this._pages.goToFirstPage();
+ this.vscroll.adjustment.set_value(this._pages.currentPagePosition()[1]);
+ }
+ },
+
+ goToNextPage: function() {
+ this._pages.goToNextPage();
+ this.vscroll.adjustment.set_value(this._pages.currentPagePosition()[1]);
+ },
+ goToPreviousPage: function() {
+ this._pages.goToPreviousPage();
+ this.vscroll.adjustment.set_value(this._pages.currentPagePosition()[1]);
+ },
+
+ _onScroll: function(actor, event) {
+ let direction = event.get_scroll_direction();
+ if (direction == Clutter.ScrollDirection.UP)
+ this.goToPreviousPage();
+ if (direction == Clutter.ScrollDirection.DOWN)
+ this.goToNextPage();
+ }
+});
+
+const AllView = new Lang.Class({
+ Name: 'AllView',
+
+ _init: function() {
+ this.actor = new PaginationScrollActor();
+ this._pageControl = new St.Widget();
+ },
+
+ _onKeyRelease: function(actor, event) {
+ if (event.get_key_symbol() == Clutter.KEY_Up) {
+ this.actor.goToNextPage();
+ return true;
+ } else if(event.get_key_symbol() == Clutter.KEY_Down) {
+ this.actor.goToPreviousPage();
+ return true
+ }
+
+ return false;
+ },
+
+ _onPan: function(action) {
+ /*
+ this._clickAction.release();
+
+ let [dist, dx, dy] = action.get_motion_delta(0);
+ let adjustment = this.actor.vscroll.adjustment;
+ adjustment.value -= (dy / this.actor.height) * adjustment.page_size;*/
+ return false;
+ },
addApp: function(app) {
- let appIcon = this._addItem(app);
- if (appIcon)
+ let appIcon = this.actor._pages.addItem(app);
+ /*if (appIcon)
appIcon.actor.connect('key-focus-in',
- Lang.bind(this, this._ensureIconVisible));
+ Lang.bind(this, this._ensureIconVisible));*/
},
addFolder: function(dir) {
- let folderIcon = this._addItem(dir);
- if (folderIcon)
+ let folderIcon = this.actor._pages.addItem(dir);
+ /*if (folderIcon)
folderIcon.actor.connect('key-focus-in',
- Lang.bind(this, this._ensureIconVisible));
+ Lang.bind(this, this._ensureIconVisible));*/
},
addFolderPopup: function(popup) {
+ /*
this._stack.add_actor(popup.actor);
popup.connect('open-state-changed', Lang.bind(this,
function(popup, isOpen) {
@@ -285,11 +344,7 @@ const AllView = new Lang.Class({
} else {
this._grid.actor.y = 0;
}
- }));
- },
-
- _ensureIconVisible: function(icon) {
- Util.ensureActorVisibleInScrollView(this.actor, icon);
+ }));*/
},
_updateIconOpacities: function(folderOpen) {
@@ -299,6 +354,14 @@ const AllView = new Lang.Class({
else
this._items[id].actor.opacity = 255;
}
+ },
+
+ removeAll: function() {
+ this.actor._pages.removeAll();
+ },
+
+ loadGrid: function() {
+ this.actor._pages.loadGrid();
}
});
@@ -327,8 +390,7 @@ const FrequentView = new Lang.Class({
continue;
let appIcon = new AppIcon(mostUsed[i]);
this._grid.addItem(appIcon.actor, -1);
- }
- }
+ } }
});
const Views = {
@@ -1027,3 +1089,4 @@ const AppIconMenu = new Lang.Class({
}
});
Signals.addSignalMethods(AppIconMenu.prototype);
+
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index 416e659..5936a0c 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -177,12 +177,21 @@ const IconGrid = new Lang.Class({
params = Params.parse(params, { rowLimit: null,
columnLimit: null,
fillParent: false,
- xAlign: St.Align.MIDDLE });
+ xAlign: St.Align.MIDDLE,
+ usePagination: false});
this._rowLimit = params.rowLimit;
this._colLimit = params.columnLimit;
this._xAlign = params.xAlign;
this._fillParent = params.fillParent;
-
+ this._usePagination = params.usePagination;
+
+ if(this._usePagination) {
+ this._nPages = 0;
+ //Set this variable properly before getPreferredHeight function is called
+ this._parentSize = [0, 0];
+ this._currentPage = 0;
+ this._firstPagesItems = [];
+ }
this.actor = new St.BoxLayout({ style_class: 'icon-grid',
vertical: true });
@@ -196,6 +205,7 @@ const IconGrid = new Lang.Class({
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) {
@@ -248,12 +258,25 @@ const IconGrid = new Lang.Class({
nRows = Math.min(nRows, this._rowLimit);
let totalSpacing = Math.max(0, nRows - 1) * spacing;
let height = nRows * this._vItemSize + totalSpacing;
+
+ if(this._usePagination) {
+
+ this._spacePerRow = this._vItemSize + spacing;
+ this._rowsPerPage = Math.floor(this._parentSize[1] / this._spacePerRow);
+ this._nPages = Math.ceil(nRows / this._rowsPerPage);
+ this._spaceBetweenPages = this._parentSize[1] - (this._rowsPerPage * (this._vItemSize +
spacing));
+ let spaceBetweenPagesTotal = this._spaceBetweenPages * (this._nPages);
+ this._childrenPerPage = nColumns * this._rowsPerPage;
+ alloc.min_size = this._rowsPerPage * this._spacePerRow * this._nPages + spaceBetweenPagesTotal;
+ alloc.natural_size = this._rowsPerPage * this._spacePerRow * this._nPages +
spaceBetweenPagesTotal;
+ return;
+ }
alloc.min_size = height;
alloc.natural_size = height;
},
_allocate: function (grid, box, flags) {
- if (this._fillParent) {
+ if(this._fillParent) {
// Reset the passed in box to fill the parent
let parentBox = this.actor.get_parent().allocation;
let gridBox = this.actor.get_theme_node().get_content_box(parentBox);
@@ -263,8 +286,11 @@ const IconGrid = new Lang.Class({
let children = this._getVisibleChildren();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
-
let [nColumns, usedWidth, spacing] = this._computeLayout(availWidth);
+ if(this._usePagination) {
+ //Recalculate the space between pages with the new spacing
+ this._spaceBetweenPages = this._parentSize[1] - (this._rowsPerPage * (this._vItemSize +
spacing));
+ }
let leftPadding;
switch(this._xAlign) {
@@ -282,35 +308,25 @@ const IconGrid = new Lang.Class({
let y = box.y1;
let columnIndex = 0;
let rowIndex = 0;
+
+ if(children.length > 0) {
+ this._firstPagesItems = [children[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._hItemSize, childNaturalWidth);
- let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
- let height = Math.min(this._vItemSize, childNaturalHeight);
- let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
-
- let childBox = new Clutter.ActorBox();
- if (Clutter.get_default_text_direction() == Clutter.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._fillParent && childBox.y2 > availHeight) {
- this._grid.set_skip_paint(children[i], true);
+ let childBox = this._calculateChildrenBox(children[i], x, y);
+ if(!this._usePagination) {
+ if (this._rowLimit && rowIndex >= this._rowLimit ||
+ this._fillParent && childBox.y2 > availHeight) {
+ this._grid.set_skip_paint(children[i], true);
+ } else {
+ children[i].allocate(childBox, flags);
+ this._grid.set_skip_paint(children[i], false);
+ }
} else {
children[i].allocate(childBox, flags);
this._grid.set_skip_paint(children[i], false);
}
-
+
columnIndex++;
if (columnIndex == nColumns) {
columnIndex = 0;
@@ -319,6 +335,14 @@ const IconGrid = new Lang.Class({
if (columnIndex == 0) {
y += this._vItemSize + spacing;
+ if(this._usePagination) {
+ if((i + 1) % this._childrenPerPage == 0) {
+ y+= this._spaceBetweenPages;
+ if(i < children.length) {
+ this._firstPagesItems.push(children[i+1]);
+ }
+ }
+ }
x = box.x1 + leftPadding;
} else {
x += this._hItemSize + spacing;
@@ -326,8 +350,31 @@ const IconGrid = new Lang.Class({
}
},
+ _calculateChildrenBox: function(child, x, y) {
+ let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight]
+ = child.get_preferred_size();
+
+ /* Center the item in its allocation horizontally */
+ let width = Math.min(this._hItemSize, childNaturalWidth);
+ let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
+ let height = Math.min(this._vItemSize, childNaturalHeight);
+ let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
+
+ let childBox = new Clutter.ActorBox();
+ if (Clutter.get_default_text_direction() == Clutter.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;
+ return childBox;
+ },
+
childrenInRow: function(rowWidth) {
- return this._computeLayout(rowWidth)[0];
+ return this._computeLayout(rowWidth)[0]
},
getRowLimit: function() {
@@ -383,5 +430,34 @@ const IconGrid = new Lang.Class({
visibleItemsCount: function() {
return this._grid.get_n_children() - this._grid.get_n_skip_paint();
+ },
+
+ nPages: function() {
+ return this._nPages;
+ },
+
+ currentPagePosition: function() {
+ let childBox = this._firstPagesItems[this._currentPage].get_allocation_box();
+ return [childBox.x1, childBox.y1];
+ },
+
+ goToNextPage: function() {
+ if(!this._nPages)
+ return;
+ if(this._currentPage + 1 < this._firstPagesItems.length)
+ this._currentPage++;
+ },
+
+ goToPreviousPage: function() {
+ if(!this._nPages)
+ return;
+ if(this._currentPage > 0)
+ this._currentPage--;
+ },
+
+ goToFirstPage: function() {
+ if(!this._nPages)
+ return;
+ this._currentPage = 0;
}
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]