[rhythmbox] search-entry: add explicit search mode



commit e3c6da3b33308fb08ffeab9ecf6e0fd9609b7486
Author: Jonathan Matthew <jonathan d14n org>
Date:   Sat Sep 10 20:11:25 2011 +1000

    search-entry: add explicit search mode
    
    In explicit search mode, the search entry includes a button rather
    than a label, and only emits the search signal when the button is
    pressed, rather than when the user stops typing.

 widgets/rb-search-entry.c |  141 +++++++++++++++++++++++++++++++++++++++-----
 widgets/rb-search-entry.h |    2 +-
 2 files changed, 126 insertions(+), 17 deletions(-)
---
diff --git a/widgets/rb-search-entry.c b/widgets/rb-search-entry.c
index 3aa4646..a817baa 100644
--- a/widgets/rb-search-entry.c
+++ b/widgets/rb-search-entry.c
@@ -44,6 +44,9 @@ static void rb_search_entry_changed_cb (GtkEditable *editable,
 			                RBSearchEntry *entry);
 static void rb_search_entry_activate_cb (GtkEntry *gtkentry,
 					 RBSearchEntry *entry);
+static void rb_search_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void rb_search_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void button_clicked_cb (GtkButton *button, RBSearchEntry *entry);
 static gboolean rb_search_entry_focus_out_event_cb (GtkWidget *widget,
 				                    GdkEventFocus *event,
 				                    RBSearchEntry *entry);
@@ -51,12 +54,17 @@ static void rb_search_entry_clear_cb (GtkEntry *entry,
 				      GtkEntryIconPosition icon_pos,
 				      GdkEvent *event,
 				      RBSearchEntry *search_entry);
+static void rb_search_entry_check_style (RBSearchEntry *entry);
 
 struct RBSearchEntryPrivate
 {
+	GtkWidget *label;
 	GtkWidget *entry;
+	GtkWidget *button;
 
+	gboolean explicit_mode;
 	gboolean clearing;
+	gboolean searching;
 
 	guint timeout;
 
@@ -88,6 +96,12 @@ enum
 	LAST_SIGNAL
 };
 
+enum
+{
+	PROP_0,
+	PROP_EXPLICIT_MODE
+};
+
 static guint rb_search_entry_signals[LAST_SIGNAL] = { 0 };
 
 static void
