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