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