[gnome-shell/wip/re-search-v2: 8/33] 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: 8/33] searchDisplay: Add ListSearchResult and ListSearchResults
- Date: Mon, 3 Dec 2012 09:56:17 +0000 (UTC)
commit 58ddbead6b94758843a83e6156dec66afb4a9a68
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/search.js | 3 -
js/ui/searchDisplay.js | 229 ++++++++++++++++++++++++++++++++++----------
js/ui/viewSelector.js | 2 +-
js/ui/wanda.js | 3 +-
5 files changed, 227 insertions(+), 80 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index c59f51a..4df8530 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 {
background-color: white;
border-radius: 5px;
@@ -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/search.js b/js/ui/search.js
index d3fa3b1..a963143 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -151,9 +151,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 cab9ca3..325b574 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_SEARCH_RESULTS_ROWS = 3;
+const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const SearchResult = new Lang.Class({
Name: 'SearchResult',
@@ -22,33 +23,103 @@ const SearchResult = new Lang.Class({
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
- 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);
+ 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';
this._dragActorSource = null;
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);
- this._dragActorSource = icon.icon;
content.label_actor = icon.label;
+ dragSource = icon.icon;
} else {
if (content._delegate && content._delegate.getDragActorSource)
- this._dragActorSource = 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',
@@ -63,29 +134,16 @@ const SearchResult = new Lang.Class({
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
- },
-
- 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);
- Main.overview.toggle();
- },
+ if (!dragSource)
+ // not exactly right, but alignment problems are hard to notice
+ dragSource = content;
- _onResultClicked: function(actor) {
- this.activate();
+ this._dragActorSource = dragSource;
},
getDragActorSource: function() {
- if (this._dragActorSource)
- return this._dragActorSource;
- // not exactly right, but alignment problems are hard to notice
- return this._content;
+ return this._dragActorSource;
},
getDragActor: function(stageX, stageY) {
@@ -100,6 +158,72 @@ 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: 'list-search-results',
+ vertical: true });
+ this.actor.connect('notify::width', Lang.bind(this, function() {
+ 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;
+ },
+
+ getResultsForDisplay: function() {
+ let alreadyVisible = this._pendingClear ? 0 : this.getVisibleResultCount();
+ let canDisplay = MAX_SEARCH_RESULTS_ROWS - alreadyVisible;
+
+ let numResults = Math.min(this._notDisplayedResult.length, canDisplay);
+
+ return this._notDisplayedResult.splice(0, numResults);
+ },
+
+ getVisibleResultCount: function() {
+ return this.actor.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.actor.add_actor(display.actor);
+ }
+ },
+
+ clear: function () {
+ this.actor.destroy_all_children();
+ this._pendingClear = false;
+ },
+
+ getFirstResult: function() {
+ if (this.getVisibleResultCount() > 0)
+ return this.actor.get_child_at_index(0)._delegate;
+ else
+ return null;
+ }
+});
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
@@ -108,7 +232,7 @@ 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 });
@@ -156,7 +280,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);
}
},
@@ -174,8 +298,8 @@ const GridSearchResults = new Lang.Class({
}
});
-const SearchResults = new Lang.Class({
- Name: 'SearchResults',
+const SearchDisplay = new Lang.Class({
+ Name: 'SearchDisplay',
_init: function(searchSystem) {
this._searchSystem = searchSystem;
@@ -225,10 +349,16 @@ 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 providerBoxContent = new St.BoxLayout({ style_class: 'search-section-content' });
let providerIcon = null;
+ let resultDisplay = null;
if (provider.appInfo) {
+ let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
+ providerBox.add(separator.actor);
+
providerIcon = new ProviderIcon(provider);
providerIcon.connect('clicked', Lang.bind(this,
function() {
@@ -236,18 +366,20 @@ const SearchResults = new Lang.Class({
Main.overview.toggle();
}));
- providerBox.add(providerIcon, { x_fill: false,
- y_fill: false,
- x_align: St.Align.START,
- y_align: St.Align.START });
+ providerBoxContent.add(providerIcon, { x_fill: false,
+ y_fill: false,
+ x_align: St.Align.START,
+ y_align: St.Align.START });
+
+ resultDisplay = new ListSearchResults(provider);
+ } else {
+ resultDisplay = new GridSearchResults(provider);
}
- let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
- x_fill: true,
+ let resultDisplayBin = new St.Bin({ x_fill: true,
y_fill: true });
- providerBox.add(resultDisplayBin, { expand: true });
-
- let resultDisplay = new GridSearchResults(provider);
+ providerBoxContent.add(resultDisplayBin, { expand: true });
+ providerBox.add(providerBoxContent);
resultDisplayBin.set_child(resultDisplay.actor);
this._providerMeta.push({ provider: provider,
@@ -407,11 +539,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/viewSelector.js b/js/ui/viewSelector.js
index 060c885..81c9275 100644
--- a/js/ui/viewSelector.js
+++ b/js/ui/viewSelector.js
@@ -90,7 +90,7 @@ const ViewSelector = new Lang.Class({
this._appsPage = this._addPage(this._appDisplay.actor, null,
_("Applications"), 'view-grid-symbolic');
- this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
+ this._searchResults = new SearchDisplay.SearchDisplay(this._searchSystem);
this._searchPage = this._addPage(this._searchResults.actor, this._entry,
_("Search"), 'edit-find-symbolic');
diff --git a/js/ui/wanda.js b/js/ui/wanda.js
index 303d577..a0adf9f 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]