]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/stock_browser.c
add editable_cells.c, list_store.c and tree_store.c
[~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 (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   g_string_ascii_up (macro);
116
117   return g_string_free (macro, FALSE);
118 }
119
120 static GtkTreeModel*
121 create_model (void)
122 {
123   GtkListStore *store;
124   GSList *ids;
125   GSList *tmp_list;
126   
127   store = gtk_list_store_new (1, STOCK_ITEM_INFO_TYPE);
128
129   ids = gtk_stock_list_ids ();
130   ids = g_slist_sort (ids, (GCompareFunc) strcmp);
131   tmp_list = ids;
132   while (tmp_list != NULL)
133     {
134       StockItemInfo info;
135       GtkStockItem item;
136       GtkTreeIter iter;
137       GtkIconSet *icon_set;
138       
139       info.id = tmp_list->data;
140       
141       if (gtk_stock_lookup (info.id, &item))
142         {
143           info.item = item;
144         }
145       else
146         {
147           info.item.label = NULL;
148           info.item.stock_id = NULL;
149           info.item.modifier = 0;
150           info.item.keyval = 0;
151           info.item.translation_domain = NULL;
152         }
153
154       /* only show icons for stock IDs that have default icons */
155       icon_set = gtk_icon_factory_lookup_default (info.id);
156       if (icon_set)
157         {
158           GtkIconSize *sizes = NULL;
159           gint n_sizes = 0;
160           gint i;
161           GtkIconSize size;
162
163           /* See what sizes this stock icon really exists at */
164           gtk_icon_set_get_sizes (icon_set, &sizes, &n_sizes);
165
166           /* Use menu size if it exists, otherwise first size found */
167           size = sizes[0];
168           i = 0;
169           while (i < n_sizes)
170             {
171               if (sizes[i] == GTK_ICON_SIZE_MENU)
172                 {
173                   size = GTK_ICON_SIZE_MENU;
174                   break;
175                 }
176               ++i;
177             }
178           g_free (sizes);
179           
180           info.small_icon = gtk_widget_render_icon (window, info.id,
181                                                     size,
182                                                     NULL);
183           
184           if (size != GTK_ICON_SIZE_MENU)
185             {
186               /* Make the result the proper size for our thumbnail */
187               gint w, h;
188               GdkPixbuf *scaled;
189               
190               gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
191               
192               scaled = gdk_pixbuf_scale_simple (info.small_icon,
193                                                 w, h,
194                                                 GDK_INTERP_BILINEAR);
195
196               g_object_unref (G_OBJECT (info.small_icon));
197               info.small_icon = scaled;
198             }
199         }
200       else
201         info.small_icon = NULL;
202
203       if (info.item.keyval != 0)
204         {
205           info.accel_str = gtk_accelerator_name (info.item.keyval,
206                                                  info.item.modifier);
207         }
208       else
209         {
210           info.accel_str = g_strdup ("");
211         }
212
213       info.macro = id_to_macro (info.id);
214       
215       gtk_list_store_append (store, &iter);
216       gtk_list_store_set (store, &iter, 0, &info, -1);
217
218       g_free (info.macro);
219       g_free (info.accel_str);
220       if (info.small_icon)
221         g_object_unref (G_OBJECT (info.small_icon));
222       
223       tmp_list = g_slist_next (tmp_list);
224     }
225   
226   g_slist_foreach (ids, (GFunc)g_free, NULL);
227   g_slist_free (ids);
228
229   return GTK_TREE_MODEL (store);
230 }
231
232 static void
233 selection_changed (GtkTreeSelection *selection)
234 {
235   GtkTreeView *treeview;
236   StockItemDisplay *display;
237   GtkTreeModel *model;
238   GtkTreeIter iter;
239   
240   treeview = gtk_tree_selection_get_tree_view (selection);
241   display = g_object_get_data (G_OBJECT (treeview), "stock-display");
242
243   if (gtk_tree_selection_get_selected (selection, &model, &iter))
244     {
245       StockItemInfo *info;
246       gchar *str;
247       
248       gtk_tree_model_get (model, &iter,
249                           0, &info,
250                           -1);
251
252       if (info->small_icon && info->item.label)
253         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon and Item");
254       else if (info->small_icon)
255         gtk_label_set_text (GTK_LABEL (display->type_label), "Icon Only");
256       else if (info->item.label)
257         gtk_label_set_text (GTK_LABEL (display->type_label), "Item Only");
258       else
259         gtk_label_set_text (GTK_LABEL (display->type_label), "???????");
260
261       gtk_label_set_text (GTK_LABEL (display->macro_label), info->macro);
262       gtk_label_set_text (GTK_LABEL (display->id_label), info->id);
263
264       if (info->item.label)
265         {
266           str = g_strdup_printf ("%s %s", info->item.label, info->accel_str);
267           gtk_label_set_text_with_mnemonic (GTK_LABEL (display->label_accel_label), str);
268           g_free (str);
269         }
270       else
271         {
272           gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
273         }
274
275       /* The problem here is that some icons don't have SIZE_LARGE_TOOLBAR,
276        * so we get a "missing image" icon...
277        */
278       if (info->small_icon)
279         gtk_image_set_from_stock (GTK_IMAGE (display->icon_image), info->id,
280                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
281       else
282         gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
283
284       stock_item_info_free (info);
285     }
286   else
287     {
288       gtk_label_set_text (GTK_LABEL (display->type_label), "No selected item");
289       gtk_label_set_text (GTK_LABEL (display->macro_label), "");
290       gtk_label_set_text (GTK_LABEL (display->id_label), "");
291       gtk_label_set_text (GTK_LABEL (display->label_accel_label), "");
292       gtk_image_set_from_pixbuf (GTK_IMAGE (display->icon_image), NULL);
293     }
294 }
295
296 static void
297 macro_set_func_text (GtkTreeViewColumn *tree_column,
298                      GtkCellRenderer   *cell,
299                      GtkTreeModel      *model,
300                      GtkTreeIter       *iter,
301                      gpointer           data)
302 {
303   StockItemInfo *info;
304   
305   gtk_tree_model_get (model, iter,
306                       0, &info,
307                       -1);
308   
309   g_object_set (GTK_CELL_RENDERER (cell),
310                 "text", info->macro,
311                 NULL);
312   
313   stock_item_info_free (info);
314 }
315
316 static void
317 macro_set_func_pixbuf (GtkTreeViewColumn *tree_column,
318                        GtkCellRenderer   *cell,
319                        GtkTreeModel      *model,
320                        GtkTreeIter       *iter,
321                        gpointer           data)
322 {
323   StockItemInfo *info;
324   
325   gtk_tree_model_get (model, iter,
326                       0, &info,
327                       -1);
328   
329   g_object_set (GTK_CELL_RENDERER (cell),
330                 "pixbuf", info->small_icon,
331                 NULL);
332   
333   stock_item_info_free (info);
334 }
335
336 static void
337 id_set_func (GtkTreeViewColumn *tree_column,
338              GtkCellRenderer   *cell,
339              GtkTreeModel      *model,
340              GtkTreeIter       *iter,
341              gpointer           data)
342 {
343   StockItemInfo *info;
344   
345   gtk_tree_model_get (model, iter,
346                       0, &info,
347                       -1);
348   
349   g_object_set (GTK_CELL_RENDERER (cell),
350                 "text", info->id,
351                 NULL);
352   
353   stock_item_info_free (info);
354 }
355
356 static void
357 accel_set_func (GtkTreeViewColumn *tree_column,
358                 GtkCellRenderer   *cell,
359                 GtkTreeModel      *model,
360                 GtkTreeIter       *iter,
361                 gpointer           data)
362 {
363   StockItemInfo *info;
364   
365   gtk_tree_model_get (model, iter,
366                       0, &info,
367                       -1);
368   
369   g_object_set (GTK_CELL_RENDERER (cell),
370                 "text", info->accel_str,
371                 NULL);
372   
373   stock_item_info_free (info);
374 }
375
376 static void
377 label_set_func (GtkTreeViewColumn *tree_column,
378                 GtkCellRenderer   *cell,
379                 GtkTreeModel      *model,
380                 GtkTreeIter       *iter,
381                 gpointer           data)
382 {
383   StockItemInfo *info;
384   
385   gtk_tree_model_get (model, iter,
386                       0, &info,
387                       -1);
388   
389   g_object_set (GTK_CELL_RENDERER (cell),
390                 "text", info->item.label,
391                 NULL);
392   
393   stock_item_info_free (info);
394 }
395
396 GtkWidget *
397 do_stock_browser (void)
398 {  
399   if (!window)
400     {
401       GtkWidget *frame;
402       GtkWidget *vbox;
403       GtkWidget *hbox;
404       GtkWidget *sw;
405       GtkWidget *treeview;
406       GtkWidget *align;
407       GtkTreeModel *model;
408       GtkCellRenderer *cell_renderer;
409       StockItemDisplay *display;
410       GtkTreeSelection *selection;
411       GtkTreeViewColumn *column;
412
413       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
414       gtk_window_set_title (GTK_WINDOW (window), "Stock Icons and Items");
415
416       gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroyed), &window);
417       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
418
419       hbox = gtk_hbox_new (FALSE, 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 (G_OBJECT (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_cell_data_func (column, cell_renderer,
444                                                macro_set_func_pixbuf, NULL, 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
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       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       gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview),
474                                                   -1,
475                                                   "ID",
476                                                   cell_renderer,
477                                                   id_set_func,
478                                                   NULL,
479                                                   NULL);
480       
481       align = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
482       gtk_box_pack_end (GTK_BOX (hbox), align, FALSE, FALSE, 0);
483       
484       frame = gtk_frame_new ("Selected Item");
485       gtk_container_add (GTK_CONTAINER (align), frame);
486
487       vbox = gtk_vbox_new (FALSE, 8);
488       gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
489       gtk_container_add (GTK_CONTAINER (frame), vbox);
490
491       display = g_new (StockItemDisplay, 1);
492       g_object_set_data_full (G_OBJECT (treeview),
493                               "stock-display",
494                               display,
495                               g_free); /* free display with treeview */
496       
497       display->type_label = gtk_label_new (NULL);
498       display->macro_label = gtk_label_new (NULL);
499       display->id_label = gtk_label_new (NULL);
500       display->label_accel_label = gtk_label_new (NULL);
501       display->icon_image = gtk_image_new_from_pixbuf (NULL); /* empty image */
502
503       gtk_box_pack_start (GTK_BOX (vbox), display->type_label,
504                           FALSE, FALSE, 0);
505
506       gtk_box_pack_start (GTK_BOX (vbox), display->icon_image,
507                           FALSE, FALSE, 0);
508       
509       gtk_box_pack_start (GTK_BOX (vbox), display->label_accel_label,
510                           FALSE, FALSE, 0);
511       gtk_box_pack_start (GTK_BOX (vbox), display->macro_label,
512                           FALSE, FALSE, 0);
513       gtk_box_pack_start (GTK_BOX (vbox), display->id_label,
514                           FALSE, FALSE, 0);
515
516       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
517       gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
518       
519       g_signal_connect (G_OBJECT (selection),
520                         "changed",
521                         G_CALLBACK (selection_changed),
522                         NULL);
523     }
524
525   if (!GTK_WIDGET_VISIBLE (window))
526     {
527       gtk_widget_show_all (window);
528     }
529   else
530     {    
531       gtk_widget_destroy (window);
532       window = NULL;
533     }
534
535   return window;
536 }