gtk/demos/gtk-demo/search_entry.c
2022-11-28 14:34:55 -05:00

324 lines
8.9 KiB
C

/* Entry/Search Entry
*
* GtkEntry allows to display icons and progress information.
* This demo shows how to use these features in a search entry.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
static GtkWidget *notebook = NULL;
static GSimpleActionGroup *actions = NULL;
static guint search_progress_id = 0;
static guint finish_search_id = 0;
static void
show_find_button (void)
{
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
}
static void
show_cancel_button (void)
{
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1);
}
static gboolean
search_progress (gpointer data)
{
gtk_entry_progress_pulse (GTK_ENTRY (data));
return G_SOURCE_CONTINUE;
}
static void
search_progress_done (GtkEntry *entry)
{
gtk_entry_set_progress_fraction (entry, 0.0);
g_object_unref (entry);
}
static gboolean
finish_search (GtkButton *button)
{
show_find_button ();
if (search_progress_id)
{
g_source_remove (search_progress_id);
search_progress_id = 0;
}
return G_SOURCE_REMOVE;
}
static gboolean
start_search_feedback (gpointer data)
{
gtk_entry_set_progress_fraction (GTK_ENTRY (data), 0.1);
search_progress_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 100,
(GSourceFunc)search_progress, g_object_ref (data),
(GDestroyNotify)search_progress_done);
return G_SOURCE_REMOVE;
}
static void
start_search (GtkButton *button,
GtkEntry *entry)
{
show_cancel_button ();
search_progress_id = g_timeout_add_seconds (1, (GSourceFunc)start_search_feedback, entry);
finish_search_id = g_timeout_add_seconds (15, (GSourceFunc)finish_search, button);
}
static void
stop_search (GtkButton *button,
gpointer data)
{
if (finish_search_id)
{
g_source_remove (finish_search_id);
finish_search_id = 0;
}
finish_search (button);
}
static void
clear_entry (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkEditable *editable = user_data;
gtk_editable_set_text (editable, "");
}
static void
set_search_by (GSimpleAction *action,
GVariant *value,
gpointer user_data)
{
GtkEntry *entry = user_data;
const char *term;
term = g_variant_get_string (value, NULL);
g_simple_action_set_state (action, value);
if (g_str_equal (term, "name"))
{
gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_PRIMARY, "Search by name");
gtk_entry_set_placeholder_text (entry, "Name…");
}
else if (g_str_equal (term, "description"))
{
gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_PRIMARY, "Search by description");
gtk_entry_set_placeholder_text (entry, "Description…");
}
else if (g_str_equal (term, "filename"))
{
gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_PRIMARY, "Search by file name");
gtk_entry_set_placeholder_text (entry, "File name…");
}
}
static void
icon_press_cb (GtkEntry *entry,
int position,
gpointer data)
{
if (position == GTK_ENTRY_ICON_PRIMARY)
{
GAction *action;
GVariant *state;
GVariant *new_state;
const char *s;
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "search-by");
state = g_action_get_state (action);
s = g_variant_get_string (state, NULL);
if (g_str_equal (s, "name"))
new_state = g_variant_new_string ("description");
else if (g_str_equal (s, "description"))
new_state = g_variant_new_string ("filename");
else if (g_str_equal (s, "filename"))
new_state = g_variant_new_string ("name");
else
g_assert_not_reached ();
g_action_change_state (action, new_state);
g_variant_unref (state);
}
}
static void
activate_cb (GtkEntry *entry,
GtkButton *button)
{
if (search_progress_id != 0)
return;
start_search (button, entry);
}
static void
search_entry_destroyed (gpointer data,
GObject *widget)
{
if (finish_search_id != 0)
{
g_source_remove (finish_search_id);
finish_search_id = 0;
}
if (search_progress_id != 0)
{
g_source_remove (search_progress_id);
search_progress_id = 0;
}
window = NULL;
}
static void
text_changed (GObject *object,
GParamSpec *pspec,
gpointer data)
{
GtkEntry *entry = GTK_ENTRY (object);
GActionMap *action_map = data;
GAction *action;
gboolean has_text;
has_text = gtk_entry_get_text_length (entry) > 0;
action = g_action_map_lookup_action (action_map, "clear");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), has_text);
}
static GMenuModel *
create_search_menu_model (void)
{
GMenu *menu = g_menu_new ();
g_menu_append (menu, _("Name"), "search.search-by::name");
g_menu_append (menu, _("Description"), "search.search-by::description");
g_menu_append (menu, _("File Name"), "search.search-by::filename");
return G_MENU_MODEL (menu);
}
static void
entry_add_to_context_menu (GtkEntry *entry)
{
GMenu *menu;
GActionEntry entries[] = {
{ "clear", clear_entry, NULL, NULL, NULL },
{ "search-by", NULL, "s", "'name'", set_search_by }
};
GMenuModel *submenu;
GMenuItem *item;
GAction *action;
GVariant *value;
actions = g_simple_action_group_new ();
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS(entries), entry);
gtk_widget_insert_action_group (GTK_WIDGET (entry), "search", G_ACTION_GROUP (actions));
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "search-by");
value = g_variant_ref_sink (g_variant_new_string ("name"));
set_search_by (G_SIMPLE_ACTION (action), value, entry);
g_variant_unref (value);
menu = g_menu_new ();
item = g_menu_item_new (_("C_lear"), "search.clear");
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-clear-symbolic");
g_menu_append_item (G_MENU (menu), item);
g_object_unref (item);
submenu = create_search_menu_model ();
g_menu_append_submenu (menu, _("Search By"), submenu);
g_object_unref (submenu);
gtk_entry_set_extra_menu (entry, G_MENU_MODEL (menu));
g_object_unref (menu);
g_signal_connect (entry, "notify::text", G_CALLBACK (text_changed), actions);
}
GtkWidget *
do_search_entry (GtkWidget *do_widget)
{
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *entry;
GtkWidget *find_button;
GtkWidget *cancel_button;
if (!window)
{
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Search Entry");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_weak_ref (G_OBJECT (window), search_entry_destroyed, &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_widget_set_margin_start (vbox, 18);
gtk_widget_set_margin_end (vbox, 18);
gtk_widget_set_margin_top (vbox, 18);
gtk_widget_set_margin_bottom (vbox, 18);
gtk_window_set_child (GTK_WINDOW (window), vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_box_append (GTK_BOX (vbox), hbox);
/* Create our entry */
entry = gtk_entry_new ();
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
GTK_ENTRY_ICON_PRIMARY,
"edit-find-symbolic");
gtk_box_append (GTK_BOX (hbox), entry);
/* Create the find and cancel buttons */
notebook = gtk_notebook_new ();
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
gtk_box_append (GTK_BOX (hbox), notebook);
find_button = gtk_button_new_with_label ("Find");
g_signal_connect (find_button, "clicked",
G_CALLBACK (start_search), entry);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), find_button, NULL);
cancel_button = gtk_button_new_with_label ("Cancel");
g_signal_connect (cancel_button, "clicked",
G_CALLBACK (stop_search), NULL);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), cancel_button, NULL);
/* Set up the search icon */
gtk_entry_set_icon_activatable (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, TRUE);
gtk_entry_set_icon_sensitive (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, TRUE);
g_signal_connect (entry, "icon-press", G_CALLBACK (icon_press_cb), NULL);
g_signal_connect (entry, "activate", G_CALLBACK (activate_cb), NULL);
/* add accessible alternatives for icon functionality */
entry_add_to_context_menu (GTK_ENTRY (entry));
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
else
{
g_clear_object (&actions);
gtk_window_destroy (GTK_WINDOW (window));
}
return window;
}