[gnome-shell/wip/re-search-v2: 4/26] searchDisplay: Add ListSearchResult and ListSearchResults
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/re-search-v2: 4/26] searchDisplay: Add ListSearchResult and ListSearchResults
- Date: Mon, 10 Dec 2012 21:02:18 +0000 (UTC)
commit 1bb09fd0f13a2722b26ea30fa84a43502836f3c7
Author: Tanner Doshier <doshitan gmail com>
Date: Wed Aug 1 20:48:10 2012 -0500
searchDisplay: Add ListSearchResult and ListSearchResults
These are for all search results except apps (and Wanda).
We also simplify a bit the packing of search results, which removes some
ugly code in navigateFocus() where we needed to call
st_widget_navigate_focus() twice, since the grid icon was composed by
two nested boxes, both focusable.
https://bugzilla.gnome.org/show_bug.cgi?id=681797
data/theme/gnome-shell.css | 70 +++++++++-----
js/ui/appDisplay.js | 6 -
js/ui/search.js | 3 -
js/ui/searchDisplay.js | 236 +++++++++++++++++++++++++++++++------------
js/ui/wanda.js | 3 +-
5 files changed, 218 insertions(+), 100 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index fd3121e..19645d7 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -49,7 +49,7 @@ stage {
.switcher-list,
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
-.search-result-content > .overview-icon {
+.grid-search-result .overview-icon {
font-size: 9pt;
font-weight: bold;
}
@@ -760,7 +760,7 @@ StScrollBar StButton#vhandle:active {
#searchResultsContent {
padding-right: 20px;
- spacing: 36px;
+ spacing: 16px;
}
#searchResultsContent:rtl {
@@ -768,29 +768,32 @@ StScrollBar StButton#vhandle:active {
padding-left: 20px;
}
-.search-section-header {
- padding: 4px 12px;
- spacing: 4px;
- color: #6f6f6f;
- font-size: .8em;
+.search-section {
+ /* This should be equal to #searchResultsContent spacing */
+ spacing: 16px;
}
-.search-statustext {
- color: #efefef;
- font-size: 2em;
- font-weight: bold;
+.search-section-separator {
+ -gradient-height: 1px;
+ -gradient-start: rgba(255,255,255,0);
+ -gradient-end: rgba(255,255,255,0.5);
+ -margin-horizontal: 1.5em;
+ height: 1px;
}
-.search-section-results {
- padding: 6px;
+.search-section-content {
+ /* This is the space between the provider icon and the results container */
+ spacing: 32px;
}
-.search-section-list-results {
- spacing: 4px;
+.search-statustext {
+ color: #efefef;
+ font-size: 2em;
+ font-weight: bold;
}
-.results-container {
- spacing: 4px;
+.list-search-results {
+ spacing: 3px;
}
/* Text labels are an odd number of pixels tall. The uneven top and bottom
@@ -819,7 +822,7 @@ StScrollBar StButton#vhandle:active {
-x-offset: 8px;
}
-/* Application Launchers and Grid */
+/* Application Launchers, Grid and List results */
.icon-grid {
spacing: 36px;
@@ -871,6 +874,23 @@ StScrollBar StButton#vhandle:active {
padding: 4px 8px;
}
+.list-search-result-content {
+ spacing: 12px;
+ padding: 12px;
+}
+
+.list-search-result-title {
+ font-weight: bold;
+ font-size: 14pt;
+ color: white;
+}
+
+.list-search-result-description {
+ font-weight: bold;
+ font-size: 12pt;
+ color: #eeeeec;
+}
+
.search-provider-icon-more {
width: 16px;
height: 16px;
@@ -880,7 +900,8 @@ StScrollBar StButton#vhandle:active {
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
.search-provider-icon,
-.search-result-content > .overview-icon {
+.list-search-result,
+.grid-search-result .overview-icon {
border-radius: 4px;
padding: 3px;
border: 1px rgba(0,0,0,0);
@@ -897,7 +918,8 @@ StScrollBar StButton#vhandle:active {
.app-well-app:hover > .overview-icon,
.show-apps:hover > .overview-icon,
.search-provider-icon:hover,
-.search-result-content:hover > .overview-icon {
+.list-search-result:hover,
+.grid-search-result:hover .overview-icon {
background-color: rgba(255,255,255,0.1);
text-shadow: black 0px 2px 2px;
transition-duration: 100;
@@ -932,12 +954,14 @@ StScrollBar StButton#vhandle:active {
}
.app-well-app:focus > .overview-icon,
-.search-result-content:focus > .overview-icon,
+.grid-search-result:focus .overview-icon,
.show-apps:focus > .overview-icon,
.search-provider-icon:focus,
+.list-search-result:focus,
.app-well-app:selected > .overview-icon,
-.search-result-content:selected > .overview-icon,
-.search-provider-icon:selected {
+.grid-search-result:selected .overview-icon,
+.search-provider-icon:selected,
+.list-search-result:selected {
background-color: rgba(255,255,255,0.33);
}
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 754864d..ac2860a 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -403,12 +403,6 @@ const SettingsSearchProvider = new Lang.Class({
pref.activate();
},
- createResultActor: function (resultMeta, terms) {
- let app = resultMeta['id'];
- let icon = new AppWellIcon(app);
- return icon.actor;
- },
-
launchSearch: function(terms) {
// FIXME: this should be a remote search provider
this.appInfo.launch([], global.create_app_launch_context());
diff --git a/js/ui/search.js b/js/ui/search.js
index 6bbbdab..827e34d 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -154,9 +154,6 @@ const SearchProvider = new Lang.Class({
* Search providers may optionally override this to render a
* particular serch result in a custom fashion. The default
* implementation will show the icon next to the name.
- *
- * The actor should be an instance of St.Widget, with the style class
- * 'search-result-content'.
*/
createResultActor: function(resultMeta, terms) {
return null;
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
index 6c0ecc1..4db34c5 100644
--- a/js/ui/searchDisplay.js
+++ b/js/ui/searchDisplay.js
@@ -11,10 +11,11 @@ const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
+const Separator = imports.ui.separator;
const Search = imports.ui.search;
-const MAX_SEARCH_RESULTS_ROWS = 1;
-
+const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
+const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const SearchResult = new Lang.Class({
Name: 'SearchResult',
@@ -23,21 +24,91 @@ const SearchResult = new Lang.Class({
this.provider = provider;
this.metaInfo = metaInfo;
this.terms = terms;
- this.actor = new St.Button({ style_class: 'search-result',
- reactive: true,
+
+ this.actor = new St.Button({ reactive: true,
+ can_focus: true,
+ track_hover: true,
x_align: St.Align.START,
y_fill: true });
+
this.actor._delegate = this;
+ this.actor.connect('clicked', Lang.bind(this, this.activate));
+ },
+
+ activate: function() {
+ this.provider.activateResult(this.metaInfo.id, this.terms);
+ Main.overview.toggle();
+ },
+
+ setSelected: function(selected) {
+ if (selected)
+ this.actor.add_style_pseudo_class('selected');
+ else
+ this.actor.remove_style_pseudo_class('selected');
+ }
+});
+
+const ListSearchResult = new Lang.Class({
+ Name: 'ListSearchResult',
+ Extends: SearchResult,
+
+ ICON_SIZE: 64,
+
+ _init: function(provider, metaInfo, terms) {
+ this.parent(provider, metaInfo, terms);
+
+ this.actor.style_class = 'list-search-result';
+ this.actor.x_fill = true;
+
+ let content = new St.BoxLayout({ style_class: 'list-search-result-content',
+ vertical: false });
+ this.actor.set_child(content);
+
+ // An icon for, or thumbnail of, content
+ let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
+ if (icon) {
+ content.add(icon);
+ }
+
+ let details = new St.BoxLayout({ vertical: true });
+ content.add(details, { x_fill: true,
+ y_fill: false,
+ x_align: St.Align.START,
+ y_align: St.Align.MIDDLE });
+
+ let title = new St.Label({ style_class: 'list-search-result-title',
+ text: this.metaInfo['name'] })
+ details.add(title, { x_fill: false,
+ y_fill: false,
+ x_align: St.Align.START,
+ y_align: St.Align.START });
+
+ // TODO: should highlight terms in the description here
+ if (this.metaInfo['description']) {
+ let description = new St.Label({ style_class: 'list-search-result-description',
+ text: '"' + this.metaInfo['description'] + '"' });
+ details.add(description, { x_fill: false,
+ y_fill: false,
+ x_align: St.Align.START,
+ y_align: St.Align.END });
+ }
+ }
+});
+
+const GridSearchResult = new Lang.Class({
+ Name: 'GridSearchResult',
+ Extends: SearchResult,
+
+ _init: function(provider, metaInfo, terms) {
+ this.parent(provider, metaInfo, terms);
+
+ this.actor.style_class = 'grid-search-result';
let content = provider.createResultActor(metaInfo, terms);
let dragSource = null;
if (content == null) {
- content = new St.Bin({ style_class: 'search-result-content',
- reactive: true,
- can_focus: true,
- track_hover: true,
- accessible_role: Atk.Role.PUSH_BUTTON });
+ content = new St.Bin();
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
content.set_child(icon.actor);
@@ -47,10 +118,8 @@ const SearchResult = new Lang.Class({
if (content._delegate && content._delegate.getDragActorSource)
dragSource = content._delegate.getDragActorSource();
}
- this._content = content;
- this.actor.set_child(content);
- this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
+ this.actor.set_child(content);
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
@@ -72,22 +141,6 @@ const SearchResult = new Lang.Class({
this._dragActorSource = dragSource;
},
- setSelected: function(selected) {
- if (selected)
- this._content.add_style_pseudo_class('selected');
- else
- this._content.remove_style_pseudo_class('selected');
- },
-
- activate: function() {
- this.provider.activateResult(this.metaInfo.id, this.terms);
- Main.overview.toggle();
- },
-
- _onResultClicked: function(actor) {
- this.activate();
- },
-
getDragActorSource: function() {
return this._dragActorSource;
},
@@ -104,6 +157,77 @@ const SearchResult = new Lang.Class({
}
});
+const ListSearchResults = new Lang.Class({
+ Name: 'ListSearchResults',
+ Extends: Search.SearchResultDisplay,
+
+ _init: function(provider) {
+ this.parent(provider);
+
+ this.actor = new St.BoxLayout({ style_class: 'search-section-content' });
+ this.providerIcon = new ProviderIcon(provider);
+ this.providerIcon.connect('clicked', Lang.bind(this,
+ function() {
+ provider.launchSearch(this._terms);
+ Main.overview.toggle();
+ }));
+
+ this.actor.add(this.providerIcon, { x_fill: false,
+ y_fill: false,
+ x_align: St.Align.START,
+ y_align: St.Align.START });
+
+ this._content = new St.BoxLayout({ style_class: 'list-search-results',
+ vertical: true });
+ this.actor.add_actor(this._content);
+
+ this._notDisplayedResult = [];
+ this._terms = [];
+ this._pendingClear = false;
+ },
+
+ getResultsForDisplay: function() {
+ let alreadyVisible = this._pendingClear ? 0 : this.getVisibleResultCount();
+ let canDisplay = MAX_LIST_SEARCH_RESULTS_ROWS - alreadyVisible;
+
+ let newResults = this._notDisplayedResult.splice(0, canDisplay);
+ return newResults;
+ },
+
+ getVisibleResultCount: function() {
+ return this._content.get_n_children();
+ },
+
+ hasMoreResults: function() {
+ return this._notDisplayedResult.length > 0;
+ },
+
+ setResults: function(results, terms) {
+ // copy the lists
+ this._notDisplayedResult = results.slice(0);
+ this._terms = terms.slice(0);
+ this._pendingClear = true;
+ },
+
+ renderResults: function(metas) {
+ for (let i = 0; i < metas.length; i++) {
+ let display = new ListSearchResult(this.provider, metas[i], this._terms);
+ this._content.add_actor(display.actor);
+ }
+ },
+
+ clear: function () {
+ this._content.destroy_all_children();
+ this._pendingClear = false;
+ },
+
+ getFirstResult: function() {
+ if (this.getVisibleResultCount() > 0)
+ return this._content.get_child_at_index(0)._delegate;
+ else
+ return null;
+ }
+});
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
@@ -112,22 +236,12 @@ const GridSearchResults = new Lang.Class({
_init: function(provider, grid) {
this.parent(provider);
- this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
+ this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
- this.actor = new St.Bin({ x_align: St.Align.START });
+ this.actor = new St.Bin({ x_align: St.Align.MIDDLE });
this.actor.set_child(this._grid.actor);
- this._width = 0;
- this.actor.connect('notify::width', Lang.bind(this, function() {
- this._width = this.actor.width;
- Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
- let results = this.getResultsForDisplay();
- if (results.length == 0)
- return;
-
- provider.getResultMetas(results, Lang.bind(this, this.renderResults));
- }));
- }));
+
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
@@ -135,12 +249,11 @@ const GridSearchResults = new Lang.Class({
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
- let canDisplay = this._grid.childrenInRow(this._width) * this._grid.getRowLimit()
+ let canDisplay = this._grid.childrenInRow(this.actor.width) * this._grid.getRowLimit()
- alreadyVisible;
- let numResults = Math.min(this._notDisplayedResult.length, canDisplay);
-
- return this._notDisplayedResult.splice(0, numResults);
+ let newResults = this._notDisplayedResult.splice(0, canDisplay);
+ return newResults;
},
getVisibleResultCount: function() {
@@ -160,7 +273,7 @@ const GridSearchResults = new Lang.Class({
renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
- let display = new SearchResult(this.provider, metas[i], this._terms);
+ let display = new GridSearchResult(this.provider, metas[i], this._terms);
this._grid.addItem(display.actor);
}
},
@@ -229,29 +342,25 @@ const SearchResults = new Lang.Class({
},
createProviderMeta: function(provider) {
- let providerBox = new St.BoxLayout({ style_class: 'search-section' });
+ let providerBox = new St.BoxLayout({ style_class: 'search-section',
+ vertical: true });
let providerIcon = null;
+ let resultDisplay = null;
if (provider.appInfo) {
- providerIcon = new ProviderIcon(provider);
- providerIcon.connect('clicked', Lang.bind(this,
- function() {
- provider.launchSearch(this._searchSystem.getTerms());
- Main.overview.toggle();
- }));
-
- providerBox.add(providerIcon, { x_fill: false,
- y_fill: false,
- x_align: St.Align.START,
- y_align: St.Align.START });
+ resultDisplay = new ListSearchResults(provider);
+ providerIcon = resultDisplay.providerIcon;
+ } else {
+ resultDisplay = new GridSearchResults(provider);
}
- let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
+ let resultDisplayBin = new St.Bin({ child: resultDisplay.actor,
x_fill: true,
y_fill: true });
providerBox.add(resultDisplayBin, { expand: true });
- let resultDisplay = new GridSearchResults(provider);
- resultDisplayBin.set_child(resultDisplay.actor);
+
+ let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
+ providerBox.add(separator.actor);
this._providerMeta.push({ provider: provider,
actor: providerBox,
@@ -412,11 +521,6 @@ const SearchResults = new Lang.Class({
let from = this._defaultResult ? this._defaultResult.actor : null;
this.actor.navigate_focus(from, direction, false);
- if (this._defaultResult) {
- // The default result appears focused, so navigate directly to the
- // next result.
- this.actor.navigate_focus(global.stage.key_focus, direction, false);
- }
}
});
diff --git a/js/ui/wanda.js b/js/ui/wanda.js
index 846098b..692efd4 100644
--- a/js/ui/wanda.js
+++ b/js/ui/wanda.js
@@ -71,8 +71,7 @@ const WandaIconBin = new Lang.Class({
Name: 'WandaIconBin',
_init: function(fish, label, params) {
- this.actor = new St.Bin({ style_class: 'search-result-content',
- reactive: true,
+ this.actor = new St.Bin({ reactive: true,
track_hover: true });
this.icon = new WandaIcon(fish, label, params);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]