]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/stock_browser.c
forgot to add stock_browser.c
[~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, it just lets you scan the
5  * available stock icons and stock items.
6  */
7
8 #include <gtk/gtk.h>
9
10 static GtkWidget *window = NULL;
11
12 typedef struct _StockItemInfo StockItemInfo;
13 struct _StockItemInfo
14 {
15   gchar *id;
16   GtkStockItem item;
17   GdkPixbuf *small_icon;
18   gchar *macro;
19   gchar *accel_str;
20 };
21
22 /* Make StockItemInfo a boxed type so we can automatically
23  * manage memory
24  */
25 #define STOCK_ITEM_INFO_TYPE stock_item_info_get_type ()
26
27 static void
28 stock_item_info_free (StockItemInfo *info)
29 {
30   g_free (info->id);
31   g_free (info->macro);
32   g_free (info->accel_str);
33   if (info->small_icon)
34     g_object_unref (G_OBJECT (info->small_icon));
35   
36   g_free (info);
37 }
38
39 static StockItemInfo*
40 stock_item_info_copy (StockItemInfo *src)
41 {
42   StockItemInfo *info;
43
44   info = g_new (StockItemInfo, 1);
45   info->id = g_strdup (src->id);
46   info->macro = g_strdup (src->macro);
47   info->accel_str = g_strdup (src->accel_str);
48   
49   info->item = src->item;
50
51   info->small_icon = src->small_icon;
52   if (info->small_icon)
53     g_object_ref (G_OBJECT (info->small_icon));
54
55   return info;
56 }
57
58 static GType
59 stock_item_info_get_type (void)
60 {
61   static GType our_type = 0;
62   
63   if (our_type == 0)
64     our_type = g_boxed_type_register_static ("StockItemInfo",
65                                              NULL,
66                                              (GBoxedCopyFunc) stock_item_info_copy,
67                                              (GBoxedFreeFunc) stock_item_info_free,
68                                              FALSE);
69
70   return our_type;
71 }
72
73 typedef struct _StockItemDisplay StockItemDisplay;
74 struct _StockItemDisplay
75 {
76   GtkWidget *type_label;
77   GtkWidget *macro_label;
78   GtkWidget *id_label;
79   GtkWidget *label_accel_label;
80   GtkWidget *icon_image;
81 };
82
83 /* columns in the tree model */
84 enum {
85   COLUMN_ICON_MACRO,
86   COLUMN_LABEL,
87   COLUMN_ACCEL,
88   COLUMN_ID
89 };
90
91 static gchar*
92 id_to_macro (const gchar *id)
93 {
94   GString *macro;
95   const gchar *cp;
96   gchar *p;
97
98   /* gtk-foo -> GTK_STOCK_FOO */
99   
100   cp = id;
101   while (*cp && *cp != '-')
102     ++cp;
103
104   if (*cp == '\0')
105     return g_strdup ("??UNKNOWN??");
106
107   macro = g_string_new (NULL);
108   
109   g_string_append_len (macro, id, cp - id);
110   
111   g_string_append (macro, "_STOCK");
112   g_string_append (macro, cp);
113
114   p = macro->str;
115   while (*p)
116     {
117       if (*p == '-')
118         *p = '_';
119       ++p;
120     }
121
122   g_strup (macro->str);
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_with_types (1, STOCK_ITEM_INFO_TYPE);
135
136   ids = gtk_stock_list_ids ();
137   tmp_list = ids;
138   while (tmp_list != NULL)
139     {
140       StockItemInfo info;
141       GtkStockItem item;
142       GtkTreeIter iter;
143       GtkIconSet *icon_set;
144       
145       info.id = tmp_list->data;
146       
147       if (gtk_stock_lookup (info.id, &item))
148         {
149           info.item = item;
150         }
151       else
152         {
153           info.item.label = NULL;
154           info.item.stock_id = NULL;
155           info.item.modifier = 0;
156           info.item.keyval = 0;
157           info.item.translation_domain = NULL;
158         }
159
160       /* only show icons for stock IDs that have default icons */
161       icon_set = gtk_icon_factory_lookup_default (info.id);
162       if (icon_set)
163         {
164           GtkIconSize *sizes = NULL;
165           gint n_sizes = 0;
166           gint i;
167           GtkIconSize size;
168
169           /* See what sizes this stock icon really exists at */
170           gtk_icon_set_get_sizes (icon_set, &sizes, &n_sizes);
171
172           /* Use menu size if it exists, otherwise first size found */
173           size = sizes[0];
174           i = 0;
175           while (i < n_sizes)
176             {
177               if (sizes[i] == GTK_ICON_SIZE_MENU)
178                 {
179                   size = GTK_ICON_SIZE_MENU;
180                   break;
181                 }
182               ++i;
183             }
184           g_free (sizes);
185           
186           info.small_icon = gtk_widget_render_icon (window, info.id,
187                                                     size,
188                                                     NULL);
189           
190           if (size != GTK_ICON_SIZE_MENU)
191             {
192               /* Make the result the proper size for our thumbnail */
193               gint w, h;
194               GdkPixbuf *scaled;
195               
196               gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
197               
198               scaled = gdk_pixbuf_scale_simple (info.small_icon,
199                                                 w, h,
200                                                 GDK_INTERP_BILINEAR);
201
202               g_object_unref (G_OBJECT (info.small_icon));
203               info.small_icon = scaled;
204             }
205         }
206       else
207         info.small_icon = NULL;
208
209       if (info.item.keyval != 0)
210         {
211           info.accel_str = gtk_accelerator_name (info.item.keyval,
212                                                  info.item.modifier);
213         }
214       else
215         {
216           info.accel_str = g_strdup ("");
217         }
218
219       info.macro = id_to_macro (info.id);
220       
221       gtk_list_store_append (store, &iter);
222       gtk_list_store_set (store, &iter, 0, &info, -1);
223
224       g_free (info.macro);
225       g_free (info.accel_str);
226       if (info.small_icon)
227         g_object_unref (G_OBJECT (info.small_icon));
228       
229       tmp_list = g_slist_next (tmp_list);
230     }
231   
232   g_slist_foreach (ids, (GFunc)g_free, NULL);
233   g_slist_free (ids);
234
235   return GTK_TREE_MODEL (store);
236 }
237
238 static void
239 selection_changed (GtkTreeSelection *selection)
240 {
241   GtkTreeView *treeview;
242   StockItemDisplay *display;
243   GtkTreeModel *model;
244   GtkTreeIter iter;
245   
246   treeview = gtk_tree_selection_get_tree_view (selection);
247   display = g_object_get_data (G_OBJECT (treeview), "stock-display");
248
249   if (gtk_tree_selection_get_selected (selection, &model, &iter))
250     {
251       StockItemInfo *info;
252       gchar *str;
253       
254       gtk_tree_model_get (model, &iter,
255                           0, &info,
256                           -1);
257
258       if (info->small_icon && info->item.label)
259         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon and Item");
260       else if (info->small_icon)
261         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon Only");
262       else if (info->item.label)
263         gtk_label_set_text (GTK_LABEL (display->type_label), "Item Only");
264       else
265         gtk_label_set_text (GTK_LABEL (display->type_label), "???????");
266
267       gtk_label_set_text (GTK_LABEL (display->macro_label), info->macro);
268       gtk_label_set_text (GTK_LABEL (display->id_label), info->id);
269
270       if (info->item.label)
271         {
272           str = g_strdup_printf ("%s %s", info->item.label, info->accel_str);
273           gtk_label_set_text_with_mnemonic (GTK_LABEL (display->label_accel_label), str);
274           g_free (str);
275         }
276       else
277         {
278           gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
279         }
280
281       /* The problem here is that some icons don't have SIZE_LARGE_TOOLBAR,
282        * so we get a "missing image" icon...
283        */
284       if (info->small_icon)
285         gtk_image_set_from_stock (GTK_IMAGE (display->icon_image), info->id,
286                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
287       else
288         gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
289
290       stock_item_info_free (info);
291     }
292   else
293     {
294       gtk_label_set_text (GTK_LABEL (display->type_label), "No selected item");
295       gtk_label_set_text (GTK_LABEL (display->macro_label), "");
296       gtk_label_set_text (GTK_LABEL (display->id_label), "");
297       gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
298       gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
299     }
300 }
301
302 static void
303 macro_set_func (GtkTreeViewColumn *tree_column,
304                 GtkCellRenderer   *cell,
305                 GtkTreeModel      *model,
306                 GtkTreeIter       *iter,
307                 gpointer           data)
308 {
309   StockItemInfo *info;
310   
311   gtk_tree_model_get (model, iter,
312                       0, &info,
313                       -1);
314   
315   g_object_set (GTK_CELL_RENDERER (cell),
316                 "text", info->macro,
317                 "pixbuf", info->small_icon,
318                 NULL);
319   
320   stock_item_info_free (info);
321 }
322
323 static void
324 id_set_func (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->id,
338                 NULL);
339   
340   stock_item_info_free (info);
341 }
342
343 static void
344 accel_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->accel_str,
358                 NULL);
359   
360   stock_item_info_free (info);
361 }
362
363 static void
364 label_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->item.label,
378                 NULL);
379   
380   stock_item_info_free (info);
381 }
382
383 GtkWidget *
384 do_stock_browser (void)
385 {  
386   if (!window)
387     {
388       GtkWidget *frame;
389       GtkWidget *vbox;
390       GtkWidget *hbox;
391       GtkWidget *sw;
392       GtkWidget *treeview;
393       GtkWidget *align;
394       GtkTreeModel *model;
395       GtkCellRenderer *cell_renderer;
396       StockItemDisplay *display;
397       GtkTreeSelection *selection;
398       
399       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
400       gtk_window_set_title (GTK_WINDOW (window), "Stock Icons and Items");
401
402       gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroyed), &window);
403       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
404
405       hbox = gtk_hbox_new (FALSE, 8);
406       gtk_container_add (GTK_CONTAINER (window), hbox);
407
408       sw = gtk_scrolled_window_new (NULL, NULL);
409       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
410                                       GTK_POLICY_NEVER,
411                                       GTK_POLICY_AUTOMATIC);
412       gtk_box_pack_start (GTK_BOX (hbox), sw, FALSE, FALSE, 0);
413
414       model = create_model ();
415       
416       treeview = gtk_tree_view_new_with_model (model);
417
418       g_object_unref (G_OBJECT (model));
419
420       gtk_container_add (GTK_CONTAINER (sw), treeview);
421       
422       cell_renderer = gtk_cell_renderer_text_pixbuf_new ();
423
424       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
425                                                   -1,
426                                                   "Macro",
427                                                   cell_renderer,
428                                                   macro_set_func,
429                                                   NULL,
430                                                   NULL);
431       g_object_unref (G_OBJECT (cell_renderer));
432
433       cell_renderer = gtk_cell_renderer_text_new ();
434
435       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
436                                                   -1,
437                                                   "Label",
438                                                   cell_renderer,
439                                                   label_set_func,
440                                                   NULL,
441                                                   NULL);
442
443       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
444                                                   -1,
445                                                   "Accel",
446                                                   cell_renderer,
447                                                   accel_set_func,
448                                                   NULL,
449                                                   NULL);
450
451       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
452                                                   -1,
453                                                   "ID",
454                                                   cell_renderer,
455                                                   id_set_func,
456                                                   NULL,
457                                                   NULL);
458       
459       g_object_unref (G_OBJECT (cell_renderer));
460       
461       align = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
462       gtk_box_pack_end (GTK_BOX (hbox), align, FALSE, FALSE, 0);
463       
464       frame = gtk_frame_new ("Selected Item");
465       gtk_container_add (GTK_CONTAINER (align), frame);
466
467       vbox = gtk_vbox_new (FALSE, 8);
468       gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
469       gtk_container_add (GTK_CONTAINER (frame), vbox);
470
471       display = g_new (StockItemDisplay, 1);
472       g_object_set_data_full (G_OBJECT (treeview),
473                               "stock-display",
474                               display,
475                               g_free); /* free display with treeview */
476       
477       display->type_label = gtk_label_new (NULL);
478       display->macro_label = gtk_label_new (NULL);
479       display->id_label = gtk_label_new (NULL);
480       display->label_accel_label = gtk_label_new (NULL);
481       display->icon_image = gtk_image_new_from_pixbuf (NULL); /* empty image */
482
483       gtk_box_pack_start (GTK_BOX (vbox), display->type_label,
484                           FALSE, FALSE, 0);
485
486       gtk_box_pack_start (GTK_BOX (vbox), display->icon_image,
487                           FALSE, FALSE, 0);
488       
489       gtk_box_pack_start (GTK_BOX (vbox), display->label_accel_label,
490                           FALSE, FALSE, 0);
491       gtk_box_pack_start (GTK_BOX (vbox), display->macro_label,
492                           FALSE, FALSE, 0);
493       gtk_box_pack_start (GTK_BOX (vbox), display->id_label,
494                           FALSE, FALSE, 0);
495
496       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
497       gtk_tree_selection_set_mode (selection, GTK_TREE_SELECTION_SINGLE);
498       
499       g_signal_connect_data (G_OBJECT (selection),
500                              "selection_changed",
501                              G_CALLBACK (selection_changed),
502                              NULL, NULL, FALSE, FALSE);
503     }
504
505   if (!GTK_WIDGET_VISIBLE (window))
506     {
507       gtk_widget_show_all (window);
508     }
509   else
510     {    
511       gtk_widget_destroy (window);
512       window = NULL;
513     }
514
515   return window;
516 }