[Overview] Update look and feel of the search field
Port the search entry to CSS and update look and feel according to the latest design. https://bugzilla.gnome.org/show_bug.cgi?id=611095
This commit is contained in:
parent
89173544d4
commit
858a6bf827
@ -62,5 +62,5 @@
|
|||||||
clip-rule="evenodd"
|
clip-rule="evenodd"
|
||||||
d="M10.5,3.5l2,2L10,8l2.5,2.5l-2,2L8,10l-2.5,2.5l-2-2L6,8L3.5,5.5l2-2L8,6L10.5,3.5 z M0,8c0-4.418,3.582-8,8-8s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
|
d="M10.5,3.5l2,2L10,8l2.5,2.5l-2,2L8,10l-2.5,2.5l-2-2L6,8L3.5,5.5l2-2L8,6L10.5,3.5 z M0,8c0-4.418,3.582-8,8-8s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
|
||||||
id="path2394"
|
id="path2394"
|
||||||
style="fill-opacity:1;fill:#000000" />
|
style="fill-opacity:1;fill:#545454" />
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
@ -271,11 +271,24 @@ StTooltip {
|
|||||||
|
|
||||||
#searchEntry {
|
#searchEntry {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border-bottom: 1px solid #262626;
|
border-radius: 4px;
|
||||||
|
color: #a8a8a8;
|
||||||
|
border: 1px solid #565656;
|
||||||
|
background-color: #404040;
|
||||||
|
caret-color: #fff;
|
||||||
|
caret-size: 1px;
|
||||||
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchEntry:active {
|
#searchEntry:focus {
|
||||||
background-color: #c4c4c4;
|
color: #545454;
|
||||||
|
border: 1px solid #3a3a3a;
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
caret-color: #545454;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchEntry:hover {
|
||||||
|
border: 1px solid #767676;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-section {
|
.dash-section {
|
||||||
|
302
js/ui/dash.js
302
js/ui/dash.js
@ -24,31 +24,6 @@ const Search = imports.ui.search;
|
|||||||
const MAX_RENDERED_SEARCH_RESULTS = 25;
|
const MAX_RENDERED_SEARCH_RESULTS = 25;
|
||||||
|
|
||||||
const DEFAULT_PADDING = 4;
|
const DEFAULT_PADDING = 4;
|
||||||
const DEFAULT_SPACING = 4;
|
|
||||||
|
|
||||||
const BACKGROUND_COLOR = new Clutter.Color();
|
|
||||||
BACKGROUND_COLOR.from_pixel(0x000000c0);
|
|
||||||
|
|
||||||
const PRELIGHT_COLOR = new Clutter.Color();
|
|
||||||
PRELIGHT_COLOR.from_pixel(0x4f6fadaa);
|
|
||||||
|
|
||||||
const TEXT_COLOR = new Clutter.Color();
|
|
||||||
TEXT_COLOR.from_pixel(0x5f5f5fff);
|
|
||||||
const BRIGHTER_TEXT_COLOR = new Clutter.Color();
|
|
||||||
BRIGHTER_TEXT_COLOR.from_pixel(0xbbbbbbff);
|
|
||||||
const BRIGHT_TEXT_COLOR = new Clutter.Color();
|
|
||||||
BRIGHT_TEXT_COLOR.from_pixel(0xffffffff);
|
|
||||||
const SEARCH_TEXT_COLOR = new Clutter.Color();
|
|
||||||
SEARCH_TEXT_COLOR.from_pixel(0x333333ff);
|
|
||||||
|
|
||||||
const SEARCH_CURSOR_COLOR = BRIGHT_TEXT_COLOR;
|
|
||||||
const HIGHLIGHTED_SEARCH_CURSOR_COLOR = SEARCH_TEXT_COLOR;
|
|
||||||
|
|
||||||
const SEARCH_BORDER_BOTTOM_COLOR = new Clutter.Color();
|
|
||||||
SEARCH_BORDER_BOTTOM_COLOR.from_pixel(0x191919ff);
|
|
||||||
|
|
||||||
const BROWSE_ACTIVATED_BG = new Clutter.Color();
|
|
||||||
BROWSE_ACTIVATED_BG.from_pixel(0x303030f0);
|
|
||||||
|
|
||||||
const DOCS = "docs";
|
const DOCS = "docs";
|
||||||
const PLACES = "places";
|
const PLACES = "places";
|
||||||
@ -220,76 +195,44 @@ function SearchEntry() {
|
|||||||
|
|
||||||
SearchEntry.prototype = {
|
SearchEntry.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.actor = new St.BoxLayout({ name: "searchEntry",
|
this.actor = new St.Entry({ name: "searchEntry",
|
||||||
reactive: true });
|
hint_text: _("Find") });
|
||||||
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
this.entry = this.actor.clutter_text;
|
||||||
y_align: Big.BoxAlignment.CENTER });
|
|
||||||
this.actor.add(box, { expand: true });
|
this.actor.clutter_text.connect('text-changed', Lang.bind(this,
|
||||||
this.actor.connect('button-press-event', Lang.bind(this, function () {
|
function() {
|
||||||
this._resetTextState(true);
|
if (this.isActive())
|
||||||
return false;
|
this.actor.set_secondary_icon_from_file(global.imagedir +
|
||||||
}));
|
"close-black.svg");
|
||||||
|
else
|
||||||
|
this.actor.set_secondary_icon_from_file(null);
|
||||||
|
}));
|
||||||
|
this.actor.connect('secondary-icon-clicked', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this.reset();
|
||||||
|
}));
|
||||||
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
|
||||||
this.pane = null;
|
this.pane = null;
|
||||||
|
|
||||||
this._defaultText = _("Find...");
|
this._capturedEventId = 0;
|
||||||
|
},
|
||||||
|
|
||||||
let textProperties = { font_name: "Sans 16px" };
|
show: function() {
|
||||||
let entryProperties = { editable: true,
|
if (this._capturedEventId == 0)
|
||||||
activatable: true,
|
this._capturedEventId = global.stage.connect('captured-event',
|
||||||
single_line_mode: true,
|
Lang.bind(this, this._onCapturedEvent));
|
||||||
color: SEARCH_TEXT_COLOR,
|
this.entry.set_cursor_visible(true);
|
||||||
cursor_color: SEARCH_CURSOR_COLOR };
|
this.entry.set_selection(0, 0);
|
||||||
Lang.copyProperties(textProperties, entryProperties);
|
},
|
||||||
this.entry = new Clutter.Text(entryProperties);
|
|
||||||
|
|
||||||
this.entry.connect('notify::text', Lang.bind(this, function () {
|
hide: function() {
|
||||||
this._resetTextState(false);
|
if (this.isActive())
|
||||||
}));
|
this.reset();
|
||||||
box.append(this.entry, Big.BoxPackFlags.EXPAND);
|
if (this._capturedEventId > 0) {
|
||||||
|
global.stage.disconnect(this._capturedEventId);
|
||||||
// Mark as editable just to get a cursor
|
this._capturedEventId = 0;
|
||||||
let defaultTextProperties = { ellipsize: Pango.EllipsizeMode.END,
|
}
|
||||||
text: this._defaultText,
|
|
||||||
editable: true,
|
|
||||||
color: TEXT_COLOR,
|
|
||||||
cursor_visible: false,
|
|
||||||
single_line_mode: true };
|
|
||||||
Lang.copyProperties(textProperties, defaultTextProperties);
|
|
||||||
this._defaultText = new Clutter.Text(defaultTextProperties);
|
|
||||||
box.add_actor(this._defaultText);
|
|
||||||
this.entry.connect('notify::allocation', Lang.bind(this, function () {
|
|
||||||
this._repositionDefaultText();
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._iconBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER,
|
|
||||||
y_align: Big.BoxAlignment.CENTER,
|
|
||||||
padding_right: 4 });
|
|
||||||
box.append(this._iconBox, Big.BoxPackFlags.END);
|
|
||||||
|
|
||||||
let magnifierUri = "file://" + global.imagedir + "magnifier.svg";
|
|
||||||
this._magnifierIcon = St.TextureCache.get_default().load_uri_sync(St.TextureCachePolicy.FOREVER,
|
|
||||||
magnifierUri, 18, 18);
|
|
||||||
let closeUri = "file://" + global.imagedir + "close-black.svg";
|
|
||||||
this._closeIcon = St.TextureCache.get_default().load_uri_sync(St.TextureCachePolicy.FOREVER,
|
|
||||||
closeUri, 18, 18);
|
|
||||||
this._closeIcon.reactive = true;
|
|
||||||
this._closeIcon.connect('button-press-event', Lang.bind(this, function () {
|
|
||||||
// Resetting this.entry.text will trigger notify::text signal which will
|
|
||||||
// result in this._resetTextState() being called, but we should not rely
|
|
||||||
// on that not short-circuiting if the text was already empty, so we call
|
|
||||||
// this._resetTextState() explicitly in that case.
|
|
||||||
if (this.entry.text == '')
|
|
||||||
this._resetTextState(false);
|
|
||||||
else
|
|
||||||
this.entry.text = '';
|
|
||||||
|
|
||||||
// Return true to stop the signal emission, so that this.actor doesn't get
|
|
||||||
// the button-press-event and re-highlight itself.
|
|
||||||
return true;
|
|
||||||
}));
|
|
||||||
this._repositionDefaultText();
|
|
||||||
this._resetTextState();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setPane: function (pane) {
|
setPane: function (pane) {
|
||||||
@ -298,35 +241,93 @@ SearchEntry.prototype = {
|
|||||||
|
|
||||||
reset: function () {
|
reset: function () {
|
||||||
this.entry.text = '';
|
this.entry.text = '';
|
||||||
|
global.stage.set_key_focus(null);
|
||||||
|
this.entry.set_cursor_visible(true);
|
||||||
|
this.entry.set_selection(0, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
getText: function () {
|
getText: function () {
|
||||||
return this.entry.text;
|
return this.entry.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||||
},
|
},
|
||||||
|
|
||||||
_resetTextState: function (searchEntryClicked) {
|
// some search term has been entered
|
||||||
let text = this.getText();
|
isActive: function() {
|
||||||
this._iconBox.remove_all();
|
return this.actor.get_text() != '';
|
||||||
// We highlight the search box if the user starts typing in it
|
},
|
||||||
// or just clicks in it to indicate that the search is active.
|
|
||||||
if (text != '' || searchEntryClicked) {
|
// the entry does not show the hint
|
||||||
if (!searchEntryClicked)
|
_isActivated: function() {
|
||||||
this._defaultText.hide();
|
return this.entry.text == this.actor.get_text();
|
||||||
this._iconBox.append(this._closeIcon, Big.BoxPackFlags.NONE);
|
},
|
||||||
this.actor.set_style_pseudo_class('active');
|
|
||||||
this.entry.cursor_color = HIGHLIGHTED_SEARCH_CURSOR_COLOR;
|
_onCapturedEvent: function(actor, event) {
|
||||||
} else {
|
let source = event.get_source();
|
||||||
this._defaultText.show();
|
let panelEvent = false;
|
||||||
this._iconBox.append(this._magnifierIcon, Big.BoxPackFlags.NONE);
|
|
||||||
this.actor.set_style_pseudo_class(null);
|
if (source) {
|
||||||
this.entry.cursor_color = SEARCH_CURSOR_COLOR;
|
let parent = source;
|
||||||
|
do {
|
||||||
|
if (parent == Main.panel.actor)
|
||||||
|
break;
|
||||||
|
} while ((parent = parent.get_parent()) != null);
|
||||||
|
panelEvent = (parent != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event.type()) {
|
||||||
|
case Clutter.EventType.BUTTON_PRESS:
|
||||||
|
// the user clicked outside after activating the entry, but
|
||||||
|
// with no search term entered - cancel the search
|
||||||
|
if (source != this.entry && this.entry.text == '') {
|
||||||
|
this.reset();
|
||||||
|
// allow only panel events to continue
|
||||||
|
return !panelEvent;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Clutter.EventType.KEY_PRESS:
|
||||||
|
// If neither the stage nor our entry have key focus, some
|
||||||
|
// "special" actor grabbed the focus (run dialog, looking
|
||||||
|
// glass); we don't want to interfere with that
|
||||||
|
let focus = global.stage.get_key_focus();
|
||||||
|
if (focus != global.stage && focus != this.entry)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let sym = event.get_key_symbol();
|
||||||
|
|
||||||
|
// If we have an active search, Escape cancels it - if we
|
||||||
|
// haven't, the key is ignored
|
||||||
|
if (sym == Clutter.Escape)
|
||||||
|
if (this._isActivated()) {
|
||||||
|
this.reset();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore non-printable keys
|
||||||
|
if (!Clutter.keysym_to_unicode(sym))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Search started - move the key focus to the entry and
|
||||||
|
// "repeat" the event
|
||||||
|
if (!this._isActivated()) {
|
||||||
|
global.stage.set_key_focus(this.entry);
|
||||||
|
this.entry.event(event, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
// Suppress all other events outside the panel while the entry
|
||||||
|
// is activated and no search has been entered - any click
|
||||||
|
// outside the entry will cancel the search
|
||||||
|
return (this.entry.text == '' && !panelEvent);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_repositionDefaultText: function () {
|
_onDestroy: function() {
|
||||||
// Offset a little to show the cursor
|
if (this._capturedEventId > 0) {
|
||||||
this._defaultText.set_position(this.entry.x + 4, this.entry.y);
|
global.stage.disconnect(this._capturedEventId);
|
||||||
this._defaultText.set_size(this.entry.width, this.entry.height);
|
this._capturedEventId = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Signals.addSignalMethods(SearchEntry.prototype);
|
Signals.addSignalMethods(SearchEntry.prototype);
|
||||||
@ -815,12 +816,11 @@ Dash.prototype = {
|
|||||||
this.actor.add(this.searchResults.actor);
|
this.actor.add(this.searchResults.actor);
|
||||||
this.searchResults.actor.hide();
|
this.searchResults.actor.hide();
|
||||||
|
|
||||||
|
this._keyPressId = 0;
|
||||||
this._searchTimeoutId = 0;
|
this._searchTimeoutId = 0;
|
||||||
this._searchEntry.entry.connect('text-changed', Lang.bind(this, function (se, prop) {
|
this._searchEntry.entry.connect('text-changed', Lang.bind(this, function (se, prop) {
|
||||||
let text = this._searchEntry.getText();
|
|
||||||
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
|
|
||||||
let searchPreviouslyActive = this._searchActive;
|
let searchPreviouslyActive = this._searchActive;
|
||||||
this._searchActive = text != '';
|
this._searchActive = this._searchEntry.isActive();
|
||||||
this._searchPending = this._searchActive && !searchPreviouslyActive;
|
this._searchPending = this._searchActive && !searchPreviouslyActive;
|
||||||
if (this._searchPending) {
|
if (this._searchPending) {
|
||||||
this.searchResults.startingSearch();
|
this.searchResults.startingSearch();
|
||||||
@ -851,35 +851,6 @@ Dash.prototype = {
|
|||||||
this.searchResults.activateSelected();
|
this.searchResults.activateSelected();
|
||||||
return true;
|
return true;
|
||||||
}));
|
}));
|
||||||
this._searchEntry.entry.connect('key-press-event', Lang.bind(this, function (se, e) {
|
|
||||||
let symbol = e.get_key_symbol();
|
|
||||||
if (symbol == Clutter.Escape) {
|
|
||||||
// Escape will keep clearing things back to the desktop.
|
|
||||||
// If we have an active search, we remove it.
|
|
||||||
if (this._searchActive)
|
|
||||||
this._searchEntry.reset();
|
|
||||||
// Next, if we're in one of the "more" modes or showing the details pane, close them
|
|
||||||
else if (this._activePane != null)
|
|
||||||
this._activePane.close();
|
|
||||||
// Finally, just close the Overview entirely
|
|
||||||
else
|
|
||||||
Main.overview.hide();
|
|
||||||
return true;
|
|
||||||
} else if (symbol == Clutter.Up) {
|
|
||||||
if (!this._searchActive)
|
|
||||||
return true;
|
|
||||||
this.searchResults.selectUp(false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else if (symbol == Clutter.Down) {
|
|
||||||
if (!this._searchActive)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
this.searchResults.selectDown(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
|
|
||||||
/***** Applications *****/
|
/***** Applications *****/
|
||||||
|
|
||||||
@ -933,6 +904,40 @@ Dash.prototype = {
|
|||||||
this.sectionArea.add(this._docsSection.actor, { expand: true });
|
this.sectionArea.add(this._docsSection.actor, { expand: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onKeyPress: function(stage, event) {
|
||||||
|
// If neither the stage nor the search entry have key focus, some
|
||||||
|
// "special" actor grabbed the focus (run dialog, looking glass);
|
||||||
|
// we don't want to interfere with that
|
||||||
|
let focus = stage.get_key_focus();
|
||||||
|
if (focus != stage && focus != this._searchEntry.entry)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let symbol = event.get_key_symbol();
|
||||||
|
if (symbol == Clutter.Escape) {
|
||||||
|
// If we're in one of the "more" modes or showing the
|
||||||
|
// details pane, close them
|
||||||
|
if (this._activePane != null)
|
||||||
|
this._activePane.close();
|
||||||
|
// Otherwise, just close the Overview entirely
|
||||||
|
else
|
||||||
|
Main.overview.hide();
|
||||||
|
return true;
|
||||||
|
} else if (symbol == Clutter.Up) {
|
||||||
|
if (!this._searchActive)
|
||||||
|
return true;
|
||||||
|
this.searchResults.selectUp(false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (symbol == Clutter.Down) {
|
||||||
|
if (!this._searchActive)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
this.searchResults.selectDown(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
_doSearch: function () {
|
_doSearch: function () {
|
||||||
this._searchTimeoutId = 0;
|
this._searchTimeoutId = 0;
|
||||||
let text = this._searchEntry.getText();
|
let text = this._searchEntry.getText();
|
||||||
@ -942,14 +947,21 @@ Dash.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
global.stage.set_key_focus(this._searchEntry.entry);
|
this._searchEntry.show();
|
||||||
|
if (this._keyPressId == 0)
|
||||||
|
this._keyPressId = global.stage.connect('key-press-event',
|
||||||
|
Lang.bind(this, this._onKeyPress));
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
this._firstSelectAfterOverlayShow = true;
|
this._firstSelectAfterOverlayShow = true;
|
||||||
this._searchEntry.reset();
|
this._searchEntry.hide();
|
||||||
if (this._activePane != null)
|
if (this._activePane != null)
|
||||||
this._activePane.close();
|
this._activePane.close();
|
||||||
|
if (this._keyPressId > 0) {
|
||||||
|
global.stage.disconnect(this._keyPressId);
|
||||||
|
this._keyPressId = 0;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
closePanes: function () {
|
closePanes: function () {
|
||||||
|
Loading…
Reference in New Issue
Block a user