[gnome-shell/wip/paging-release2: 5/12] AppDisplay: Add pages indicators
- From: Carlos Soriano <csoriano src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/paging-release2: 5/12] AppDisplay: Add pages indicators
- Date: Tue, 20 Aug 2013 22:05:00 +0000 (UTC)
commit e9c28a13636808bc6afaf29545e53d8c757d2b43
Author: Carlos Soriano <carlos soriano89 gmail com>
Date: Mon Aug 12 19:09:43 2013 +0200
AppDisplay: Add pages indicators
Add indicators to the AllView pagination, which display
how many pages of apps we have and allow the user to
navigate through them.
data/Makefile.am | 2 +
data/theme/gnome-shell.css | 16 +++-
data/theme/page-indicator-active.svg | 67 +++++++++++++++
data/theme/page-indicator-inactive.svg | 67 +++++++++++++++
js/ui/appDisplay.js | 146 ++++++++++++++++++++++++++++++-
5 files changed, 292 insertions(+), 6 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index ece7925..3126e27 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -41,6 +41,8 @@ dist_theme_DATA = \
theme/message-tray-background.png \
theme/more-results.svg \
theme/noise-texture.png \
+ theme/page-indicator-active.svg \
+ theme/page-indicator-inactive.svg \
theme/panel-button-border.svg \
theme/panel-button-highlight-narrow.svg \
theme/panel-button-highlight-wide.svg \
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 2342579..ce7d445 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -899,11 +899,25 @@ StScrollBar StButton#vhandle:active {
.search-display > StBoxLayout,
.all-apps,
-.frequent-apps > StBoxLayout {
+.frequent-apps > StBoxLayout{
/* horizontal padding to make sure scrollbars or dash don't overlap content */
padding: 0px 88px 10px 88px;
}
+.pages-icon-indicator {
+ background-image: url(page-indicator-inactive.svg);
+}
+
+.pages-icon-indicator:hover,
+.pages-icon-indicator:checked{
+ background-image: url(page-indicator-active.svg);
+}
+
+.pages-indicator {
+ spacing: 35px;
+ padding: 0px, 20px 0px, 0px;
+}
+
.app-folder-icon {
padding: 5px;
}
diff --git a/data/theme/page-indicator-active.svg b/data/theme/page-indicator-active.svg
new file mode 100644
index 0000000..38b720f
--- /dev/null
+++ b/data/theme/page-indicator-active.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="18"
+ height="18"
+ id="svg4703"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="page-indicator-active.svg">
+ <defs
+ id="defs4705" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.197802"
+ inkscape:cx="2.1522887"
+ inkscape:cy="16.782904"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="1021"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata4708">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,2)">
+ <path
+ transform="matrix(0.72823872,0,0,0.8336417,-1512.2872,-525.55618)"
+ d="m 2099.9808,638.83099 c 0,5.29998 -4.9184,9.59645 -10.9854,9.59645 -6.0671,0 -10.9854,-4.29647
-10.9854,-9.59645 0,-5.29997 4.9183,-9.59645 10.9854,-9.59645 6.067,0 10.9854,4.29648 10.9854,9.59645 z"
+ sodipodi:ry="9.5964489"
+ sodipodi:rx="10.985409"
+ sodipodi:cy="638.83099"
+ sodipodi:cx="2088.9954"
+ id="path4711"
+ style="fill:#fdffff;fill-opacity:0.94117647;stroke:none"
+ sodipodi:type="arc" />
+ </g>
+</svg>
diff --git a/data/theme/page-indicator-inactive.svg b/data/theme/page-indicator-inactive.svg
new file mode 100644
index 0000000..3048f56
--- /dev/null
+++ b/data/theme/page-indicator-inactive.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="18"
+ height="18"
+ id="svg5266"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="page-indicator-inactive.svg">
+ <defs
+ id="defs5268" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.313709"
+ inkscape:cx="13.381365"
+ inkscape:cy="17.859535"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="1021"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5271">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,2)">
+ <path
+ sodipodi:type="arc"
+
style="fill:#ffffff;fill-opacity:0;stroke:#ffffff;stroke-width:2.93356276;stroke-miterlimit:4;stroke-opacity:0.39215686;stroke-dasharray:none"
+ id="path5274"
+ sodipodi:cx="2088.9954"
+ sodipodi:cy="638.83099"
+ sodipodi:rx="10.985409"
+ sodipodi:ry="9.5964489"
+ d="m 2099.9808,638.83099 c 0,5.29998 -4.9184,9.59645 -10.9854,9.59645 -6.0671,0 -10.9854,-4.29647
-10.9854,-9.59645 0,-5.29997 4.9183,-9.59645 10.9854,-9.59645 6.067,0 10.9854,4.29648 10.9854,9.59645 z"
+ transform="matrix(0.63720887,0,0,0.72943648,-1322.1264,-458.98661)" />
+ </g>
+</svg>
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 498df15..f5d444d 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -37,6 +37,8 @@ const INACTIVE_GRID_OPACITY = 77;
const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.15;
const FOLDER_SUBICON_FRACTION = .4;
+const MAX_APPS_PAGES = 20;
+
const PAGE_SWITCH_TIME = 0.25;
// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
@@ -169,6 +171,99 @@ const PaginationScrollView = new Lang.Class({
}
});
+const PaginationIconIndicator = new Lang.Class({
+ Name: 'PaginationIconIndicator',
+ _init: function(parent, index) {
+
+ this.actor = new St.Button({ style_class: 'pages-icon-indicator',
+ button_mask: St.ButtonMask.ONE || St.ButtonMask.TWO,
+ toggle_mode: true,
+ can_focus: true });
+ this.actor.connect('clicked', Lang.bind(this, this._onClicked));
+ this.actor._delegate = this;
+ //Background image is 18x18 but it is a svg, so we have to put a size
+ this.actor.set_size(18, 18);
+ this._parent = parent;
+ this.actor._index = index;
+ },
+
+ _onClicked: function(actor, button) {
+ this._parent.goToPage(this.actor._index, true);
+ return false;
+ },
+
+ setChecked: function (checked) {
+ this.actor.set_checked(checked);
+ }
+});
+
+const PaginationIndicator = new Lang.Class({
+ Name:'PaginationIndicator',
+
+ _init: function(params) {
+ params['y_expand'] = true;
+ this.actor = new Shell.GenericContainer(params);
+ this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
+ this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
+ this.actor.connect('allocate', Lang.bind(this, this._allocate));
+ this.actor.connect('style-changed', Lang.bind(this, this._styleChanged));
+ this._spacing = 0;
+ },
+
+ _getPreferredHeight: function(actor, forWidth, alloc) {
+ let [minHeight, natHeight] = this.actor.get_children()[0].get_preferred_height(forWidth);
+ if (this._nPages) {
+ let natHeightPerChild = natHeight + this._spacing;
+ let totalUsedHeight = this._nPages * natHeightPerChild - this._spacing;
+ let minHeightPerChild = minHeight + this._spacing;
+ minHeight = this._nPages * minHeightPerChild - this._spacing;
+ natHeight = this._nPages * natHeightPerChild - this._spacing;
+ } else
+ minHeight = natHeight = 0;
+ alloc.min_size = 0;
+ alloc.natural_size = natHeight;
+ },
+
+ _getPreferredWidth: function(actor, forHeight, alloc) {
+ let [minWidth, natWidth] = this.actor.get_children()[0].get_preferred_width(forHeight);
+ let totalWidth = natWidth + this._spacing;
+ alloc.min_size = totalWidth;
+ alloc.natural_size = totalWidth;
+ },
+
+ _allocate: function(actor, box, flags) {
+ let children = this.actor.get_children();
+ for (let i in children)
+ this.actor.set_skip_paint(children[i], true);
+ if (children.length < 1)
+ return;
+ let availHeight = box.y2 - box.y1;
+ let availWidth = box.x2 - box.x1;
+ let [minHeight, natHeight] = children[0].get_preferred_height(availWidth);
+ let heightPerChild = natHeight + this._spacing;
+ let totalUsedHeight = this._nPages * heightPerChild - this._spacing;
+ let [minWidth, natWidth] = children[0].get_preferred_width(natHeight);
+ let widthPerChild = natWidth + this._spacing * 2;
+ let firstPosition = [this._spacing, availHeight / 2 - totalUsedHeight / 2];
+ for (let i = 0; i < this._nPages; i++) {
+ let childBox = new Clutter.ActorBox();
+ childBox.x1 = 0;
+ childBox.x2 = availWidth;
+ childBox.y1 = firstPosition[1] + i * heightPerChild;
+ childBox.y2 = childBox.y1 + heightPerChild;
+ if (childBox.y2 > availHeight)
+ break;
+ children[i].allocate(childBox, flags);
+ this.actor.set_skip_paint(children[i], false);
+ }
+ },
+
+ _styleChanged: function() {
+ this._spacing = this.actor.get_theme_node().get_length('spacing');
+ this.actor.queue_relayout();
+ }
+});
+
const AllView = new Lang.Class({
Name: 'AllView',
Extends: PaginatedAlphabeticalView,
@@ -176,10 +271,22 @@ const AllView = new Lang.Class({
_init: function() {
this.parent();
this._paginationView = new PaginationScrollView(this, {style_class: 'all-apps'});
+ this._paginationIndicator = new PaginationIndicator({ style_class: 'pages-indicator' });
let layout = new Clutter.BinLayout();
this.actor = new St.Widget({ layout_manager: layout,
x_expand:true, y_expand:true });
layout.add(this._paginationView, Clutter.ActorAlign.CENTER, Clutter.ActorAlign.CENTER);
+ if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
+ layout.add(this._paginationIndicator.actor, Clutter.ActorAlign.START, Clutter.ActorAlign.CENTER);
+ else
+ layout.add(this._paginationIndicator.actor, Clutter.ActorAlign.END, Clutter.ActorAlign.CENTER);
+ for (let i = 0; i < MAX_APPS_PAGES; i++) {
+ let indicatorIcon = new PaginationIconIndicator(this, i);
+ if (i == 0)
+ indicatorIcon.setChecked(true);
+ this._paginationIndicator.actor.add_actor(indicatorIcon.actor);
+ }
+
this._grid.connect('n-pages-changed', Lang.bind(this, this._updatedNPages));
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
@@ -218,10 +325,33 @@ const AllView = new Lang.Class({
_updatedNPages: function(iconGrid, nPages) {
// We don't need a relayout because we already done it at iconGrid
// when pages are calculated (and then the signal is emitted before that)");
+ this._paginationIndicator._nPages = nPages;
this.invalidatePagination = true;
},
- goToPage: function(pageNumber) {
+ goToPage: function(pageNumber, updateIndicators, action) {
+ this.viewGoToPage(pageNumber, action);
+ if (updateIndicators)
+ this.indicatorsGoToPage(pageNumber);
+ },
+
+ indicatorsGoToPage: function(pageNumber) {
+ // Since it can happens after a relayout, we have to ensure that all is unchecked
+ let indicators = this._paginationIndicator.actor.get_children();
+ if (this._grid.nPages() > 1) {
+ for (let index in indicators)
+ indicators[index].set_checked(false);
+ this._paginationIndicator.actor.get_child_at_index(this._currentPage).set_checked(true);
+ }
+ },
+
+ viewGoToPage: function(pageNumber, action) {
+ // Since we call this function also from shown signal of the overview, we can't assure the
pagination is already calculated
+ // so we first ask pagination if it has some page, if not, we return and that's it. (nevermind,
because when creating for first time
+ // pagination, that is when it can happens, paginations starts at page 0 already, so no problem here)
+ if (!this._grid.nPages())
+ return;
+
if (pageNumber < this._grid.nPages() && pageNumber >= 0) {
this._currentPage = pageNumber;
let params = { value: this._grid.getPagePosition(this._currentPage)[1],
@@ -237,12 +367,12 @@ const AllView = new Lang.Class({
if (direction == Clutter.ScrollDirection.UP)
if (this._currentPage > 0) {
nextPage = this._currentPage - 1;
- this.goToPage(nextPage);
+ this.goToPage(nextPage, true);
}
if (direction == Clutter.ScrollDirection.DOWN)
if(this._currentPage < (this._grid.nPages() - 1)) {
nextPage = this._currentPage + 1;
- this.goToPage(nextPage);
+ this.goToPage(nextPage, true);
}
},
@@ -304,8 +434,14 @@ const AllView = new Lang.Class({
updateAdjustment: function(availHeight) {
this._verticalAdjustment.page_size = availHeight;
this._verticalAdjustment.upper = this._stack.height;
- if (this.invalidatePagination)
- this.goToPage(0);
+ if (this.invalidatePagination) {
+ // We can modify the adjustment, so we do that to show the first page, but we can't modify the
indicators,
+ // so we modify it before redraw (we won't see too much flickering at all)
+ if (this._grid.nPages() > 1) {
+ this.goToPage(0, false);
+ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { this.goToPage(0,
true); }));
+ }
+ }
this.invalidatePagination = false;
},
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]