]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/iconview.c
gtk-demo: Use gdk-pixbuf resource api
[~andy/gtk] / demos / gtk-demo / iconview.c
1 /* Icon View/Icon View Basics
2  *
3  * The GtkIconView widget is used to display and manipulate icons.
4  * It uses a GtkTreeModel for data storage, so the list store
5  * example might be helpful.
6  */
7
8 #include <gtk/gtk.h>
9 #include <string.h>
10 #include "demo-common.h"
11
12 static GtkWidget *window = NULL;
13
14 #define FOLDER_NAME "gnome-fs-directory.png"
15 #define FILE_NAME "gnome-fs-regular.png"
16
17 enum
18 {
19   COL_PATH,
20   COL_DISPLAY_NAME,
21   COL_PIXBUF,
22   COL_IS_DIRECTORY,
23   NUM_COLS
24 };
25
26
27 static GdkPixbuf *file_pixbuf, *folder_pixbuf;
28 gchar *parent;
29 GtkToolItem *up_button;
30
31 /* Loads the images for the demo and returns whether the operation succeeded */
32 static gboolean
33 load_pixbufs (GError **error)
34 {
35   char *filename;
36
37   if (file_pixbuf)
38     return TRUE; /* already loaded earlier */
39
40   /* demo_find_file() looks in the current directory first,
41    * so you can run gtk-demo without installing GTK, then looks
42    * in the location where the file is installed.
43    */
44   filename = demo_find_file (FILE_NAME, error);
45   if (!filename)
46     return FALSE; /* note that "error" was filled in and returned */
47
48   file_pixbuf = gdk_pixbuf_new_from_file (filename, error);
49   g_free (filename);
50
51   if (!file_pixbuf)
52     return FALSE; /* Note that "error" was filled with a GError */
53
54   filename = demo_find_file (FOLDER_NAME, error);
55   if (!filename)
56     return FALSE; /* note that "error" was filled in and returned */
57
58   folder_pixbuf = gdk_pixbuf_new_from_file (filename, error);
59   g_free (filename);
60
61   return TRUE;
62 }
63
64 static void
65 fill_store (GtkListStore *store)
66 {
67   GDir *dir;
68   const gchar *name;
69   GtkTreeIter iter;
70
71   /* First clear the store */
72   gtk_list_store_clear (store);
73
74   /* Now go through the directory and extract all the file
75    * information */
76   dir = g_dir_open (parent, 0, NULL);
77   if (!dir)
78     return;
79
80   name = g_dir_read_name (dir);
81   while (name != NULL)
82     {
83       gchar *path, *display_name;
84       gboolean is_dir;
85
86       /* We ignore hidden files that start with a '.' */
87       if (name[0] != '.')
88         {
89           path = g_build_filename (parent, name, NULL);
90
91           is_dir = g_file_test (path, G_FILE_TEST_IS_DIR);
92
93           display_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
94
95           gtk_list_store_append (store, &iter);
96           gtk_list_store_set (store, &iter,
97                               COL_PATH, path,
98                               COL_DISPLAY_NAME, display_name,
99                               COL_IS_DIRECTORY, is_dir,
100                               COL_PIXBUF, is_dir ? folder_pixbuf : file_pixbuf,
101                               -1);
102           g_free (path);
103           g_free (display_name);
104         }
105
106       name = g_dir_read_name (dir);
107     }
108   g_dir_close (dir);
109 }
110
111 static gint
112 sort_func (GtkTreeModel *model,
113            GtkTreeIter  *a,
114            GtkTreeIter  *b,
115            gpointer      user_data)
116 {
117   gboolean is_dir_a, is_dir_b;
118   gchar *name_a, *name_b;
119   int ret;
120
121   /* We need this function because we want to sort
122    * folders before files.
123    */
124
125
126   gtk_tree_model_get (model, a,
127                       COL_IS_DIRECTORY, &is_dir_a,
128                       COL_DISPLAY_NAME, &name_a,
129                       -1);
130
131   gtk_tree_model_get (model, b,
132                       COL_IS_DIRECTORY, &is_dir_b,
133                       COL_DISPLAY_NAME, &name_b,
134                       -1);
135
136   if (!is_dir_a && is_dir_b)
137     ret = 1;
138   else if (is_dir_a && !is_dir_b)
139     ret = -1;
140   else
141     {
142       ret = g_utf8_collate (name_a, name_b);
143     }
144
145   g_free (name_a);
146   g_free (name_b);
147
148   return ret;
149 }
150
151 static GtkListStore *
152 create_store (void)
153 {
154   GtkListStore *store;
155
156   store = gtk_list_store_new (NUM_COLS,
157                               G_TYPE_STRING,
158                               G_TYPE_STRING,
159                               GDK_TYPE_PIXBUF,
160                               G_TYPE_BOOLEAN);
161
162   /* Set sort column and function */
163   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
164                                            sort_func,
165                                            NULL, NULL);
166   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
167                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
168                                         GTK_SORT_ASCENDING);
169
170   return store;
171 }
172
173 static void
174 item_activated (GtkIconView *icon_view,
175                 GtkTreePath *tree_path,
176                 gpointer     user_data)
177 {
178   GtkListStore *store;
179   gchar *path;
180   GtkTreeIter iter;
181   gboolean is_dir;
182
183   store = GTK_LIST_STORE (user_data);
184
185   gtk_tree_model_get_iter (GTK_TREE_MODEL (store),
186                            &iter, tree_path);
187   gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
188                       COL_PATH, &path,
189                       COL_IS_DIRECTORY, &is_dir,
190                       -1);
191
192   if (!is_dir)
193     {
194       g_free (path);
195       return;
196     }
197
198   /* Replace parent with path and re-fill the model*/
199   g_free (parent);
200   parent = path;
201
202   fill_store (store);
203
204   /* Sensitize the up button */
205   gtk_widget_set_sensitive (GTK_WIDGET (up_button), TRUE);
206 }
207
208 static void
209 up_clicked (GtkToolItem *item,
210             gpointer     user_data)
211 {
212   GtkListStore *store;
213   gchar *dir_name;
214
215   store = GTK_LIST_STORE (user_data);
216
217   dir_name = g_path_get_dirname (parent);
218   g_free (parent);
219
220   parent = dir_name;
221
222   fill_store (store);
223
224   /* Maybe de-sensitize the up button */
225   gtk_widget_set_sensitive (GTK_WIDGET (up_button),
226                             strcmp (parent, "/") != 0);
227 }
228
229 static void
230 home_clicked (GtkToolItem *item,
231               gpointer     user_data)
232 {
233   GtkListStore *store;
234
235   store = GTK_LIST_STORE (user_data);
236
237   g_free (parent);
238   parent = g_strdup (g_get_home_dir ());
239
240   fill_store (store);
241
242   /* Sensitize the up button */
243   gtk_widget_set_sensitive (GTK_WIDGET (up_button),
244                             TRUE);
245 }
246
247 static void close_window(void)
248 {
249   gtk_widget_destroy (window);
250   window = NULL;
251
252   g_object_unref (file_pixbuf);
253   file_pixbuf = NULL;
254
255   g_object_unref (folder_pixbuf);
256   folder_pixbuf = NULL;
257 }
258
259 GtkWidget *
260 do_iconview (GtkWidget *do_widget)
261 {
262   if (!window)
263     {
264       GError *error;
265
266       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
267       gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
268
269       gtk_window_set_screen (GTK_WINDOW (window),
270                              gtk_widget_get_screen (do_widget));
271       gtk_window_set_title (GTK_WINDOW (window), "GtkIconView demo");
272
273       g_signal_connect (window, "destroy",
274                         G_CALLBACK (close_window), NULL);
275
276       error = NULL;
277       if (!load_pixbufs (&error))
278         {
279           GtkWidget *dialog;
280
281           dialog = gtk_message_dialog_new (GTK_WINDOW (window),
282                                            GTK_DIALOG_DESTROY_WITH_PARENT,
283                                            GTK_MESSAGE_ERROR,
284                                            GTK_BUTTONS_CLOSE,
285                                            "Failed to load an image: %s",
286                                            error->message);
287
288           g_error_free (error);
289
290           g_signal_connect (dialog, "response",
291                             G_CALLBACK (gtk_widget_destroy), NULL);
292
293           gtk_widget_show (dialog);
294         }
295       else
296         {
297           GtkWidget *sw;
298           GtkWidget *icon_view;
299           GtkListStore *store;
300           GtkWidget *vbox;
301           GtkWidget *tool_bar;
302           GtkToolItem *home_button;
303
304           vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
305           gtk_container_add (GTK_CONTAINER (window), vbox);
306
307           tool_bar = gtk_toolbar_new ();
308           gtk_box_pack_start (GTK_BOX (vbox), tool_bar, FALSE, FALSE, 0);
309
310           up_button = gtk_tool_button_new_from_stock (GTK_STOCK_GO_UP);
311           gtk_tool_item_set_is_important (up_button, TRUE);
312           gtk_widget_set_sensitive (GTK_WIDGET (up_button), FALSE);
313           gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), up_button, -1);
314
315           home_button = gtk_tool_button_new_from_stock (GTK_STOCK_HOME);
316           gtk_tool_item_set_is_important (home_button, TRUE);
317           gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), home_button, -1);
318
319
320           sw = gtk_scrolled_window_new (NULL, NULL);
321           gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
322                                                GTK_SHADOW_ETCHED_IN);
323           gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
324                                           GTK_POLICY_AUTOMATIC,
325                                           GTK_POLICY_AUTOMATIC);
326
327           gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
328
329           /* Create the store and fill it with the contents of '/' */
330           parent = g_strdup ("/");
331           store = create_store ();
332           fill_store (store);
333
334           icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store));
335           gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
336                                             GTK_SELECTION_MULTIPLE);
337           g_object_unref (store);
338
339           /* Connect to the "clicked" signal of the "Up" tool button */
340           g_signal_connect (up_button, "clicked",
341                             G_CALLBACK (up_clicked), store);
342
343           /* Connect to the "clicked" signal of the "Home" tool button */
344           g_signal_connect (home_button, "clicked",
345                             G_CALLBACK (home_clicked), store);
346
347           /* We now set which model columns that correspond to the text
348            * and pixbuf of each item
349            */
350           gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view), COL_DISPLAY_NAME);
351           gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), COL_PIXBUF);
352
353           /* Connect to the "item-activated" signal */
354           g_signal_connect (icon_view, "item-activated",
355                             G_CALLBACK (item_activated), store);
356           gtk_container_add (GTK_CONTAINER (sw), icon_view);
357
358           gtk_widget_grab_focus (icon_view);
359         }
360     }
361
362   if (!gtk_widget_get_visible (window))
363     gtk_widget_show_all (window);
364   else
365     {
366       gtk_widget_destroy (window);
367       window = NULL;
368     }
369
370   return window;
371 }