[gnome-shell] [Overview] Update look and feel of the search field
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] [Overview] Update look and feel of the search field
- Date: Thu, 11 Mar 2010 20:18:34 +0000 (UTC)
commit 858a6bf8274c3ee41ae33ea40b4e27fb3324a758
Author: Florian Müllner <fmuellner src gnome org>
Date: Sat Feb 27 15:49:39 2010 +0100
[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
data/close-black.svg | 4 +-
data/theme/gnome-shell.css | 19 +++-
js/ui/dash.js | 306 +++++++++++++++++++++++---------------------
3 files changed, 177 insertions(+), 152 deletions(-)
---
diff --git a/data/close-black.svg b/data/close-black.svg
index 1443bb8..c370745 100644
--- a/data/close-black.svg
+++ b/data/close-black.svg
@@ -62,5 +62,5 @@
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"
id="path2394"
- style="fill-opacity:1;fill:#000000" />
-</svg>
\ No newline at end of file
+ style="fill-opacity:1;fill:#545454" />
+</svg>
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 5fa11de..b5cce5c 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -271,11 +271,24 @@ StTooltip {
#searchEntry {
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:focus {
+ color: #545454;
+ border: 1px solid #3a3a3a;
+ background-color: #e8e8e8;
+ caret-color: #545454;
}
-#searchEntry:active {
- background-color: #c4c4c4;
+#searchEntry:hover {
+ border: 1px solid #767676;
}
.dash-section {
diff --git a/js/ui/dash.js b/js/ui/dash.js
index 041c2a1..d0e32c6 100644
--- a/js/ui/dash.js
+++ b/js/ui/dash.js
@@ -24,31 +24,6 @@ const Search = imports.ui.search;
const MAX_RENDERED_SEARCH_RESULTS = 25;
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 PLACES = "places";
@@ -220,76 +195,44 @@ function SearchEntry() {
SearchEntry.prototype = {
_init : function() {
- this.actor = new St.BoxLayout({ name: "searchEntry",
- reactive: true });
- let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- y_align: Big.BoxAlignment.CENTER });
- this.actor.add(box, { expand: true });
- this.actor.connect('button-press-event', Lang.bind(this, function () {
- this._resetTextState(true);
- return false;
- }));
+ this.actor = new St.Entry({ name: "searchEntry",
+ hint_text: _("Find") });
+ this.entry = this.actor.clutter_text;
+
+ this.actor.clutter_text.connect('text-changed', Lang.bind(this,
+ function() {
+ if (this.isActive())
+ 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._defaultText = _("Find...");
-
- let textProperties = { font_name: "Sans 16px" };
- let entryProperties = { editable: true,
- activatable: true,
- single_line_mode: true,
- color: SEARCH_TEXT_COLOR,
- cursor_color: SEARCH_CURSOR_COLOR };
- Lang.copyProperties(textProperties, entryProperties);
- this.entry = new Clutter.Text(entryProperties);
-
- this.entry.connect('notify::text', Lang.bind(this, function () {
- this._resetTextState(false);
- }));
- box.append(this.entry, Big.BoxPackFlags.EXPAND);
-
- // Mark as editable just to get a cursor
- 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._capturedEventId = 0;
+ },
- 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 = '';
+ show: function() {
+ if (this._capturedEventId == 0)
+ this._capturedEventId = global.stage.connect('captured-event',
+ Lang.bind(this, this._onCapturedEvent));
+ this.entry.set_cursor_visible(true);
+ this.entry.set_selection(0, 0);
+ },
- // 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();
+ hide: function() {
+ if (this.isActive())
+ this.reset();
+ if (this._capturedEventId > 0) {
+ global.stage.disconnect(this._capturedEventId);
+ this._capturedEventId = 0;
+ }
},
setPane: function (pane) {
@@ -298,35 +241,93 @@ SearchEntry.prototype = {
reset: function () {
this.entry.text = '';
+ global.stage.set_key_focus(null);
+ this.entry.set_cursor_visible(true);
+ this.entry.set_selection(0, 0);
},
getText: function () {
- return this.entry.text;
- },
-
- _resetTextState: function (searchEntryClicked) {
- let text = this.getText();
- this._iconBox.remove_all();
- // 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) {
- if (!searchEntryClicked)
- this._defaultText.hide();
- this._iconBox.append(this._closeIcon, Big.BoxPackFlags.NONE);
- this.actor.set_style_pseudo_class('active');
- this.entry.cursor_color = HIGHLIGHTED_SEARCH_CURSOR_COLOR;
- } else {
- this._defaultText.show();
- this._iconBox.append(this._magnifierIcon, Big.BoxPackFlags.NONE);
- this.actor.set_style_pseudo_class(null);
- this.entry.cursor_color = SEARCH_CURSOR_COLOR;
+ return this.entry.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
+ },
+
+ // some search term has been entered
+ isActive: function() {
+ return this.actor.get_text() != '';
+ },
+
+ // the entry does not show the hint
+ _isActivated: function() {
+ return this.entry.text == this.actor.get_text();
+ },
+
+ _onCapturedEvent: function(actor, event) {
+ let source = event.get_source();
+ let panelEvent = false;
+
+ if (source) {
+ 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 () {
- // Offset a little to show the cursor
- this._defaultText.set_position(this.entry.x + 4, this.entry.y);
- this._defaultText.set_size(this.entry.width, this.entry.height);
+ _onDestroy: function() {
+ if (this._capturedEventId > 0) {
+ global.stage.disconnect(this._capturedEventId);
+ this._capturedEventId = 0;
+ }
}
};
Signals.addSignalMethods(SearchEntry.prototype);
@@ -815,12 +816,11 @@ Dash.prototype = {
this.actor.add(this.searchResults.actor);
this.searchResults.actor.hide();
+ this._keyPressId = 0;
this._searchTimeoutId = 0;
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;
- this._searchActive = text != '';
+ this._searchActive = this._searchEntry.isActive();
this._searchPending = this._searchActive && !searchPreviouslyActive;
if (this._searchPending) {
this.searchResults.startingSearch();
@@ -851,35 +851,6 @@ Dash.prototype = {
this.searchResults.activateSelected();
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 *****/
@@ -933,6 +904,40 @@ Dash.prototype = {
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 () {
this._searchTimeoutId = 0;
let text = this._searchEntry.getText();
@@ -942,14 +947,21 @@ Dash.prototype = {
},
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() {
this._firstSelectAfterOverlayShow = true;
- this._searchEntry.reset();
+ this._searchEntry.hide();
if (this._activePane != null)
this._activePane.close();
+ if (this._keyPressId > 0) {
+ global.stage.disconnect(this._keyPressId);
+ this._keyPressId = 0;
+ }
},
closePanes: function () {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]