]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/stock_browser.c
add deprecation compile flags
[~andy/gtk] / demos / gtk-demo / stock_browser.c
1 /* Stock Item and Icon Browser
2  *
3  * This source code for this demo doesn't demonstrate anything
4  * particularly useful in applications. The purpose of the "demo" is
5  * just to provide a handy place to browse the available stock icons
6  * and stock items.
7  */
8
9 #include <string.h>
10
11 #include <gtk/gtk.h>
12
13 static GtkWidget *window = NULL;
14
15 typedef struct _StockItemInfo StockItemInfo;
16 struct _StockItemInfo
17 {
18   gchar *id;
19   GtkStockItem item;
20   GdkPixbuf *small_icon;
21   gchar *macro;
22   gchar *accel_str;
23 };
24
25 /* Make StockItemInfo a boxed type so we can automatically
26  * manage memory
27  */
28 #define STOCK_ITEM_INFO_TYPE stock_item_info_get_type ()
29
30 static void
31 stock_item_info_free (StockItemInfo *info)
32 {
33   g_free (info->id);
34   g_free (info->macro);
35   g_free (info->accel_str);
36   if (info->small_icon)
37     g_object_unref (info->small_icon);
38   
39   g_free (info);
40 }
41
42 static StockItemInfo*
43 stock_item_info_copy (StockItemInfo *src)
44 {
45   StockItemInfo *info;
46
47   info = g_new (StockItemInfo, 1);
48   info->id = g_strdup (src->id);
49   info->macro = g_strdup (src->macro);
50   info->accel_str = g_strdup (src->accel_str);
51   
52   info->item = src->item;
53
54   info->small_icon = src->small_icon;
55   if (info->small_icon)
56     g_object_ref (info->small_icon);
57
58   return info;
59 }
60
61 static GType
62 stock_item_info_get_type (void)
63 {
64   static GType our_type = 0;
65   
66   if (our_type == 0)
67     our_type = g_boxed_type_register_static ("StockItemInfo",
68                                              (GBoxedCopyFunc) stock_item_info_copy,
69                                              (GBoxedFreeFunc) stock_item_info_free);
70
71   return our_type;
72 }
73
74 typedef struct _StockItemDisplay StockItemDisplay;
75 struct _StockItemDisplay
76 {
77   GtkWidget *type_label;
78   GtkWidget *macro_label;
79   GtkWidget *id_label;
80   GtkWidget *label_accel_label;
81   GtkWidget *icon_image;
82 };
83
84 static gchar*
85 id_to_macro (const gchar *id)
86 {
87   GString *macro = NULL;
88   const gchar *cp;
89
90   /* gtk-foo-bar -> GTK_STOCK_FOO_BAR */
91
92   macro = g_string_new (NULL);
93   
94   cp = id;
95   
96   if (strncmp (cp, "gtk-", 4) == 0)
97     {
98       g_string_append (macro, "GTK_STOCK_");
99       cp += 4;
100     }
101
102   while (*cp)
103     {
104       if (*cp == '-')
105         g_string_append_c (macro, '_');
106       else if (g_ascii_islower (*cp))
107         g_string_append_c (macro, g_ascii_toupper (*cp));
108       else
109         g_string_append_c (macro, *cp);
110
111       cp++;
112     }
113
114   return g_string_free (macro, FALSE);
115 }
116
117 static GtkTreeModel*
118 create_model (void)
119 {
120   GtkListStore *store;
121   GSList *ids;
122   GSList *tmp_list;
123   
124   store = gtk_list_store_new (2, STOCK_ITEM_INFO_TYPE, G_TYPE_STRING);
125
126   ids = gtk_stock_list_ids ();
127   ids = g_slist_sort (ids, (GCompareFunc) strcmp);
128   tmp_list = ids;
129   while (tmp_list != NULL)
130     {
131       StockItemInfo info;
132       GtkStockItem item;
133       GtkTreeIter iter;
134       GtkIconSet *icon_set;
135       
136       info.id = tmp_list->data;
137       
138       if (gtk_stock_lookup (info.id, &item))
139         {
140           info.item = item;
141         }
142       else
143         {
144           info.item.label = NULL;
145           info.item.stock_id = NULL;
146           info.item.modifier = 0;
147           info.item.keyval = 0;
148           info.item.translation_domain = NULL;
149         }
150
151       /* only show icons for stock IDs that have default icons */
152       icon_set = gtk_icon_factory_lookup_default (info.id);
153       if (icon_set)
154         {
155           GtkIconSize *sizes = NULL;
156           gint n_sizes = 0;
157           gint i;
158           GtkIconSize size;
159
160           /* See what sizes this stock icon really exists at */
161           gtk_icon_set_get_sizes (icon_set, &sizes, &n_sizes);
162
163           /* Use menu size if it exists, otherwise first size found */
164           size = sizes[0];
165           i = 0;
166           while (i < n_sizes)
167             {
168               if (sizes[i] == GTK_ICON_SIZE_MENU)
169                 {
170                   size = GTK_ICON_SIZE_MENU;
171                   break;
172                 }
173               ++i;
174             }
175           g_free (sizes);
176           
177           info.small_icon = gtk_widget_render_icon (window, info.id,
178                                                     size,
179                                                     NULL);
180           
181           if (size != GTK_ICON_SIZE_MENU)
182             {
183               /* Make the result the proper size for our thumbnail */
184               gint w, h;
185               GdkPixbuf *scaled;
186               
187               gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
188               
189               scaled = gdk_pixbuf_scale_simple (info.small_icon,
190                                                 w, h,
191                                                 GDK_INTERP_BILINEAR);
192
193               g_object_unref (info.small_icon);
194               info.small_icon = scaled;
195             }
196         }
197       else
198         info.small_icon = NULL;
199
200       if (info.item.keyval != 0)
201         {
202           info.accel_str = gtk_accelerator_name (info.item.keyval,
203                                                  info.item.modifier);
204         }
205       else
206         {
207           info.accel_str = g_strdup ("");
208         }
209
210       info.macro = id_to_macro (info.id);
211       
212       gtk_list_store_append (store, &iter);
213       gtk_list_store_set (store, &iter, 0, &info, 1, info.id, -1);
214
215       g_free (info.macro);
216       g_free (info.accel_str);
217       if (info.small_icon)
218         g_object_unref (info.small_icon);
219       
220       tmp_list = g_slist_next (tmp_list);
221     }
222   
223   g_slist_foreach (ids, (GFunc)g_free, NULL);
224   g_slist_free (ids);
225
226   return GTK_TREE_MODEL (store);
227 }
228
229 /* Finds the largest size at which the given image stock id is
230  * available. This would not be useful for a normal application
231  */
232 static GtkIconSize
233 get_largest_size (const char *id)
234 {
235   GtkIconSet *set = gtk_icon_factory_lookup_default (id);
236   GtkIconSize *sizes;
237   gint n_sizes, i;
238   GtkIconSize best_size = GTK_ICON_SIZE_INVALID;
239   gint best_pixels = 0;
240
241   gtk_icon_set_get_sizes (set, &sizes, &n_sizes);
242
243   for (i = 0; i < n_sizes; i++)
244     {
245       gint width, height;
246       
247       gtk_icon_size_lookup (sizes[i], &width, &height);
248
249       if (width * height > best_pixels)
250         {
251           best_size = sizes[i];
252           best_pixels = width * height;
253         }
254     }
255   
256   g_free (sizes);
257
258   return best_size;
259 }
260
261 static void
262 selection_changed (GtkTreeSelection *selection)
263 {
264   GtkTreeView *treeview;
265   StockItemDisplay *display;
266   GtkTreeModel *model;
267   GtkTreeIter iter;
268   
269   treeview = gtk_tree_selection_get_tree_view (selection);
270   display = g_object_get_data (G_OBJECT (treeview), "stock-display");
271
272   if (gtk_tree_selection_get_selected (selection, &model, &iter))
273     {
274       StockItemInfo *info;
275       gchar *str;
276       
277       gtk_tree_model_get (model, &iter,
278                           0, &info,
279                           -1);
280
281       if (info->small_icon && info->item.label)
282         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon and Item");
283       else if (info->small_icon)
284         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon Only");
285       else if (info->item.label)
286         gtk_label_set_text (GTK_LABEL (display->type_label), "Item Only");
287       else
288         gtk_label_set_text (GTK_LABEL (display->type_label), "???????");
289
290       gtk_label_set_text (GTK_LABEL (display->macro_label), info->macro);
291       gtk_label_set_text (GTK_LABEL (display->id_label), info->id);
292
293       if (info->item.label)
294         {
295           str = g_strdup_printf ("%s %s", info->item.label, info->accel_str);
296           gtk_label_set_text_with_mnemonic (GTK_LABEL (display->label_accel_label), str);
297           g_free (str);
298         }
299       else
300         {
301           gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
302         }
303
304       if (info->small_icon)
305         gtk_image_set_from_stock (GTK_IMAGE (display->icon_image), info->id,
306                                   get_largest_size (info->id));
307       else
308         gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
309
310       stock_item_info_free (info);
311     }
312   else
313     {
314       gtk_label_set_text (GTK_LABEL (display->type_label), "No selected item");
315       gtk_label_set_text (GTK_LABEL (display->macro_label), "");
316       gtk_label_set_text (GTK_LABEL (display->id_label), "");
317       gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
318       gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
319     }
320 }
321
322 static void
323 macro_set_func_text (GtkTreeViewColumn *tree_column,
324                      GtkCellRenderer   *cell,
325                      GtkTreeModel      *model,
326                      GtkTreeIter       *iter,
327                      gpointer           data)
328 {
329   StockItemInfo *info;
330   
331   gtk_tree_model_get (model, iter,
332                       0, &info,
333                       -1);
334   
335   g_object_set (GTK_CELL_RENDERER (cell),
336                 "text", info->macro,
337                 NULL);
338   
339   stock_item_info_free (info);
340 }
341
342 static void
343 id_set_func (GtkTreeViewColumn *tree_column,
344              GtkCellRenderer   *cell,
345              GtkTreeModel      *model,
346              GtkTreeIter       *iter,
347              gpointer           data)
348 {
349   StockItemInfo *info;
350   
351   gtk_tree_model_get (model, iter,
352                       0, &info,
353                       -1);
354   
355   g_object_set (GTK_CELL_RENDERER (cell),
356                 "text", info->id,
357                 NULL);
358   
359   stock_item_info_free (info);
360 }
361
362 static void
363 accel_set_func (GtkTreeViewColumn *tree_column,
364                 GtkCellRenderer   *cell,
365                 GtkTreeModel      *model,
366                 GtkTreeIter       *iter,
367                 gpointer           data)
368 {
369   StockItemInfo *info;
370   
371   gtk_tree_model_get (model, iter,
372                       0, &info,
373                       -1);
374   
375   g_object_set (GTK_CELL_RENDERER (cell),
376                 "text", info->accel_str,
377                 NULL);
378   
379   stock_item_info_free (info);
380 }
381
382 static void
383 label_set_func (GtkTreeViewColumn *tree_column,
384                 GtkCellRenderer   *cell,
385                 GtkTreeModel      *model,
386                 GtkTreeIter       *iter,
387                 gpointer           data)
388 {
389   StockItemInfo *info;
390   
391   gtk_tree_model_get (model, iter,
392                       0, &info,
393                       -1);
394   
395   g_object_set (GTK_CELL_RENDERER (cell),
396                 "text", info->item.label,
397                 NULL);
398   
399   stock_item_info_free (info);
400 }
401
402 GtkWidget *
403 do_stock_browser (void)
404 {  
405   if (!window)
406     {
407       GtkWidget *frame;
408       GtkWidget *vbox;
409       GtkWidget *hbox;
410       GtkWidget *sw;
411       GtkWidget *treeview;
412       GtkWidget *align;
413       GtkTreeModel *model;
414       GtkCellRenderer *cell_renderer;
415       StockItemDisplay *display;
416       GtkTreeSelection *selection;
417       GtkTreeViewColumn *column;
418
419       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
420       gtk_window_set_title (GTK_WINDOW (window), "Stock Icons and Items");
421       gtk_window_set_default_size (GTK_WINDOW (window), -1, 500);
422
423       g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
424       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
425
426       hbox = gtk_hbox_new (FALSE, 8);
427       gtk_container_add (GTK_CONTAINER (window), hbox);
428
429       sw = gtk_scrolled_window_new (NULL, NULL);
430       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
431                                       GTK_POLICY_NEVER,
432                                       GTK_POLICY_AUTOMATIC);
433       gtk_box_pack_start (GTK_BOX (hbox), sw, FALSE, FALSE, 0);
434
435       model = create_model ();
436       
437       treeview = gtk_tree_view_new_with_model (model);
438
439       g_object_unref (model);
440
441       gtk_container_add (GTK_CONTAINER (sw), treeview);
442       
443       column = gtk_tree_view_column_new ();
444       gtk_tree_view_column_set_title (column, "Macro");
445
446       cell_renderer = gtk_cell_renderer_pixbuf_new ();
447       gtk_tree_view_column_pack_start (column,
448                                        cell_renderer,
449                                        FALSE);
450       gtk_tree_view_column_set_attributes (column, cell_renderer,
451                                            "stock_id", 1, NULL);
452       cell_renderer = gtk_cell_renderer_text_new ();
453       gtk_tree_view_column_pack_start (column,
454                                        cell_renderer,
455                                        TRUE);
456       gtk_tree_view_column_set_cell_data_func (column, cell_renderer,
457                                                macro_set_func_text, NULL, NULL);
458
459       gtk_tree_view_append_column (GTK_TREE_VIEW (treeview),
460                                    column);
461
462       cell_renderer = gtk_cell_renderer_text_new ();
463       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
464                                                   -1,
465                                                   "Label",
466                                                   cell_renderer,
467                                                   label_set_func,
468                                                   NULL,
469                                                   NULL);
470
471       cell_renderer = gtk_cell_renderer_text_new ();
472       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
473                                                   -1,
474                                                   "Accel",
475                                                   cell_renderer,
476                                                   accel_set_func,
477                                                   NULL,
478                                                   NULL);
479
480       cell_renderer = gtk_cell_renderer_text_new ();
481       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
482                                                   -1,
483                                                   "ID",
484                                                   cell_renderer,
485                                                   id_set_func,
486                                                   NULL,
487                                                   NULL);
488       
489       align = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
490       gtk_box_pack_end (GTK_BOX (hbox), align, FALSE, FALSE, 0);
491       
492       frame = gtk_frame_new ("Selected Item");
493       gtk_container_add (GTK_CONTAINER (align), frame);
494
495       vbox = gtk_vbox_new (FALSE, 8);
496       gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
497       gtk_container_add (GTK_CONTAINER (frame), vbox);
498
499       display = g_new (StockItemDisplay, 1);
500       g_object_set_data_full (G_OBJECT (treeview),
501                               "stock-display",
502                               display,
503                               g_free); /* free display with treeview */
504       
505       display->type_label = gtk_label_new (NULL);
506       display->macro_label = gtk_label_new (NULL);
507       display->id_label = gtk_label_new (NULL);
508       display->label_accel_label = gtk_label_new (NULL);
509       display->icon_image = gtk_image_new_from_pixbuf (NULL); /* empty image */
510
511       gtk_box_pack_start (GTK_BOX (vbox), display->type_label,
512                           FALSE, FALSE, 0);
513
514       gtk_box_pack_start (GTK_BOX (vbox), display->icon_image,
515                           FALSE, FALSE, 0);
516       
517       gtk_box_pack_start (GTK_BOX (vbox), display->label_accel_label,
518                           FALSE, FALSE, 0);
519       gtk_box_pack_start (GTK_BOX (vbox), display->macro_label,
520                           FALSE, FALSE, 0);
521       gtk_box_pack_start (GTK_BOX (vbox), display->id_label,
522                           FALSE, FALSE, 0);
523
524       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
525       gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
526       
527       g_signal_connect (selection,
528                         "changed",
529                         G_CALLBACK (selection_changed),
530                         NULL);
531     }
532
533   if (!GTK_WIDGET_VISIBLE (window))
534     {
535       gtk_widget_show_all (window);
536     }
537   else
538     {    
539       gtk_widget_destroy (window);
540       window = NULL;
541     }
542
543   return window;
544 }