Compare commits
13 Commits
citadel
...
wip/raresv
Author | SHA1 | Date | |
---|---|---|---|
|
de814752d6 | ||
|
c36f006b88 | ||
|
bf884ae9ea | ||
|
7bbff9d0c0 | ||
|
04ad2b24d8 | ||
|
4ffbec5b75 | ||
|
d35f2d375b | ||
|
235d4b244d | ||
|
9a007058ae | ||
|
985e53a04e | ||
|
aed6d466cb | ||
|
c62e3614d5 | ||
|
8dae0b5767 |
@ -1180,14 +1180,19 @@ StScrollBar {
|
||||
|
||||
.list-search-result-content {
|
||||
spacing: 12px;
|
||||
padding: 12px; }
|
||||
padding: 2px; }
|
||||
|
||||
.list-search-result-title {
|
||||
font-size: 1.5em;
|
||||
color: #e2e2df; }
|
||||
|
||||
.list-search-result-provider {
|
||||
color: #e2e2df;
|
||||
margin-top: 0.24em; }
|
||||
|
||||
.list-search-result-description {
|
||||
color: #cacac4; }
|
||||
color: #cacac4;
|
||||
margin-left: 30px; }
|
||||
|
||||
.search-provider-icon {
|
||||
padding: 15px; }
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2bef9b25e23632fe66e12c5d96a9c487f172a6a0
|
||||
Subproject commit 664cd88ee6fce1c9699512c83e0b68e45052fc23
|
@ -1171,23 +1171,30 @@ StScrollBar {
|
||||
.list-search-results {
|
||||
spacing: 3px; }
|
||||
|
||||
.list-search-provider-details {
|
||||
spacing: 3px;
|
||||
width: 150px;
|
||||
margin-left: 30px; }
|
||||
|
||||
.search-section-separator {
|
||||
-gradient-height: 1px;
|
||||
-gradient-start: rgba(255, 255, 255, 0);
|
||||
-gradient-end: rgba(255, 255, 255, 0.1);
|
||||
-margin-horizontal: 1.5em;
|
||||
height: 1px; }
|
||||
height: 2px;
|
||||
background-color: rgba(255, 255, 255, 0.2); }
|
||||
|
||||
.list-search-result-content {
|
||||
spacing: 12px;
|
||||
padding: 12px; }
|
||||
padding: 2px; }
|
||||
|
||||
.list-search-result-title {
|
||||
font-size: 1.5em;
|
||||
color: #e2e2df; }
|
||||
|
||||
.list-search-result-provider {
|
||||
color: #e2e2df;
|
||||
margin-top: 0.24em;
|
||||
}
|
||||
|
||||
.list-search-result-description {
|
||||
color: #cacac4; }
|
||||
color: rgba(202, 202, 196, 0.5);
|
||||
margin-left: 30px; }
|
||||
|
||||
.search-provider-icon {
|
||||
padding: 15px; }
|
||||
|
@ -1131,7 +1131,7 @@ const AppSearchProvider = new Lang.Class({
|
||||
this.getInitialResultSet(terms, callback, cancellable);
|
||||
},
|
||||
|
||||
createResultObject: function (resultMeta) {
|
||||
createResultObject: function (resultMeta, searchResultsView) {
|
||||
let app = this._appSys.lookup_app(resultMeta['id']);
|
||||
return new AppIcon(app);
|
||||
}
|
||||
|
175
js/ui/search.js
175
js/ui/search.js
@ -22,7 +22,7 @@ const Util = imports.misc.util;
|
||||
|
||||
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
|
||||
|
||||
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
|
||||
const MAX_LIST_SEARCH_RESULTS_ROWS = 5;
|
||||
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
|
||||
|
||||
const MaxWidthBin = new Lang.Class({
|
||||
@ -48,9 +48,10 @@ const MaxWidthBin = new Lang.Class({
|
||||
const SearchResult = new Lang.Class({
|
||||
Name: 'SearchResult',
|
||||
|
||||
_init: function(provider, metaInfo) {
|
||||
_init: function(provider, metaInfo, searchResultsView) {
|
||||
this.provider = provider;
|
||||
this.metaInfo = metaInfo;
|
||||
this._searchResultsView = searchResultsView;
|
||||
|
||||
this.actor = new St.Button({ reactive: true,
|
||||
can_focus: true,
|
||||
@ -72,10 +73,10 @@ const ListSearchResult = new Lang.Class({
|
||||
Name: 'ListSearchResult',
|
||||
Extends: SearchResult,
|
||||
|
||||
ICON_SIZE: 64,
|
||||
ICON_SIZE: 24,
|
||||
|
||||
_init: function(provider, metaInfo) {
|
||||
this.parent(provider, metaInfo);
|
||||
_init: function(provider, metaInfo, searchResultsView) {
|
||||
this.parent(provider, metaInfo, searchResultsView);
|
||||
|
||||
this.actor.style_class = 'list-search-result';
|
||||
this.actor.x_fill = true;
|
||||
@ -90,7 +91,7 @@ const ListSearchResult = new Lang.Class({
|
||||
content.add(icon);
|
||||
}
|
||||
|
||||
let details = new St.BoxLayout({ vertical: true });
|
||||
let details = new St.BoxLayout({ vertical: false });
|
||||
content.add(details, { x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
@ -101,17 +102,38 @@ const ListSearchResult = new Lang.Class({
|
||||
details.add(title, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
y_align: St.Align.MIDDLE });
|
||||
this.actor.label_actor = title;
|
||||
|
||||
this._descriptionLabel =
|
||||
new St.Label({
|
||||
style_class: 'list-search-result-description' });
|
||||
|
||||
if (this.metaInfo['description']) {
|
||||
let description = new St.Label({ style_class: 'list-search-result-description' });
|
||||
description.clutter_text.set_markup(this.metaInfo['description']);
|
||||
details.add(description, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.END });
|
||||
this._highlightTerms();
|
||||
|
||||
details.add(this._descriptionLabel, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
}
|
||||
|
||||
this._termsChangedSignal =
|
||||
this._searchResultsView.connect(
|
||||
'terms-changed',
|
||||
Lang.bind(this, this._highlightTerms));
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
},
|
||||
|
||||
_highlightTerms: function() {
|
||||
if (!this.metaInfo['description'] || !this._descriptionLabel || !this._searchResultsView)
|
||||
return;
|
||||
|
||||
this._descriptionLabel.clutter_text.set_markup(this._searchResultsView.highlightTerms(this.metaInfo['description']));
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._searchResultsView.disconnect(this._termsChangedSignal);
|
||||
}
|
||||
});
|
||||
|
||||
@ -119,8 +141,8 @@ const GridSearchResult = new Lang.Class({
|
||||
Name: 'GridSearchResult',
|
||||
Extends: SearchResult,
|
||||
|
||||
_init: function(provider, metaInfo) {
|
||||
this.parent(provider, metaInfo);
|
||||
_init: function(provider, metaInfo, searchResultsView) {
|
||||
this.parent(provider, metaInfo, searchResultsView);
|
||||
|
||||
this.actor.style_class = 'grid-search-result';
|
||||
|
||||
@ -135,8 +157,9 @@ const GridSearchResult = new Lang.Class({
|
||||
const SearchResultsBase = new Lang.Class({
|
||||
Name: 'SearchResultsBase',
|
||||
|
||||
_init: function(provider) {
|
||||
_init: function(provider, searchResultsView) {
|
||||
this.provider = provider;
|
||||
this._searchResultsView = searchResultsView;
|
||||
|
||||
this._terms = [];
|
||||
|
||||
@ -147,8 +170,8 @@ const SearchResultsBase = new Lang.Class({
|
||||
y_fill: true });
|
||||
this.actor.add(this._resultDisplayBin, { expand: true });
|
||||
|
||||
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
|
||||
this.actor.add(separator.actor);
|
||||
let separator = new St.DrawingArea({ style_class: 'search-section-separator' });
|
||||
this.actor.add(separator);
|
||||
|
||||
this._resultDisplays = {};
|
||||
|
||||
@ -164,7 +187,8 @@ const SearchResultsBase = new Lang.Class({
|
||||
|
||||
_createResultDisplay: function(meta) {
|
||||
if (this.provider.createResultObject)
|
||||
return this.provider.createResultObject(meta);
|
||||
return this.provider.createResultObject(meta,
|
||||
this._searchResultsView);
|
||||
|
||||
return null;
|
||||
},
|
||||
@ -188,7 +212,7 @@ const SearchResultsBase = new Lang.Class({
|
||||
Main.overview.toggle();
|
||||
},
|
||||
|
||||
_setMoreIconVisible: function(visible) {
|
||||
_setMoreLabelVisible: function(visible, moreNumber) {
|
||||
},
|
||||
|
||||
_ensureResultActors: function(results, callback) {
|
||||
@ -231,7 +255,6 @@ const SearchResultsBase = new Lang.Class({
|
||||
|
||||
updateSearch: function(providerResults, terms, callback) {
|
||||
this._terms = terms;
|
||||
|
||||
if (providerResults.length == 0) {
|
||||
this._clearResultDisplay();
|
||||
this.actor.hide();
|
||||
@ -256,7 +279,8 @@ const SearchResultsBase = new Lang.Class({
|
||||
results.forEach(Lang.bind(this, function(resultId) {
|
||||
this._addItem(this._resultDisplays[resultId]);
|
||||
}));
|
||||
this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
|
||||
this._setMoreLabelVisible(hasMoreResults && this.provider.canLaunchSearch,
|
||||
providerResults.length - results.length);
|
||||
this.actor.show();
|
||||
callback();
|
||||
}));
|
||||
@ -268,20 +292,20 @@ const ListSearchResults = new Lang.Class({
|
||||
Name: 'ListSearchResults',
|
||||
Extends: SearchResultsBase,
|
||||
|
||||
_init: function(provider) {
|
||||
this.parent(provider);
|
||||
_init: function(provider, searchResultsView) {
|
||||
this.parent(provider, searchResultsView);
|
||||
|
||||
this._container = new St.BoxLayout({ style_class: 'search-section-content' });
|
||||
this.providerIcon = new ProviderIcon(provider);
|
||||
this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this.providerIcon.connect('clicked', Lang.bind(this,
|
||||
this.providerInfo = new ProviderInfo(provider);
|
||||
this.providerInfo.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this.providerInfo.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
this.providerIcon.animateLaunch();
|
||||
this.providerInfo.animateLaunch();
|
||||
provider.launchSearch(this._terms);
|
||||
Main.overview.toggle();
|
||||
}));
|
||||
|
||||
this._container.add(this.providerIcon, { x_fill: false,
|
||||
this._container.add(this.providerInfo, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
@ -293,8 +317,8 @@ const ListSearchResults = new Lang.Class({
|
||||
this._resultDisplayBin.set_child(this._container);
|
||||
},
|
||||
|
||||
_setMoreIconVisible: function(visible) {
|
||||
this.providerIcon.moreIcon.visible = visible;
|
||||
_setMoreLabelVisible: function(visible, moreNumber) {
|
||||
this.providerInfo.setMoreVisible(visible, moreNumber);
|
||||
},
|
||||
|
||||
_getMaxDisplayedResults: function() {
|
||||
@ -306,7 +330,8 @@ const ListSearchResults = new Lang.Class({
|
||||
},
|
||||
|
||||
_createResultDisplay: function(meta) {
|
||||
return this.parent(meta) || new ListSearchResult(this.provider, meta);
|
||||
return this.parent(meta, this._searchResultsView) ||
|
||||
new ListSearchResult(this.provider, meta, this._searchResultsView);
|
||||
},
|
||||
|
||||
_addItem: function(display) {
|
||||
@ -326,14 +351,14 @@ const GridSearchResults = new Lang.Class({
|
||||
Name: 'GridSearchResults',
|
||||
Extends: SearchResultsBase,
|
||||
|
||||
_init: function(provider, parentContainer) {
|
||||
this.parent(provider);
|
||||
_init: function(provider, searchResultsView) {
|
||||
this.parent(provider, searchResultsView);
|
||||
// We need to use the parent container to know how much results we can show.
|
||||
// None of the actors in this class can be used for that, since the main actor
|
||||
// goes hidden when no results are displayed, and then it lost its allocation.
|
||||
// Then on the next use of _getMaxDisplayedResults allocation is 0, en therefore
|
||||
// it doesn't show any result although we have some.
|
||||
this._parentContainer = parentContainer;
|
||||
this._parentContainer = searchResultsView.actor;
|
||||
|
||||
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
|
||||
xAlign: St.Align.START });
|
||||
@ -354,7 +379,8 @@ const GridSearchResults = new Lang.Class({
|
||||
},
|
||||
|
||||
_createResultDisplay: function(meta) {
|
||||
return this.parent(meta) || new GridSearchResult(this.provider, meta);
|
||||
return this.parent(meta, this._searchResultsView) ||
|
||||
new GridSearchResult(this.provider, meta, this._searchResultsView);
|
||||
},
|
||||
|
||||
_addItem: function(display) {
|
||||
@ -418,6 +444,8 @@ const SearchResults = new Lang.Class({
|
||||
|
||||
this._providers = [];
|
||||
|
||||
this._searchTermRegex = null;
|
||||
|
||||
this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA });
|
||||
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::enabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||
@ -537,6 +565,14 @@ const SearchResults = new Lang.Class({
|
||||
|
||||
if (this._searchTimeoutId == 0)
|
||||
this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, Lang.bind(this, this._onSearchTimeout));
|
||||
|
||||
let escapedSearchTerms = this._terms.map(
|
||||
(currentTerm, index, array) =>
|
||||
{ return Shell.util_regex_escape(currentTerm) });
|
||||
|
||||
this._searchTermRegex =
|
||||
new RegExp(`(${escapedSearchTerms.join('|')})`, 'gi');
|
||||
this.emit('terms-changed');
|
||||
},
|
||||
|
||||
_onPan: function(action) {
|
||||
@ -556,9 +592,9 @@ const SearchResults = new Lang.Class({
|
||||
|
||||
let providerDisplay;
|
||||
if (provider.appInfo)
|
||||
providerDisplay = new ListSearchResults(provider);
|
||||
providerDisplay = new ListSearchResults(provider, this);
|
||||
else
|
||||
providerDisplay = new GridSearchResults(provider, this.actor);
|
||||
providerDisplay = new GridSearchResults(provider, this);
|
||||
|
||||
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
providerDisplay.actor.hide();
|
||||
@ -675,14 +711,22 @@ const SearchResults = new Lang.Class({
|
||||
} else {
|
||||
result.actor.remove_style_pseudo_class('selected');
|
||||
}
|
||||
},
|
||||
|
||||
highlightTerms: function(description) {
|
||||
if (!description)
|
||||
return '';
|
||||
|
||||
return description.replace(this._searchTermRegex, '<b>$1</b>');
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SearchResults.prototype);
|
||||
|
||||
const ProviderIcon = new Lang.Class({
|
||||
Name: 'ProviderIcon',
|
||||
const ProviderInfo = new Lang.Class({
|
||||
Name: 'ProviderInfo',
|
||||
Extends: St.Button,
|
||||
|
||||
PROVIDER_ICON_SIZE: 48,
|
||||
PROVIDER_ICON_SIZE: 32,
|
||||
|
||||
_init: function(provider) {
|
||||
this.provider = provider;
|
||||
@ -692,22 +736,45 @@ const ProviderIcon = new Lang.Class({
|
||||
accessible_name: provider.appInfo.get_name(),
|
||||
track_hover: true });
|
||||
|
||||
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
this._content = new St.BoxLayout({ vertical: false });
|
||||
this.set_child(this._content);
|
||||
|
||||
let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
|
||||
|
||||
this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
|
||||
visible: false,
|
||||
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
|
||||
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
|
||||
gicon: provider.appInfo.get_icon() });
|
||||
this._content.add_actor(icon);
|
||||
this._content.add_actor(this.moreIcon);
|
||||
|
||||
this._providerDetails = new St.BoxLayout({
|
||||
style_class: 'list-search-provider-details',
|
||||
vertical: true });
|
||||
|
||||
let providerNameLabel = new St.Label({
|
||||
style_class: 'list-search-result-provider',
|
||||
text: provider.appInfo.get_name() });
|
||||
|
||||
this._remainingResultsLabel = new St.Label({
|
||||
style_class: 'list-search-result-title' });
|
||||
|
||||
this._providerDetails.add(providerNameLabel,
|
||||
{ x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
this._providerDetails.add(this._remainingResultsLabel,
|
||||
{ x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
|
||||
|
||||
this._content.add(icon, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
this._content.add(this._providerDetails, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
},
|
||||
|
||||
animateLaunch: function() {
|
||||
@ -715,5 +782,11 @@ const ProviderIcon = new Lang.Class({
|
||||
let app = appSys.lookup_app(this.provider.appInfo.get_id());
|
||||
if (app.state == Shell.AppState.STOPPED)
|
||||
IconGrid.zoomOutActor(this._content);
|
||||
},
|
||||
|
||||
setMoreVisible: function(visible, resultsCount) {
|
||||
this._remainingResultsLabel.visible = visible;
|
||||
this._remainingResultsLabel.clutter_text.set_markup(
|
||||
_("%d more").format(resultsCount));
|
||||
}
|
||||
});
|
||||
|
@ -240,6 +240,21 @@ shell_util_translate_time_string (const char *str)
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_util_regex_escape:
|
||||
* @str: a UTF-8 string to escape
|
||||
*
|
||||
* A wrapper around g_regex_escape_string() that takes its argument as
|
||||
* \0-terminated string rather than a byte-array the confuses gjs.
|
||||
*
|
||||
* Returns: @str with all regex-special characters escaped
|
||||
*/
|
||||
char *
|
||||
shell_util_regex_escape (const char *str)
|
||||
{
|
||||
return g_regex_escape_string (str, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_write_string_to_stream:
|
||||
* @stream: a #GOutputStream
|
||||
|
@ -24,6 +24,8 @@ char *shell_util_format_date (const char *format,
|
||||
gint64 time_ms);
|
||||
const char *shell_util_translate_time_string (const char *str);
|
||||
|
||||
char *shell_util_regex_escape (const char *str);
|
||||
|
||||
gboolean shell_write_string_to_stream (GOutputStream *stream,
|
||||
const char *str,
|
||||
GError **error);
|
||||
|
Loading…
Reference in New Issue
Block a user