]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/search_entry.c
gtk-demo: Add test of transparent GdkWindows
[~andy/gtk] / demos / gtk-demo / search_entry.c
1 /* Entry/Search Entry
2  *
3  * GtkEntry allows to display icons and progress information.
4  * This demo shows how to use these features in a search entry.
5  */
6
7 #include <gtk/gtk.h>
8
9 static GtkWidget *window = NULL;
10 static GtkWidget *menu = NULL;
11 static GtkWidget *notebook = NULL;
12
13 static guint search_progress_id = 0;
14 static guint finish_search_id = 0;
15
16 static void
17 show_find_button (void)
18 {
19   gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
20 }
21
22 static void
23 show_cancel_button (void)
24 {
25   gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1);
26 }
27
28 static gboolean
29 search_progress (gpointer data)
30 {
31   gtk_entry_progress_pulse (GTK_ENTRY (data));
32
33   return TRUE;
34 }
35
36 static void
37 search_progress_done (GtkEntry *entry)
38 {
39   gtk_entry_set_progress_fraction (entry, 0.0);
40 }
41
42 static gboolean
43 finish_search (GtkButton *button)
44 {
45   show_find_button ();
46   g_source_remove (search_progress_id);
47   search_progress_id = 0;
48
49   return FALSE;
50 }
51
52 static gboolean
53 start_search_feedback (gpointer data)
54 {
55   search_progress_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 100,
56                                            (GSourceFunc)search_progress, data,
57                                            (GDestroyNotify)search_progress_done);
58   return FALSE;
59 }
60
61 static void
62 start_search (GtkButton *button,
63               GtkEntry  *entry)
64 {
65   show_cancel_button ();
66   search_progress_id = g_timeout_add_seconds (1, (GSourceFunc)start_search_feedback, entry);
67   finish_search_id = g_timeout_add_seconds (15, (GSourceFunc)finish_search, button);
68 }
69
70
71 static void
72 stop_search (GtkButton *button,
73              gpointer   data)
74 {
75   g_source_remove (finish_search_id);
76   finish_search (button);
77 }
78
79 static void
80 clear_entry (GtkEntry *entry)
81 {
82   gtk_entry_set_text (entry, "");
83 }
84
85 static void
86 search_by_name (GtkWidget *item,
87                 GtkEntry  *entry)
88 {
89   gtk_entry_set_icon_from_stock (entry,
90                                  GTK_ENTRY_ICON_PRIMARY,
91                                  GTK_STOCK_FIND);
92   gtk_entry_set_icon_tooltip_text (entry,
93                                    GTK_ENTRY_ICON_PRIMARY,
94                                    "Search by name\n"
95                                    "Click here to change the search type");
96   gtk_entry_set_placeholder_text (entry, "name");
97 }
98
99 static void
100 search_by_description (GtkWidget *item,
101                        GtkEntry  *entry)
102 {
103   gtk_entry_set_icon_from_stock (entry,
104                                  GTK_ENTRY_ICON_PRIMARY,
105                                  GTK_STOCK_EDIT);
106   gtk_entry_set_icon_tooltip_text (entry,
107                                    GTK_ENTRY_ICON_PRIMARY,
108                                    "Search by description\n"
109                                    "Click here to change the search type");
110   gtk_entry_set_placeholder_text (entry, "description");
111 }
112
113 static void
114 search_by_file (GtkWidget *item,
115                 GtkEntry  *entry)
116 {
117   gtk_entry_set_icon_from_stock (entry,
118                                  GTK_ENTRY_ICON_PRIMARY,
119                                  GTK_STOCK_OPEN);
120   gtk_entry_set_icon_tooltip_text (entry,
121                                    GTK_ENTRY_ICON_PRIMARY,
122                                    "Search by file name\n"
123                                    "Click here to change the search type");
124   gtk_entry_set_placeholder_text (entry, "file name");
125 }
126
127 GtkWidget *
128 create_search_menu (GtkWidget *entry)
129 {
130   GtkWidget *menu;
131   GtkWidget *item;
132   GtkWidget *image;
133
134   menu = gtk_menu_new ();
135
136   item = gtk_image_menu_item_new_with_mnemonic ("Search by _name");
137   image = gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU);
138   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
139   gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE);
140   g_signal_connect (item, "activate",
141                     G_CALLBACK (search_by_name), entry);
142   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
143
144   item = gtk_image_menu_item_new_with_mnemonic ("Search by _description");
145   image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
146   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
147   gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE);
148   g_signal_connect (item, "activate",
149                     G_CALLBACK (search_by_description), entry);
150   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
151
152   item = gtk_image_menu_item_new_with_mnemonic ("Search by _file name");
153   image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
154   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
155   gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE);
156   g_signal_connect (item, "activate",
157                     G_CALLBACK (search_by_file), entry);
158   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
159
160   gtk_widget_show_all (menu);
161
162   return menu;
163 }
164
165 static void
166 icon_press_cb (GtkEntry       *entry,
167                gint            position,
168                GdkEventButton *event,
169                gpointer        data)
170 {
171   if (position == GTK_ENTRY_ICON_PRIMARY)
172     gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
173                     event->button, event->time);
174   else
175     clear_entry (entry);
176 }
177
178 static void
179 text_changed_cb (GtkEntry   *entry,
180                  GParamSpec *pspec,
181                  GtkWidget  *button)
182 {
183   gboolean has_text;
184
185   has_text = gtk_entry_get_text_length (entry) > 0;
186   gtk_entry_set_icon_sensitive (entry,
187                                 GTK_ENTRY_ICON_SECONDARY,
188                                 has_text);
189   gtk_widget_set_sensitive (button, has_text);
190 }
191
192 static void
193 activate_cb (GtkEntry  *entry,
194              GtkButton *button)
195 {
196   if (search_progress_id != 0)
197     return;
198
199   start_search (button, entry);
200
201 }
202
203 static void
204 search_entry_destroyed (GtkWidget  *widget)
205 {
206   if (finish_search_id != 0)
207     g_source_remove (finish_search_id);
208
209   if (search_progress_id != 0)
210     g_source_remove (search_progress_id);
211
212   window = NULL;
213 }
214
215 static void
216 entry_populate_popup (GtkEntry *entry,
217                       GtkMenu  *menu,
218                       gpointer user_data)
219 {
220   GtkWidget *item;
221   GtkWidget *search_menu;
222   gboolean has_text;
223
224   has_text = gtk_entry_get_text_length (entry) > 0;
225
226   item = gtk_separator_menu_item_new ();
227   gtk_widget_show (item);
228   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
229
230   item = gtk_menu_item_new_with_mnemonic ("C_lear");
231   gtk_widget_show (item);
232   g_signal_connect_swapped (item, "activate",
233                             G_CALLBACK (clear_entry), entry);
234   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
235   gtk_widget_set_sensitive (item, has_text);
236
237   search_menu = create_search_menu (GTK_WIDGET (entry));
238   item = gtk_menu_item_new_with_label ("Search by");
239   gtk_widget_show (item);
240   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), search_menu);
241   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
242 }
243
244 GtkWidget *
245 do_search_entry (GtkWidget *do_widget)
246 {
247   GtkWidget *content_area;
248   GtkWidget *vbox;
249   GtkWidget *hbox;
250   GtkWidget *label;
251   GtkWidget *entry;
252   GtkWidget *button;
253   GtkWidget *find_button;
254   GtkWidget *cancel_button;
255
256   if (!window)
257     {
258       window = gtk_dialog_new_with_buttons ("Search Entry",
259                                             GTK_WINDOW (do_widget),
260                                             0,
261                                             GTK_STOCK_CLOSE,
262                                             GTK_RESPONSE_NONE,
263                                             NULL);
264       gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
265
266       g_signal_connect (window, "response",
267                         G_CALLBACK (gtk_widget_destroy), NULL);
268       g_signal_connect (window, "destroy",
269                         G_CALLBACK (search_entry_destroyed), &window);
270
271       content_area = gtk_dialog_get_content_area (GTK_DIALOG (window));
272
273       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
274       gtk_box_pack_start (GTK_BOX (content_area), vbox, TRUE, TRUE, 0);
275       gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
276
277       label = gtk_label_new (NULL);
278       gtk_label_set_markup (GTK_LABEL (label), "Search entry demo");
279       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
280
281       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
282       gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
283       gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
284
285       /* Create our entry */
286       entry = gtk_entry_new ();
287       gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
288
289       /* Create the find and cancel buttons */
290       notebook = gtk_notebook_new ();
291       gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
292       gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
293       gtk_box_pack_start (GTK_BOX (hbox), notebook, FALSE, FALSE, 0);
294
295       find_button = gtk_button_new_with_label ("Find");
296       g_signal_connect (find_button, "clicked",
297                         G_CALLBACK (start_search), entry);
298       gtk_notebook_append_page (GTK_NOTEBOOK (notebook), find_button, NULL);
299       gtk_widget_show (find_button);
300
301       cancel_button = gtk_button_new_with_label ("Cancel");
302       g_signal_connect (cancel_button, "clicked",
303                         G_CALLBACK (stop_search), NULL);
304       gtk_notebook_append_page (GTK_NOTEBOOK (notebook), cancel_button, NULL);
305       gtk_widget_show (cancel_button);
306
307       /* Set up the search icon */
308       search_by_name (NULL, GTK_ENTRY (entry));
309
310       /* Set up the clear icon */
311       gtk_entry_set_icon_from_stock (GTK_ENTRY (entry),
312                                      GTK_ENTRY_ICON_SECONDARY,
313                                      GTK_STOCK_CLEAR);
314       text_changed_cb (GTK_ENTRY (entry), NULL, find_button);
315
316       g_signal_connect (entry, "icon-press",
317                         G_CALLBACK (icon_press_cb), NULL);
318       g_signal_connect (entry, "notify::text",
319                         G_CALLBACK (text_changed_cb), find_button);
320       g_signal_connect (entry, "activate",
321                         G_CALLBACK (activate_cb), NULL);
322
323       /* Create the menu */
324       menu = create_search_menu (entry);
325       gtk_menu_attach_to_widget (GTK_MENU (menu), entry, NULL);
326
327       /* add accessible alternatives for icon functionality */
328       g_signal_connect (entry, "populate-popup",
329                         G_CALLBACK (entry_populate_popup), NULL);
330
331       /* Give the focus to the close button */
332       button = gtk_dialog_get_widget_for_response (GTK_DIALOG (window), GTK_RESPONSE_NONE);
333       gtk_widget_grab_focus (button);
334     }
335
336   if (!gtk_widget_get_visible (window))
337     gtk_widget_show_all (window);
338   else
339     {
340       gtk_widget_destroy (menu);
341       gtk_widget_destroy (window);
342       window = NULL;
343     }
344
345   return window;
346 }