[gnome-shell] app-display: Implement filtering applications by category



commit 4fd24da4e4d61eabda496a9db4e3b5bfb7d8d600
Author: Maxim Ermilov <zaspire rambler ru>
Date:   Sat Dec 18 22:18:10 2010 +0300

    app-display: Implement filtering applications by category
    
    Add a list of filters to the application view of the view selector, as in the latest mockups
    
    https://bugzilla.gnome.org/show_bug.cgi?id=631537

 data/Makefile.am               |    1 +
 data/gs-applications.menu      |   70 ++++++++++++++++----
 data/theme/filter-selected.svg |   81 +++++++++++++++++++++++
 data/theme/gnome-shell.css     |   22 ++++---
 js/ui/appDisplay.js            |  142 +++++++++++++++++++++++-----------------
 5 files changed, 232 insertions(+), 84 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 8c04198..d8cb906 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -27,6 +27,7 @@ dist_theme_DATA =				\
 	theme/corner-ripple.png			\
 	theme/dash-placeholder.svg		\
 	theme/dialog-error.svg			\
+	theme/filter-selected.svg		\
 	theme/gnome-shell.css			\
 	theme/mosaic-view-active.svg		\
 	theme/mosaic-view.svg			\
diff --git a/data/gs-applications.menu b/data/gs-applications.menu
index 1d0bfdc..cb4db03 100644
--- a/data/gs-applications.menu
+++ b/data/gs-applications.menu
@@ -1,12 +1,30 @@
 <Menu>
-    <DefaultLayout>
-        <Menuname>Apps</Menuname>
-        <Menuname>Games</Menuname>
-        <Menuname>Tools</Menuname>
-    </DefaultLayout>
+	<DefaultLayout>
+		<Menuname>Accessories</Menuname>
+		<Menuname>Games</Menuname>
+		<Menuname>Graphics</Menuname>
+		<Menuname>Internet</Menuname>
+		<Menuname>Multimedia</Menuname>
+		<Menuname>Office</Menuname>
+		<Menuname>Other</Menuname>
+	</DefaultLayout>
+
 	<Name>Applications</Name>
 	<AppDir>/usr/local/share/applications</AppDir>
 	<DefaultAppDirs/>
+
+	<Menu>
+		<Name>Accessories</Name>
+		<Include>
+			<And>
+				<Category>Utility</Category>
+				<Not>
+					<Category>System</Category>
+				</Not>
+			</And>
+		</Include>
+	</Menu>
+
 	<Menu>
 		<Name>Games</Name>
 		<Include>
@@ -15,21 +33,47 @@
 			</And>
 		</Include>
 	</Menu>
+
 	<Menu>
-		<Name>Tools</Name>
+		<Name>Graphics</Name>
 		<Include>
-			<Category>Development</Category>
 			<And>
-				<Category>System</Category>
-				<Not>
-					<Category>Settings</Category>
-				</Not>
+				<Category>Graphics</Category>
+			</And>
+		</Include>
+	</Menu>
+
+	<Menu>
+		<Name>Internet</Name>
+		<Include>
+			<And>
+				<Category>Network</Category>
+				<Not><Category>Settings</Category></Not>
+			</And>
+		</Include>
+	</Menu>
+
+	<Menu>
+		<Name>Multimedia</Name>
+		<Include>
+			<And>
+				<Category>AudioVideo</Category>
+				<Not><Category>Settings</Category></Not>
+			</And>
+		</Include>
+	</Menu>
+
+	<Menu>
+		<Name>Office</Name>
+		<Include>
+			<And>
+				<Category>Office</Category>
 			</And>
-			<Category>Utility</Category>
 		</Include>
 	</Menu>
+
 	<Menu>
-		<Name>Apps</Name>
+		<Name>Other</Name>
 		<OnlyUnallocated/>
 		<Include>
 			<And>
