[gnome-shell] appDisplay: Add page indicators



commit dcea8bed6d66c38ac1a98872b4c3791065ae011a
Author: Carlos Soriano <carlos soriano89 gmail com>
Date:   Mon Aug 12 19:09:43 2013 +0200

    appDisplay: Add page indicators
    
    Add indicators to the pagination in AllView, which displays
    how many pages of apps we have and allows the user to
    navigate through them.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706081

 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                    |  106 +++++++++++++++++++++++++++++++-
 5 files changed, 257 insertions(+), 1 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 6ad4dca..b2e9817 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 24f1c75..9ed2867 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -941,6 +941,22 @@ StScrollBar StButton#vhandle:active {
     padding: 0px 88px 10px 88px;
 }
 
+.page-indicator {
+    width: 18px;
+    height: 18px;
+    background-image: url(page-indicator-inactive.svg);
+}
+
+.page-indicator:hover,
+.page-indicator:checked{
+    background-image: url(page-indicator-active.svg);
+}
+
+.page-indicators {
+    spacing: 30px;
+    padding: 0px 30px;
+}
+
 .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 0dd3885..c9d2ff8 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -37,6 +37,12 @@ const INACTIVE_GRID_OPACITY = 77;
 const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.15;
 const FOLDER_SUBICON_FRACTION = .4;
 
+const INDICATORS_ANIMATION_TIME = 0.5;
+// 100% means indicators wait for be animated until the previous one
+// is animated completely. 0% means all animators are animated
+// at once without delay
+const INDICATORS_ANIMATION_DELAY_PERCENTAGE = 50;
+
 const PAGE_SWITCH_TIME = 0.3;
 
 // Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
@@ -169,6 +175,90 @@ const PagesBin = new Lang.Class({
     }
 });
 
+const PageIndicators = new Lang.Class({
+    Name:'PageIndicators',
+
+    _init: function() {
+        this.actor = new St.BoxLayout({ style_class: 'page-indicators',
+                                        vertical: true,
+                                        x_expand: true, y_expand: true,
+                                        x_align: Clutter.ActorAlign.END,
+                                        y_align: Clutter.ActorAlign.CENTER });
+        this._nPages = 0;
+        this._currentPage = undefined;
+
+        this.actor.connect('notify::mapped',
+                           Lang.bind(this, this._animateIndicators));
+    },
+
+    setNPages: function(nPages) {
+        if (this._nPages == nPages)
+            return;
+
+        let diff = nPages - this._nPages;
+        if (diff > 0) {
+            for (let i = 0; i < diff; i++) {
+                let pageIndex = this._nPages + i;
+                let indicator = new St.Button({ style_class: 'page-indicator',
+                                                button_mask: St.ButtonMask.ONE |
+                                                             St.ButtonMask.TWO |
+                                                             St.ButtonMask.THREE,
+                                                toggle_mode: true,
+                                                checked: pageIndex == this._currentPage });
+                indicator.connect('clicked', Lang.bind(this,
+                    function() {
+                        this.emit('page-activated', pageIndex);
+                    }));
+                this.actor.add_actor(indicator);
+            }
+        } else {
+            let children = this.actor.get_children().splice(diff);
+            for (let i = 0; i < children.length; i++)
+                children[i].destroy();
+        }
+        this._nPages = nPages;
+    },
+
+    setCurrentPage: function(currentPage) {
+        this._currentPage = currentPage;
+
+        let children = this.actor.get_children();
+        for (let i = 0; i < children.length; i++)
+            children[i].set_checked(i == this._currentPage);
+    },
+
+    _animateIndicators: function() {
+        if (!this.actor.mapped)
+            return;
+
+        let children = this.actor.get_children();
+        if (children.length == 0)
+            return;
+
+        let timePerChild = INDICATORS_ANIMATION_TIME / this._nPages;
+        let delay = INDICATORS_ANIMATION_DELAY_PERCENTAGE / 100 * timePerChild;
+
+        let [stageX, ] = children[0].get_transformed_position();
+        let offset;
+        let monitor = Main.layoutManager.primaryMonitor;
+        if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
+            offset = monitor.x - stageX - children[0].width;
+        else
+            offset = monitor.x + monitor.width - stageX;
+
+        for (let i = 0; i < this._nPages; i++) {
+            children[i].translation_x = offset;
+            Tweener.addTween(children[i],
+                             { translation_x: 0,
+                               time: timePerChild,
+                               delay: delay * i,
+                               transition: 'easeOutQuad'
+                             });
+        }
+    }
+});
+Signals.addSignalMethods(PageIndicators.prototype);
+
 const AllView = new Lang.Class({
     Name: 'AllView',
     Extends: BaseAppView,
@@ -186,6 +276,13 @@ const AllView = new Lang.Class({
                                      x_expand:true, y_expand:true });
         this.actor.add_actor(this._pagesBin);
 
+        this._pageIndicators = new PageIndicators();
+        this._pageIndicators.connect('page-activated', Lang.bind(this,
+            function(indicators, pageIndex) {
+                this.goToPage(pageIndex);
+            }));
+        this.actor.add_actor(this._pageIndicators.actor);
+
         this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
         let box = new St.BoxLayout({ vertical: true });
         this._verticalAdjustment = new St.Adjustment();
@@ -223,6 +320,7 @@ const AllView = new Lang.Class({
                          { value: this._grid.getPageY(this._currentPage),
                            time: PAGE_SWITCH_TIME,
                            transition: 'easeOutQuad' });
+        this._pageIndicators.setCurrentPage(pageNumber);
     },
 
     _onScroll: function(actor, event) {
@@ -331,8 +429,14 @@ const AllView = new Lang.Class({
         this._grid.computePages(availWidth, availHeight);
         // Make sure the view doesn't have a bad adjustment value after screen size changes
         // and therefore the pages computation.
-        if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != 
this._grid.nPages())
+        if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != 
this._grid.nPages()) {
             this._verticalAdjustment.value = 0;
+            Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
+                function() {
+                    this._pageIndicators.setNPages(this._grid.nPages());
+                    this._pageIndicators.setCurrentPage(0);
+                }));
+        }
 
         this._availWidth = availWidth;
         this._availHeight = availHeight;


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