]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/iconview.c
49985ee30709b99cc4df916f924245bbf3d47882
[~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 }
109
110 static gint
111 sort_func (GtkTreeModel *model,
112            GtkTreeIter  *a,
113            GtkTreeIter  *b,
114            gpointer      user_data)
115 {
116   gboolean is_dir_a, is_dir_b;
117   gchar *name_a, *name_b;
118   int ret;
119
120   /* We need this function because we want to sort
121    * folders before files.
122    */
123
124
125   gtk_tree_model_get (model, a,
126                       COL_IS_DIRECTORY, &is_dir_a,
127                       COL_DISPLAY_NAME, &name_a,
128                       -1);
129
130   gtk_tree_model_get (model, b,
131                       COL_IS_DIRECTORY, &is_dir_b,
132                       COL_DISPLAY_NAME, &name_b,
133                       -1);
134
135   if (!is_dir_a && is_dir_b)
136     ret = 1;
137   else if (is_dir_a && !is_dir_b)
138     ret = -1;
139   else
140     {
141       ret = g_utf8_collate (name_a, name_b);
142     }
143
144   g_free (name_a);
145   g_free (name_b);
146
147   return ret;
148 }
149
150 static GtkListStore *
151 create_store (void)
152 {
153   GtkListStore *store;
154
155   store = gtk_list_store_new (NUM_COLS,
156                               G_TYPE_STRING,
157                               G_TYPE_STRING,
158                               GDK_TYPE_PIXBUF,
159                               G_TYPE_BOOLEAN);
160
161   /* Set sort column and function */
162   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
163                                            sort_func,
164                                            NULL, NULL);
165   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
166                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
167                                         GTK_SORT_ASCENDING);
168
169   return store;
170 }
171
172 static void
173 item_activated (GtkIconView *icon_view,
174                 GtkTreePath *tree_path,
175                 gpointer     user_data)
176 {
177   GtkListStore *store;
178   gchar *path;
179   GtkTreeIter iter;
180   gboolean is_dir;
181
182   store = GTK_LIST_STORE (user_data);
183
184   gtk_tree_model_get_iter (GTK_TREE_MODEL (store),
185                            &iter, tree_path);
186   gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
187                       COL_PATH, &path,
188                       COL_IS_DIRECTORY, &is_dir,
189                       -1);
190
191   if (!is_dir)
192     {
193       g_free (path);
194       return;
195     }
196
197   /* Replace parent with path and re-fill the model*/
198   g_free (parent);
199   parent = path;
200
201   fill_store (store);
202
203   /* Sensitize the up button */
204   gtk_widget_set_sensitive (GTK_WIDGET (up_button), TRUE);
205 }
206
207 static void
208 up_clicked (GtkToolItem *item,
209             gpointer     user_data)
210 {
211   GtkListStore *store;
212   gchar *dir_name;
213
214   store = GTK_LIST_STORE (user_data);
215
216   dir_name = g_path_get_dirname (parent);
217   g_free (parent);
218
219   parent = dir_name;
220
221   fill_store (store);
222
223   /* Maybe de-sensitize the up button */
224   gtk_widget_set_sensitive (GTK_WIDGET (up_button),
225                             strcmp (parent, "/") != 0);
226 }
227
228 static void
229 home_clicked (GtkToolItem *item,
230               gpointer     user_data)
231 {
232   GtkListStore *store;
233
234   store = GTK_LIST_STORE (user_data);
235
236   g_free (parent);
237   parent = g_strdup (g_get_home_dir ());
238
239   fill_store (store);
240
241   /* Sensitize the up button */
242   gtk_widget_set_sensitive (GTK_WIDGET (up_button),
243                             TRUE);
244 }
245
246 static void close_window(void)
247 {
248   gtk_widget_destroy (window);
249   window = NULL;
250
251   g_object_unref (file_pixbuf);
252   file_pixbuf = NULL;
253
254   g_object_unref (folder_pixbuf);
255   folder_pixbuf = NULL;
256 }
257
258 GtkWidget *
259 do_iconview (GtkWidget *do_widget)
260 {
261   if (!window)
262     {
263       GError *error;
264
265       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
266       gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
267
268       gtk_window_set_screen (GTK_WINDOW (window),
269                              gtk_widget_get_screen (do_widget));
270       gtk_window_set_title (GTK_WINDOW (window), "GtkIconView demo");
271
272       g_signal_connect (window, "destroy",
273                         G_CALLBACK (close_window), NULL);
274
275       error = NULL;
276       if (!load_pixbufs (&error))
277         {
278           GtkWidget *dialog;
279
280           dialog = gtk_message_dialog_new (GTK_WINDOW (window),
281                                            GTK_DIALOG_DESTROY_WITH_PARENT,
282                                            GTK_MESSAGE_ERROR,
283                                            GTK_BUTTONS_CLOSE,
284                                            "Failed to load an image: %s",
285                                            error->message);
286
287           g_error_free (error);
288
289           g_signal_connect (dialog, "response",
290                             G_CALLBACK (gtk_widget_destroy), NULL);
291
292           gtk_widget_show (dialog);
293         }
294       else
295         {
296           GtkWidget *sw;
297           GtkWidget *icon_view;
298           GtkListStore *store;
299           GtkWidget *vbox;
300           GtkWidget *tool_bar;
301           GtkToolItem *home_button;
302
303           vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
304           gtk_container_add (GTK_CONTAINER (window), vbox);
305
306           tool_bar = gtk_toolbar_new ();
307           gtk_box_pack_start (GTK_BOX (vbox), tool_bar, FALSE, FALSE, 0);
308
309           up_button = gtk_tool_button_new_from_stock (GTK_STOCK_GO_UP);
310           gtk_tool_item_set_is_important (up_button, TRUE);
311           gtk_widget_set_sensitive (GTK_WIDGET (up_button), FALSE);
312           gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), up_button, -1);
313
314           home_button = gtk_tool_button_new_from_stock (GTK_STOCK_HOME);
315           gtk_tool_item_set_is_important (home_button, TRUE);
316           gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), home_button, -1);
317
318
319           sw = gtk_scrolled_window_new (NULL, NULL);
320           gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
321                                                GTK_SHADOW_ETCHED_IN);
322           gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
323                                           GTK_POLICY_AUTOMATIC,
324                                           GTK_POLICY_AUTOMATIC);
325
326           gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
327
328           /* Create the store and fill it with the contents of '/' */
329           parent = g_strdup ("/");
330           store = create_store ();
331           fill_store (store);
332
333           icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store));
334           gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
335                                             GTK_SELECTION_MULTIPLE);
336           g_object_unref (store);
337
338           /* Connect to the "clicked" signal of the "Up" tool button */
339           g_signal_connect (up_button, "clicked",
340                             G_CALLBACK (up_clicked), store);
341
342           /* Connect to the "clicked" signal of the "Home" tool button */
343           g_signal_connect (home_button, "clicked",
344                             G_CALLBACK (home_clicked), store);
345
346           /* We now set which model columns that correspond to the text
347            * and pixbuf of each item
348            */
349           gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view), COL_DISPLAY_NAME);
350           gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), COL_PIXBUF);
351
352           /* Connect to the "item-activated" signal */
353           g_signal_connect (icon_view, "item-activated",
354                             G_CALLBACK (item_activated), store);
355           gtk_container_add (GTK_CONTAINER (sw), icon_view);
356
357           gtk_widget_grab_focus (icon_view);
358         }
359     }
360
361   if (!gtk_widget_get_visible (window))
362     gtk_widget_show_all (window);
363   else
364     {
365       gtk_widget_destroy (window);
366       window = NULL;
367     }
368
369   return window;
370 }
371