diff --git a/data/Makefile.am b/data/Makefile.am index 8c0419811..d8cb9064c 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 1d0bfdc03..cb4db03a8 100644 --- a/data/gs-applications.menu +++ b/data/gs-applications.menu @@ -1,12 +1,30 @@ - - Apps - Games - Tools - + + Accessories + Games + Graphics + Internet + Multimedia + Office + Other + + Applications /usr/local/share/applications + + + Accessories + + + Utility + + System + + + + + Games @@ -15,21 +33,47 @@ + - Tools + Graphics - Development - System - - Settings - + Graphics - Utility + - Apps + Internet + + + Network + Settings + + + + + + Multimedia + + + AudioVideo + Settings + + + + + + Office + + + Office + + + + + + Other diff --git a/data/theme/filter-selected.svg b/data/theme/filter-selected.svg new file mode 100644 index 000000000..62c8e5b7f --- /dev/null +++ b/data/theme/filter-selected.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index e6b483b8e..98899a2f2 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 0cdb5dda6..eaeeb1590 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._view.setFilter(Lang.bind(this, function(app) { + if (num == -1) + return true; + return this._sections[num].name == app.get_section(); + })); - 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 }); + 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'); } }, + _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.actor.destroy_children(); - this._sections.forEach(function (section) { section.view.disconnectAll(); }); - 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();