]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/stock_browser.c
gtk-demo: Remove file lists from demo data
[~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_pixbuf (window,
170                                                            info.id,
171                                                            size);
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       GtkTreeModel *model;
405       GtkCellRenderer *cell_renderer;
406       StockItemDisplay *display;
407       GtkTreeSelection *selection;
408       GtkTreeViewColumn *column;
409
410       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
411       gtk_window_set_screen (GTK_WINDOW (window),
412                              gtk_widget_get_screen (do_widget));
413       gtk_window_set_title (GTK_WINDOW (window), "Stock Icons and Items");
414       gtk_window_set_default_size (GTK_WINDOW (window), -1, 500);
415
416       g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
417       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
418
419       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
420       gtk_container_add (GTK_CONTAINER (window), hbox);
421
422       sw = gtk_scrolled_window_new (NULL, NULL);
423       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
424                                       GTK_POLICY_NEVER,
425                                       GTK_POLICY_AUTOMATIC);
426       gtk_box_pack_start (GTK_BOX (hbox), sw, FALSE, FALSE, 0);
427
428       model = create_model ();
429
430       treeview = gtk_tree_view_new_with_model (model);
431
432       g_object_unref (model);
433
434       gtk_container_add (GTK_CONTAINER (sw), treeview);
435
436       column = gtk_tree_view_column_new ();
437       gtk_tree_view_column_set_title (column, "Macro");
438
439       cell_renderer = gtk_cell_renderer_pixbuf_new ();
440       gtk_tree_view_column_pack_start (column,
441                                        cell_renderer,
442                                        FALSE);
443       gtk_tree_view_column_set_attributes (column, cell_renderer,
444                                            "stock_id", 1, NULL);
445       cell_renderer = gtk_cell_renderer_text_new ();
446       gtk_tree_view_column_pack_start (column,
447                                        cell_renderer,
448                                        TRUE);
449       gtk_tree_view_column_set_cell_data_func (column, cell_renderer,
450                                                macro_set_func_text, NULL, NULL);
451
452       gtk_tree_view_append_column (GTK_TREE_VIEW (treeview),
453                                    column);
454
455       cell_renderer = gtk_cell_renderer_text_new ();
456       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
457                                                   -1,
458                                                   "Label",
459                                                   cell_renderer,
460                                                   label_set_func,
461                                                   NULL,
462                                                   NULL);
463
464       cell_renderer = gtk_cell_renderer_text_new ();
465       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
466                                                   -1,
467                                                   "Accel",
468                                                   cell_renderer,
469                                                   accel_set_func,
470                                                   NULL,
471                                                   NULL);
472
473       cell_renderer = gtk_cell_renderer_text_new ();
474       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
475                                                   -1,
476                                                   "ID",
477                                                   cell_renderer,
478                                                   id_set_func,
479                                                   NULL,
480                                                   NULL);
481
482       frame = gtk_frame_new ("Selected Item");
483       gtk_widget_set_valign (frame, GTK_ALIGN_START);
484       gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
485
486       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
487       gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
488       gtk_container_add (GTK_CONTAINER (frame), vbox);
489
490       display = g_new (StockItemDisplay, 1);
491       g_object_set_data_full (G_OBJECT (treeview),
492                               "stock-display",
493                               display,
494                               g_free); /* free display with treeview */
495
496       display->type_label = gtk_label_new (NULL);
497       display->macro_label = gtk_label_new (NULL);
498       display->id_label = gtk_label_new (NULL);
499       display->label_accel_label = gtk_label_new (NULL);
500       display->icon_image = gtk_image_new_from_pixbuf (NULL); /* empty image */
501
502       gtk_box_pack_start (GTK_BOX (vbox), display->type_label,
503                           FALSE, FALSE, 0);
504
505       gtk_box_pack_start (GTK_BOX (vbox), display->icon_image,
506                           FALSE, FALSE, 0);
507
508       gtk_box_pack_start (GTK_BOX (vbox), display->label_accel_label,
509                           FALSE, FALSE, 0);
510       gtk_box_pack_start (GTK_BOX (vbox), display->macro_label,
511                           FALSE, FALSE, 0);
512       gtk_box_pack_start (GTK_BOX (vbox), display->id_label,
513                           FALSE, FALSE, 0);
514
515       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
516       gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
517
518       g_signal_connect (selection,
519                         "changed",
520                         G_CALLBACK (selection_changed),
521                         NULL);
522     }
523
524   if (!gtk_widget_get_visible (window))
525     {
526       gtk_widget_show_all (window);
527     }
528   else
529     {
530       gtk_widget_destroy (window);
531       window = NULL;
532     }
533
534   return window;
535 }