]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/stock_browser.c
demos/gtk-demo/stock_browser.c (id_to_macro): make the uppercasing work. (#59550)
[~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       *p = g_ascii_toupper (*p);
119       if (*p == '-')
120         *p = '_';
121       ++p;
122     }
123
124   return g_string_free (macro, FALSE);
125 }
126
127 static GtkTreeModel*
128 create_model (void)
129 {
130   GtkListStore *store;
131   GSList *ids;
132   GSList *tmp_list;
133   
134   store = gtk_list_store_new (1, STOCK_ITEM_INFO_TYPE);
135
136   ids = gtk_stock_list_ids ();
137   ids = g_slist_sort (ids, (GCompareFunc) strcmp);
138   tmp_list = ids;
139   while (tmp_list != NULL)
140     {
141       StockItemInfo info;
142       GtkStockItem item;
143       GtkTreeIter iter;
144       GtkIconSet *icon_set;
145       
146       info.id = tmp_list->data;
147       
148       if (gtk_stock_lookup (info.id, &item))
149         {
150           info.item = item;
151         }
152       else
153         {
154           info.item.label = NULL;
155           info.item.stock_id = NULL;
156           info.item.modifier = 0;
157           info.item.keyval = 0;
158           info.item.translation_domain = NULL;
159         }
160
161       /* only show icons for stock IDs that have default icons */
162       icon_set = gtk_icon_factory_lookup_default (info.id);
163       if (icon_set)
164         {
165           GtkIconSize *sizes = NULL;
166           gint n_sizes = 0;
167           gint i;
168           GtkIconSize size;
169
170           /* See what sizes this stock icon really exists at */
171           gtk_icon_set_get_sizes (icon_set, &sizes, &n_sizes);
172
173           /* Use menu size if it exists, otherwise first size found */
174           size = sizes[0];
175           i = 0;
176           while (i < n_sizes)
177             {
178               if (sizes[i] == GTK_ICON_SIZE_MENU)
179                 {
180                   size = GTK_ICON_SIZE_MENU;
181                   break;
182                 }
183               ++i;
184             }
185           g_free (sizes);
186           
187           info.small_icon = gtk_widget_render_icon (window, info.id,
188                                                     size,
189                                                     NULL);
190           
191           if (size != GTK_ICON_SIZE_MENU)
192             {
193               /* Make the result the proper size for our thumbnail */
194               gint w, h;
195               GdkPixbuf *scaled;
196               
197               gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
198               
199               scaled = gdk_pixbuf_scale_simple (info.small_icon,
200                                                 w, h,
201                                                 GDK_INTERP_BILINEAR);
202
203               g_object_unref (G_OBJECT (info.small_icon));
204               info.small_icon = scaled;
205             }
206         }
207       else
208         info.small_icon = NULL;
209
210       if (info.item.keyval != 0)
211         {
212           info.accel_str = gtk_accelerator_name (info.item.keyval,
213                                                  info.item.modifier);
214         }
215       else
216         {
217           info.accel_str = g_strdup ("");
218         }
219
220       info.macro = id_to_macro (info.id);
221       
222       gtk_list_store_append (store, &iter);
223       gtk_list_store_set (store, &iter, 0, &info, -1);
224
225       g_free (info.macro);
226       g_free (info.accel_str);
227       if (info.small_icon)
228         g_object_unref (G_OBJECT (info.small_icon));
229       
230       tmp_list = g_slist_next (tmp_list);
231     }
232   
233   g_slist_foreach (ids, (GFunc)g_free, NULL);
234   g_slist_free (ids);
235
236   return GTK_TREE_MODEL (store);
237 }
238
239 static void
240 selection_changed (GtkTreeSelection *selection)
241 {
242   GtkTreeView *treeview;
243   StockItemDisplay *display;
244   GtkTreeModel *model;
245   GtkTreeIter iter;
246   
247   treeview = gtk_tree_selection_get_tree_view (selection);
248   display = g_object_get_data (G_OBJECT (treeview), "stock-display");
249
250   if (gtk_tree_selection_get_selected (selection, &model, &iter))
251     {
252       StockItemInfo *info;
253       gchar *str;
254       
255       gtk_tree_model_get (model, &iter,
256                           0, &info,
257                           -1);
258
259       if (info->small_icon && info->item.label)
260         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon and Item");
261       else if (info->small_icon)
262         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon Only");
263       else if (info->item.label)
264         gtk_label_set_text (GTK_LABEL (display->type_label), "Item Only");
265       else
266         gtk_label_set_text (GTK_LABEL (display->type_label), "???????");
267
268       gtk_label_set_text (GTK_LABEL (display->macro_label), info->macro);
269       gtk_label_set_text (GTK_LABEL (display->id_label), info->id);
270
271       if (info->item.label)
272         {
273           str = g_strdup_printf ("%s %s", info->item.label, info->accel_str);
274           gtk_label_set_text_with_mnemonic (GTK_LABEL (display->label_accel_label), str);
275           g_free (str);
276         }
277       else
278         {
279           gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
280         }
281
282       /* The problem here is that some icons don't have SIZE_LARGE_TOOLBAR,
283        * so we get a "missing image" icon...
284        */
285       if (info->small_icon)
286         gtk_image_set_from_stock (GTK_IMAGE (display->icon_image), info->id,
287                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
288       else
289         gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
290
291       stock_item_info_free (info);
292     }
293   else
294     {
295       gtk_label_set_text (GTK_LABEL (display->type_label), "No selected item");
296       gtk_label_set_text (GTK_LABEL (display->macro_label), "");
297       gtk_label_set_text (GTK_LABEL (display->id_label), "");
298       gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
299       gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
300     }
301 }
302
303 static void
304 macro_set_func_text (GtkTreeViewColumn *tree_column,
305                      GtkCellRenderer   *cell,
306                      GtkTreeModel      *model,
307                      GtkTreeIter       *iter,
308                      gpointer           data)
309 {
310   StockItemInfo *info;
311   
312   gtk_tree_model_get (model, iter,
313                       0, &info,
314                       -1);
315   
316   g_object_set (GTK_CELL_RENDERER (cell),
317                 "text", info->macro,
318                 NULL);
319   
320   stock_item_info_free (info);
321 }
322
323 static void
324 macro_set_func_pixbuf (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                 "pixbuf", info->small_icon,
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 (void)
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_title (GTK_WINDOW (window), "Stock Icons and Items");
422
423       gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (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 (G_OBJECT (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_cell_data_func (column, cell_renderer,
451                                                macro_set_func_pixbuf, NULL, 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
464       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
465                                                   -1,
466                                                   "Label",
467                                                   cell_renderer,
468                                                   label_set_func,
469                                                   NULL,
470                                                   NULL);
471
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       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
481                                                   -1,
482                                                   "ID",
483                                                   cell_renderer,
484                                                   id_set_func,
485                                                   NULL,
486                                                   NULL);
487       
488       align = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
489       gtk_box_pack_end (GTK_BOX (hbox), align, FALSE, FALSE, 0);
490       
491       frame = gtk_frame_new ("Selected Item");
492       gtk_container_add (GTK_CONTAINER (align), frame);
493
494       vbox = gtk_vbox_new (FALSE, 8);
495       gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
496       gtk_container_add (GTK_CONTAINER (frame), vbox);
497
498       display = g_new (StockItemDisplay, 1);
499       g_object_set_data_full (G_OBJECT (treeview),
500                               "stock-display",
501                               display,
502                               g_free); /* free display with treeview */
503       
504       display->type_label = gtk_label_new (NULL);
505       display->macro_label = gtk_label_new (NULL);
506       display->id_label = gtk_label_new (NULL);
507       display->label_accel_label = gtk_label_new (NULL);
508       display->icon_image = gtk_image_new_from_pixbuf (NULL); /* empty image */
509
510       gtk_box_pack_start (GTK_BOX (vbox), display->type_label,
511                           FALSE, FALSE, 0);
512
513       gtk_box_pack_start (GTK_BOX (vbox), display->icon_image,
514                           FALSE, FALSE, 0);
515       
516       gtk_box_pack_start (GTK_BOX (vbox), display->label_accel_label,
517                           FALSE, FALSE, 0);
518       gtk_box_pack_start (GTK_BOX (vbox), display->macro_label,
519                           FALSE, FALSE, 0);
520       gtk_box_pack_start (GTK_BOX (vbox), display->id_label,
521                           FALSE, FALSE, 0);
522
523       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
524       gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
525       
526       g_signal_connect (G_OBJECT (selection),
527                         "changed",
528                         G_CALLBACK (selection_changed),
529                         NULL);
530     }
531
532   if (!GTK_WIDGET_VISIBLE (window))
533     {
534       gtk_widget_show_all (window);
535     }
536   else
537     {    
538       gtk_widget_destroy (window);
539       window = NULL;
540     }
541
542   return window;
543 }