]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/stock_browser.c
Update to use the new g_boxed_type_register_static API.
[~andy/gtk] / demos / gtk-demo / stock_browser.c
1 /* Stock Item/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 (G_OBJECT (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 (G_OBJECT (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 /* columns in the tree model */
85 enum {
86   COLUMN_ICON_MACRO,
87   COLUMN_LABEL,
88   COLUMN_ACCEL,
89   COLUMN_ID
90 };
91
92 static gchar*
93 id_to_macro (const gchar *id)
94 {
95   GString *macro;
96   const gchar *cp;
97   gchar *p;
98
99   /* gtk-foo -> GTK_STOCK_FOO */
100   
101   cp = id;
102   while (*cp && *cp != '-')
103     ++cp;
104
105   if (*cp == '\0')
106     return g_strdup ("??UNKNOWN??");
107
108   macro = g_string_new (NULL);
109   
110   g_string_append_len (macro, id, cp - id);
111   
112   g_string_append (macro, "_STOCK");
113   g_string_append (macro, cp);
114
115   p = macro->str;
116   while (*p)
117     {
118       if (*p == '-')
119         *p = '_';
120       ++p;
121     }
122
123   g_ascii_strup (macro->str);
124   
125   return g_string_free (macro, FALSE);
126 }
127
128 static GtkTreeModel*
129 create_model (void)
130 {
131   GtkListStore *store;
132   GSList *ids;
133   GSList *tmp_list;
134   
135   store = gtk_list_store_new (1, STOCK_ITEM_INFO_TYPE);
136
137   ids = gtk_stock_list_ids ();
138   ids = g_slist_sort (ids, (GCompareFunc) strcmp);
139   tmp_list = ids;
140   while (tmp_list != NULL)
141     {
142       StockItemInfo info;
143       GtkStockItem item;
144       GtkTreeIter iter;
145       GtkIconSet *icon_set;
146       
147       info.id = tmp_list->data;
148       
149       if (gtk_stock_lookup (info.id, &item))
150         {
151           info.item = item;
152         }
153       else
154         {
155           info.item.label = NULL;
156           info.item.stock_id = NULL;
157           info.item.modifier = 0;
158           info.item.keyval = 0;
159           info.item.translation_domain = NULL;
160         }
161
162       /* only show icons for stock IDs that have default icons */
163       icon_set = gtk_icon_factory_lookup_default (info.id);
164       if (icon_set)
165         {
166           GtkIconSize *sizes = NULL;
167           gint n_sizes = 0;
168           gint i;
169           GtkIconSize size;
170
171           /* See what sizes this stock icon really exists at */
172           gtk_icon_set_get_sizes (icon_set, &sizes, &n_sizes);
173
174           /* Use menu size if it exists, otherwise first size found */
175           size = sizes[0];
176           i = 0;
177           while (i < n_sizes)
178             {
179               if (sizes[i] == GTK_ICON_SIZE_MENU)
180                 {
181                   size = GTK_ICON_SIZE_MENU;
182                   break;
183                 }
184               ++i;
185             }
186           g_free (sizes);
187           
188           info.small_icon = gtk_widget_render_icon (window, info.id,
189                                                     size,
190                                                     NULL);
191           
192           if (size != GTK_ICON_SIZE_MENU)
193             {
194               /* Make the result the proper size for our thumbnail */
195               gint w, h;
196               GdkPixbuf *scaled;
197               
198               gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
199               
200               scaled = gdk_pixbuf_scale_simple (info.small_icon,
201                                                 w, h,
202                                                 GDK_INTERP_BILINEAR);
203
204               g_object_unref (G_OBJECT (info.small_icon));
205               info.small_icon = scaled;
206             }
207         }
208       else
209         info.small_icon = NULL;
210
211       if (info.item.keyval != 0)
212         {
213           info.accel_str = gtk_accelerator_name (info.item.keyval,
214                                                  info.item.modifier);
215         }
216       else
217         {
218           info.accel_str = g_strdup ("");
219         }
220
221       info.macro = id_to_macro (info.id);
222       
223       gtk_list_store_append (store, &iter);
224       gtk_list_store_set (store, &iter, 0, &info, -1);
225
226       g_free (info.macro);
227       g_free (info.accel_str);
228       if (info.small_icon)
229         g_object_unref (G_OBJECT (info.small_icon));
230       
231       tmp_list = g_slist_next (tmp_list);
232     }
233   
234   g_slist_foreach (ids, (GFunc)g_free, NULL);
235   g_slist_free (ids);
236
237   return GTK_TREE_MODEL (store);
238 }
239
240 static void
241 selection_changed (GtkTreeSelection *selection)
242 {
243   GtkTreeView *treeview;
244   StockItemDisplay *display;
245   GtkTreeModel *model;
246   GtkTreeIter iter;
247   
248   treeview = gtk_tree_selection_get_tree_view (selection);
249   display = g_object_get_data (G_OBJECT (treeview), "stock-display");
250
251   if (gtk_tree_selection_get_selected (selection, &model, &iter))
252     {
253       StockItemInfo *info;
254       gchar *str;
255       
256       gtk_tree_model_get (model, &iter,
257                           0, &info,
258                           -1);
259
260       if (info->small_icon && info->item.label)
261         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon and Item");
262       else if (info->small_icon)
263         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon Only");
264       else if (info->item.label)
265         gtk_label_set_text (GTK_LABEL (display->type_label), "Item Only");
266       else
267         gtk_label_set_text (GTK_LABEL (display->type_label), "???????");
268
269       gtk_label_set_text (GTK_LABEL (display->macro_label), info->macro);
270       gtk_label_set_text (GTK_LABEL (display->id_label), info->id);
271
272       if (info->item.label)
273         {
274           str = g_strdup_printf ("%s %s", info->item.label, info->accel_str);
275           gtk_label_set_text_with_mnemonic (GTK_LABEL (display->label_accel_label), str);
276           g_free (str);
277         }
278       else
279         {
280           gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
281         }
282
283       /* The problem here is that some icons don't have SIZE_LARGE_TOOLBAR,
284        * so we get a "missing image" icon...
285        */
286       if (info->small_icon)
287         gtk_image_set_from_stock (GTK_IMAGE (display->icon_image), info->id,
288                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
289       else
290         gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
291
292       stock_item_info_free (info);
293     }
294   else
295     {
296       gtk_label_set_text (GTK_LABEL (display->type_label), "No selected item");
297       gtk_label_set_text (GTK_LABEL (display->macro_label), "");
298       gtk_label_set_text (GTK_LABEL (display->id_label), "");
299       gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
300       gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
301     }
302 }
303
304 static void
305 macro_set_func_text (GtkTreeViewColumn *tree_column,
306                      GtkCellRenderer   *cell,
307                      GtkTreeModel      *model,
308                      GtkTreeIter       *iter,
309                      gpointer           data)
310 {
311   StockItemInfo *info;
312   
313   gtk_tree_model_get (model, iter,
314                       0, &info,
315                       -1);
316   
317   g_object_set (GTK_CELL_RENDERER (cell),
318                 "text", info->macro,
319                 NULL);
320   
321   stock_item_info_free (info);
322 }
323
324 static void
325 macro_set_func_pixbuf (GtkTreeViewColumn *tree_column,
326                        GtkCellRenderer   *cell,
327                        GtkTreeModel      *model,
328                        GtkTreeIter       *iter,
329                        gpointer           data)
330 {
331   StockItemInfo *info;
332   
333   gtk_tree_model_get (model, iter,
334                       0, &info,
335                       -1);
336   
337   g_object_set (GTK_CELL_RENDERER (cell),
338                 "pixbuf", info->small_icon,
339                 NULL);
340   
341   stock_item_info_free (info);
342 }
343
344 static void
345 id_set_func (GtkTreeViewColumn *tree_column,
346              GtkCellRenderer   *cell,
347              GtkTreeModel      *model,
348              GtkTreeIter       *iter,
349              gpointer           data)
350 {
351   StockItemInfo *info;
352   
353   gtk_tree_model_get (model, iter,
354                       0, &info,
355                       -1);
356   
357   g_object_set (GTK_CELL_RENDERER (cell),
358                 "text", info->id,
359                 NULL);
360   
361   stock_item_info_free (info);
362 }
363
364 static void
365 accel_set_func (GtkTreeViewColumn *tree_column,
366                 GtkCellRenderer   *cell,
367                 GtkTreeModel      *model,
368                 GtkTreeIter       *iter,
369                 gpointer           data)
370 {
371   StockItemInfo *info;
372   
373   gtk_tree_model_get (model, iter,
374                       0, &info,
375                       -1);
376   
377   g_object_set (GTK_CELL_RENDERER (cell),
378                 "text", info->accel_str,
379                 NULL);
380   
381   stock_item_info_free (info);
382 }
383
384 static void
385 label_set_func (GtkTreeViewColumn *tree_column,
386                 GtkCellRenderer   *cell,
387                 GtkTreeModel      *model,
388                 GtkTreeIter       *iter,
389                 gpointer           data)
390 {
391   StockItemInfo *info;
392   
393   gtk_tree_model_get (model, iter,
394                       0, &info,
395                       -1);
396   
397   g_object_set (GTK_CELL_RENDERER (cell),
398                 "text", info->item.label,
399                 NULL);
400   
401   stock_item_info_free (info);
402 }
403
404 GtkWidget *
405 do_stock_browser (void)
406 {  
407   if (!window)
408     {
409       GtkWidget *frame;
410       GtkWidget *vbox;
411       GtkWidget *hbox;
412       GtkWidget *sw;
413       GtkWidget *treeview;
414       GtkWidget *align;
415       GtkTreeModel *model;
416       GtkCellRenderer *cell_renderer;
417       StockItemDisplay *display;
418       GtkTreeSelection *selection;
419       GtkTreeViewColumn *column;
420
421       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
422       gtk_window_set_title (GTK_WINDOW (window), "Stock Icons and Items");
423
424       gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroyed), &window);
425       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
426
427       hbox = gtk_hbox_new (FALSE, 8);
428       gtk_container_add (GTK_CONTAINER (window), hbox);
429
430       sw = gtk_scrolled_window_new (NULL, NULL);
431       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
432                                       GTK_POLICY_NEVER,
433                                       GTK_POLICY_AUTOMATIC);
434       gtk_box_pack_start (GTK_BOX (hbox), sw, FALSE, FALSE, 0);
435
436       model = create_model ();
437       
438       treeview = gtk_tree_view_new_with_model (model);
439
440       g_object_unref (G_OBJECT (model));
441
442       gtk_container_add (GTK_CONTAINER (sw), treeview);
443       
444       column = gtk_tree_view_column_new ();
445       gtk_tree_view_column_set_title (column, "Macro");
446
447       cell_renderer = gtk_cell_renderer_pixbuf_new ();
448       gtk_tree_view_column_pack_start (column,
449                                        cell_renderer,
450                                        FALSE);
451       gtk_tree_view_column_set_cell_data_func (column, cell_renderer,
452                                                macro_set_func_pixbuf, NULL, NULL);
453       cell_renderer = gtk_cell_renderer_text_new ();
454       gtk_tree_view_column_pack_start (column,
455                                        cell_renderer,
456                                        TRUE);
457       gtk_tree_view_column_set_cell_data_func (column, cell_renderer,
458                                                macro_set_func_text, NULL, NULL);
459
460       gtk_tree_view_append_column (GTK_TREE_VIEW (treeview),
461                                    column);
462
463       cell_renderer = gtk_cell_renderer_text_new ();
464
465       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
466                                                   -1,
467                                                   "Label",
468                                                   cell_renderer,
469                                                   label_set_func,
470                                                   NULL,
471                                                   NULL);
472
473       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
474                                                   -1,
475                                                   "Accel",
476                                                   cell_renderer,
477                                                   accel_set_func,
478                                                   NULL,
479                                                   NULL);
480
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 (G_OBJECT (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 }