@@ -96,6 +110,8 @@ rb_search_entry_class_init (RBSearchEntryClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
 	object_class->finalize = rb_search_entry_finalize;
+	object_class->set_property = rb_search_entry_set_property;
+	object_class->get_property = rb_search_entry_get_property;
 
 	/**
 	 * RBSearchEntry::search:
@@ -135,13 +151,26 @@ rb_search_entry_class_init (RBSearchEntryClass *klass)
 			      1,
 			      G_TYPE_STRING);
 
+	/**
+	 * RBSearchEntry:explicit-mode:
+	 *
+	 * If TRUE, show a button and only emit the 'search' signal when
+	 * the user presses it rather than when they stop typing.
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_EXPLICIT_MODE,
+					 g_param_spec_boolean ("explicit-mode",
+							       "explicit mode",
+							       "whether in explicit search mode or not",
+							       FALSE,
+							       G_PARAM_READWRITE));
+
 	g_type_class_add_private (klass, sizeof (RBSearchEntryPrivate));
 }
 
 static void
 rb_search_entry_init (RBSearchEntry *entry)
 {
-	GtkWidget *label;
 	GtkSettings *settings;
 	char *theme;
 
@@ -154,9 +183,11 @@ rb_search_entry_init (RBSearchEntry *entry)
 	g_free (theme);
 
 	/* this string can only be so long, or there wont be a search entry :) */
-	label = gtk_label_new_with_mnemonic (_("_Search:"));
-	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
-	gtk_box_pack_start (GTK_BOX (entry), label, FALSE, TRUE, 0);
+	entry->priv->label = gtk_label_new_with_mnemonic (_("_Search:"));
+	gtk_label_set_justify (GTK_LABEL (entry->priv->label), GTK_JUSTIFY_RIGHT);
+	gtk_box_pack_start (GTK_BOX (entry), entry->priv->label, FALSE, TRUE, 0);
+	gtk_widget_set_no_show_all (entry->priv->label, TRUE);
+	gtk_widget_show (entry->priv->label);
 
 	entry->priv->entry = gtk_entry_new ();
 	gtk_entry_set_icon_from_stock (GTK_ENTRY (entry->priv->entry),
@@ -170,7 +201,7 @@ rb_search_entry_init (RBSearchEntry *entry)
 				 G_CALLBACK (rb_search_entry_clear_cb),
 				 entry, 0);
 
-	gtk_label_set_mnemonic_widget (GTK_LABEL (label),
+	gtk_label_set_mnemonic_widget (GTK_LABEL (entry->priv->label),
 				       entry->priv->entry);
 
 	gtk_box_pack_start (GTK_BOX (entry), entry->priv->entry, TRUE, TRUE, 0);
@@ -187,6 +218,47 @@ rb_search_entry_init (RBSearchEntry *entry)
 				 "activate",
 				 G_CALLBACK (rb_search_entry_activate_cb),
 				 entry, 0);
+
+	entry->priv->button = gtk_button_new_with_label (_("Search"));
+	gtk_box_pack_start (GTK_BOX (entry), entry->priv->button, FALSE, FALSE, 0);
+	gtk_widget_set_no_show_all (entry->priv->button, TRUE);
+	g_signal_connect_object (entry->priv->button,
+				 "clicked",
+				 G_CALLBACK (button_clicked_cb),
+				 entry, 0);
+}
+
+static void
+rb_search_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	RBSearchEntry *entry = RB_SEARCH_ENTRY (object);
+
+	switch (prop_id) {
+	case PROP_EXPLICIT_MODE:
+		entry->priv->explicit_mode = g_value_get_boolean (value);
+		gtk_widget_set_visible (entry->priv->label, entry->priv->explicit_mode == FALSE);
+		gtk_widget_set_visible (entry->priv->button, entry->priv->explicit_mode == TRUE);
+		rb_search_entry_check_style (entry);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_search_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	RBSearchEntry *entry = RB_SEARCH_ENTRY (object);
+
+	switch (prop_id) {
+	case PROP_EXPLICIT_MODE:
+		g_value_set_boolean (value, entry->priv->explicit_mode);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -270,6 +342,7 @@ rb_search_entry_check_style (RBSearchEntry *entry)
 	GdkRGBA bg_color = {0,};
 	GdkRGBA fg_color = {0,};
 	const gchar* text;
+	gboolean searching;
 
 	if (entry->priv->is_a11y_theme)
 		return;
@@ -286,8 +359,14 @@ rb_search_entry_check_style (RBSearchEntry *entry)
 		fg_color = fallback_fg_color;
 	}
 
-	text = gtk_entry_get_text (GTK_ENTRY (entry->priv->entry));
-	if (text && *text) {
+	if (entry->priv->explicit_mode) {
+		searching = entry->priv->searching;
+	} else {
+		text = gtk_entry_get_text (GTK_ENTRY (entry->priv->entry));
+		searching = (text && *text);
+	}
+
+	if (searching) {
 		gtk_widget_override_color (entry->priv->entry, GTK_STATE_NORMAL, &fg_color);
 		gtk_widget_override_background_color (entry->priv->entry, GTK_STATE_NORMAL, &bg_color);
 		gtk_widget_override_cursor (entry->priv->entry, &fg_color, &fg_color);
@@ -304,10 +383,13 @@ static void
 rb_search_entry_changed_cb (GtkEditable *editable,
 			    RBSearchEntry *entry)
 {
-	rb_search_entry_check_style (entry);
+	const char *text;
 
-	if (entry->priv->clearing == TRUE)
+	if (entry->priv->clearing == TRUE) {
+		entry->priv->searching = FALSE;
+		rb_search_entry_check_style (entry);
 		return;
+	}
 
 	if (entry->priv->timeout != 0) {
 		g_source_remove (entry->priv->timeout);
@@ -315,19 +397,29 @@ rb_search_entry_changed_cb (GtkEditable *editable,
 	}
 
 	/* emit it now if we're clearing the entry */
-	if (gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)))
+	text = gtk_entry_get_text (GTK_ENTRY (entry->priv->entry));
+	if (text != NULL && text[0] != '\0') {
+		gtk_widget_set_sensitive (entry->priv->button, TRUE);
 		entry->priv->timeout = g_timeout_add (300, (GSourceFunc) rb_search_entry_timeout_cb, entry);
-	else
+	} else {
+		entry->priv->searching = FALSE;
+		gtk_widget_set_sensitive (entry->priv->button, FALSE);
 		rb_search_entry_timeout_cb (entry);
+	}
+	rb_search_entry_check_style (entry);
 }
 
 static gboolean
 rb_search_entry_timeout_cb (RBSearchEntry *entry)
 {
+	const char *text;
 	gdk_threads_enter ();
 
-	g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[SEARCH], 0,
-		       gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)));
+	text = gtk_entry_get_text (GTK_ENTRY (entry->priv->entry));
+
+	if (entry->priv->explicit_mode == FALSE) {
+		g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[SEARCH], 0, text);
+	}
 	entry->priv->timeout = 0;
 
 	gdk_threads_leave ();