diff --git a/data/theme/filter-selected.svg b/data/theme/filter-selected.svg
new file mode 100644
index 0000000..62c8e5b
--- /dev/null
+++ b/data/theme/filter-selected.svg
@@ -0,0 +1,81 @@
+<?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="10"
+   height="20"
+   id="svg10003"
+   version="1.1"
+   inkscape:version="0.47 r22583"
+   sodipodi:docname="filter-selected.svg">
+  <defs
+     id="defs10005">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 32 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="64 : 32 : 1"
+       inkscape:persp3d-origin="32 : 21.333333 : 1"
+       id="perspective10011" />
+    <inkscape:perspective
+       id="perspective9998"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.5"
+     inkscape:cx="32"
+     inkscape:cy="10.181818"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1680"
+     inkscape:window-height="994"
+     inkscape:window-x="0"
+     inkscape:window-y="26"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata10008">
+    <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,-44)">
+    <path
+       inkscape:export-ydpi="90"
+       inkscape:export-xdpi="90"
+       inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png"
+       sodipodi:nodetypes="cccc"
+       inkscape:connector-curvature="0"
+       id="rect34320"
+       d="m -0.18726572,54.181804 10.55634072,10.55636 10e-6,-21.11269 z"
+       style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+  </g>
+</svg>
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index e6b483b..98899a2 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -470,26 +470,28 @@ StTooltip StLabel {
 
 /* Apps */
 
-.overview-pane {
-    width: 440px;
-}
-
 .icon-grid {
     spacing: 36px;
     -shell-grid-item-size: 70px;
 }
 
 .all-app {
-    padding: 16px 250px 10px 16px;
+    padding: 16px 25px 16px 16px;
+    spacing: 20px;
 }
 
-.app-section-divider-container {
-    padding-top: 36px;
-    padding-bottom: 36px;
+.app-filter {
+    font-size: 14px;
+    font-weight: bold;
+    height: 40px;
+    color: #aaa;
+    width: 200px;
 }
 
-.app-section-divider {
-    height: 2px;
+.app-filter:selected {
+    color: #ffffff;
+    background-image: url("filter-selected.svg");
+    background-position: 190px 10px;
 }
 
 #dash > .app-well-app {
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 0cdb5dd..eaeeb15 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -29,10 +29,20 @@ function AlphabeticalView() {
 
 AlphabeticalView.prototype = {
     _init: function() {
-        this.actor = new St.BoxLayout({ vertical: true });
         this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
         this._appSystem = Shell.AppSystem.get_default();
-        this.actor.add(this._grid.actor, { y_align: St.Align.START, expand: true });
+
+        this._filterApp = null;
+
+        let box = new St.BoxLayout({ vertical: true });
+        box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
+
+        this.actor = new St.ScrollView({ x_fill: true,
+                                         y_fill: false,
+                                         y_align: St.Align.START,
+                                         vshadows: true });
+        this.actor.add_actor(box);
+        this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
     },
 
     _removeAll: function() {
@@ -40,20 +50,24 @@ AlphabeticalView.prototype = {
         this._apps = [];
     },
 
-    _addApp: function(app) {
-        let appIcon = new AppWellIcon(this._appSystem.get_app(app.get_id()));
-        appIcon.connect('launching', Lang.bind(this, function() {
-            this.emit('launching');
-        }));
-        appIcon._draggable.connect('drag-begin', Lang.bind(this, function() {
-            this.emit('drag-begin');
-        }));
+    _addApp: function(appInfo) {
+        let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
 
         this._grid.addItem(appIcon.actor);
 
+        appIcon._appInfo = appInfo;
+        if (this._filterApp && !this._filterApp(appInfo))
+            appIcon.actor.hide();
+
         this._apps.push(appIcon);
     },
 
+    setFilter: function(filter) {
+        this._filterApp = filter;
+        for (let i = 0; i < this._apps.length; i++)
+            this._apps[i].actor.visible = filter(this._apps[i]._appInfo);
+    },
+
     refresh: function(apps) {
         let ids = [];
         for (let i in apps)
@@ -70,8 +84,6 @@ AlphabeticalView.prototype = {
     }
 };
 
-Signals.addSignalMethods(AlphabeticalView.prototype);
-
 function ViewByCategories() {
     this._init();
 }
@@ -79,59 +91,78 @@ function ViewByCategories() {
 ViewByCategories.prototype = {
     _init: function() {
         this._appSystem = Shell.AppSystem.get_default();
-        this.actor = new St.BoxLayout({ vertical: true });
+        this.actor = new St.BoxLayout({ style_class: 'all-app' });
         this.actor._delegate = this;
+
+        this._view = new AlphabeticalView();
+
+        this._filters = new St.BoxLayout({ vertical: true });
+        this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
+        this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
+
         this._sections = [];
     },
 
-    _updateSections: function(apps) {
-        this._removeAll();
+    _selectCategory: function(num) {
+        if (num != -1)
+            this._allFilter.remove_style_pseudo_class('selected');
+        else
+            this._allFilter.add_style_pseudo_class('selected');
 
-        let sections = this._appSystem.get_sections();
-        if (!sections)
-            return;
-        for (let i = 0; i < sections.length; i++) {
-            if (i) {
-                let actor = new St.Bin({ style_class: 'app-section-divider' });
-                let divider = new St.Bin({ style_class: 'app-section-divider-container',
-                                           child: actor,
-                                           x_fill: true });
-
-                this.actor.add(divider, { y_fill: false, expand: true });
-            }
-            let _apps = apps.filter(function(app) {
-                return app.get_section() == sections[i];
-            });
-            this._sections[i] = { view: new AlphabeticalView(),
-                                  apps: _apps,
-                                  name: sections[i] };
-            this._sections[i].view.connect('launching', Lang.bind(this, function() {
-                this.emit('launching');
-            }));
-            this._sections[i].view.connect('drag-begin', Lang.bind(this, function() {
-                this.emit('drag-begin');
-            }));
-            this.actor.add(this._sections[i].view.actor, { y_align: St.Align.START, expand: true });
+        this._view.setFilter(Lang.bind(this, function(app) {
+            if (num == -1)
+                return true;
+            return this._sections[num].name == app.get_section();
+        }));
+
+        for (let i = 0; i < this._sections.length; i++) {
+            if (i == num)
+                this._sections[i].filterActor.add_style_pseudo_class('selected');
+            else
+                this._sections[i].filterActor.remove_style_pseudo_class('selected');
         }
     },
 
-    _removeAll: function() {
-        this.actor.destroy_children();
-        this._sections.forEach(function (section) { section.view.disconnectAll(); });
+    _addFilter: function(name, num) {
+        let button = new St.Button({ label: name,
+                                     style_class: 'app-filter',
+                                     x_align: St.Align.START });
+        this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
+        button.connect('clicked', Lang.bind(this, function() {
+            this._selectCategory(num);
+        }));
+
+        if (num != -1)
+            this._sections[num] = { filterActor: button,
+                                    name: name };
+        else
+            this._allFilter = button;
+    },
 
+    _removeAll: function() {
         this._sections = [];
+        this._filters.destroy_children();
     },
 
     refresh: function(apps) {
-        this._updateSections(apps);
-        for (let i = 0; i < this._sections.length; i++) {
-            this._sections[i].view.refresh(this._sections[i].apps);
-        }
+        this._removeAll();
+
+        let sections = this._appSystem.get_sections();
+        this._apps = apps;
+        this._view.refresh(apps);
+
+        this._addFilter(_("All"), -1);
+
+        if (!sections)
+            return;
+
+        for (let i = 0; i < sections.length; i++)
+            this._addFilter(sections[i], i);
+
+        this._selectCategory(-1);
     }
 };
 
-Signals.addSignalMethods(ViewByCategories.prototype);
-
 /* This class represents a display containing a collection of application items.
  * The applications are sorted based on their name.
  */
@@ -146,17 +177,8 @@ AllAppDisplay.prototype = {
             Main.queueDeferredWork(this._workId);
         }));
 
-        this._scrollView = new St.ScrollView({ x_fill: true,
-                                               y_fill: false,
-                                               vshadows: true });
-        this.actor = new St.Bin({ style_class: 'all-app',
-                                  y_align: St.Align.START,
-                                  child: this._scrollView });
-
         this._appView = new ViewByCategories();
-        this._scrollView.add_actor(this._appView.actor);
-
-        this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+        this.actor = new St.Bin({ child: this._appView.actor, x_fill: true, y_fill: true });
 
         this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
     },
@@ -169,8 +191,6 @@ AllAppDisplay.prototype = {
         this._appView.refresh(apps);
     }
 };
-Signals.addSignalMethods(AllAppDisplay.prototype);
-
 
 function BaseAppSearchProvider() {
     this._init();



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