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