@@ -346,8 +438,10 @@ rb_search_entry_focus_out_event_cb (GtkWidget *widget,
 	g_source_remove (entry->priv->timeout);
 	entry->priv->timeout = 0;
 
-	g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[SEARCH], 0,
-		       gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)));
+	if (entry->priv->explicit_mode == FALSE) {
+		g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[SEARCH], 0,
+			       gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)));
+	}
 
 	return FALSE;
 }
@@ -363,17 +457,32 @@ rb_search_entry_focus_out_event_cb (GtkWidget *widget,
 gboolean
 rb_search_entry_searching (RBSearchEntry *entry)
 {
-	return strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry->priv->entry))) != 0;
+	if (entry->priv->explicit_mode) {
+		return entry->priv->searching;
+	} else {
+		return strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry->priv->entry))) != 0;
+	}
 }
 
 static void
 rb_search_entry_activate_cb (GtkEntry *gtkentry,
 			     RBSearchEntry *entry)
 {
+	entry->priv->searching = TRUE;
+	rb_search_entry_check_style (entry);
 	g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[ACTIVATE], 0,
 		       gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)));
 }
 
+static void
+button_clicked_cb (GtkButton *button, RBSearchEntry *entry)
+{
+	entry->priv->searching = TRUE;
+	rb_search_entry_check_style (entry);
+	g_signal_emit (G_OBJECT (entry), rb_search_entry_signals[SEARCH], 0,
+		       gtk_entry_get_text (GTK_ENTRY (entry->priv->entry)));
+}
+
 /**
  * rb_search_entry_grab_focus:
  * @entry: a #RBSearchEntry
diff --git a/widgets/rb-search-entry.h b/widgets/rb-search-entry.h
index 4f13a6f..f464a00 100644
--- a/widgets/rb-search-entry.h
+++ b/widgets/rb-search-entry.h
@@ -56,7 +56,7 @@ struct _RBSearchEntryClass
 	GtkHBoxClass parent;
 
 	void (*search) (RBSearchEntry *view, const char *text);
-	void (*activate) (RBSearchEntry *entry);
+	void (*activate) (RBSearchEntry *entry, const char *text);
 };
 
 GType		rb_search_entry_get_type (void);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]