]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/iconview.c
Add gdk_draw_rectangle_alpha_libgtk_only which uses XRenderFillRectangle
[~andy/gtk] / demos / gtk-demo / iconview.c
1 /* Icon View
2  *
3  * The GtkIconView widget is used to display and manipulate icons.  It
4  * uses a GtkTreeModel for data storage, so the list store example
5  * might be helpful.
6  */
7
8 #include <config.h>
9 #include <gtk/gtk.h>
10 #include <string.h>
11 #include "demo-common.h"
12
13 static GtkWidget *window = NULL;
14
15 #define FOLDER_NAME "gnome-fs-directory.png"
16 #define FILE_NAME "gnome-fs-regular.png"
17
18 enum
19 {
20   COL_PATH,
21   COL_DISPLAY_NAME,
22   COL_PIXBUF,
23   COL_IS_DIRECTORY,
24   NUM_COLS
25 };
26
27
28 static GdkPixbuf *file_pixbuf, *folder_pixbuf;
29 gchar *parent;
30 GtkToolItem *up_button;
31
32 /* Loads the images for the demo and returns whether the operation succeeded */
33 static gboolean
34 load_pixbufs (GError **error)
35 {
36   char *filename;
37
38   if (file_pixbuf)
39     return TRUE; /* already loaded earlier */
40
41   /* demo_find_file() looks in the the current directory first,
42    * so you can run gtk-demo without installing GTK, then looks
43    * in the location where the file is installed.
44    */
45   filename = demo_find_file (FILE_NAME, error);
46   if (!filename)
47     return FALSE; /* note that "error" was filled in and returned */
48
49   file_pixbuf = gdk_pixbuf_new_from_file (filename, error);
50   g_free (filename);
51   
52   if (!file_pixbuf)
53     return FALSE; /* Note that "error" was filled with a GError */
54   
55   filename = demo_find_file (FOLDER_NAME, error);
56   if (!filename)
57     return FALSE; /* note that "error" was filled in and returned */
58
59   folder_pixbuf = gdk_pixbuf_new_from_file (filename, error);
60   g_free (filename);
61
62   return TRUE;
63 }
64
65 static void
66 fill_store (GtkListStore *store)
67 {
68   GDir *dir;
69   const gchar *name;
70   GtkTreeIter iter;
71   
72   /* First clear the store */
73   gtk_list_store_clear (store);
74
75   /* Now go through the directory and extract all the file
76    * information */
77   dir = g_dir_open (parent, 0, NULL);
78   if (!dir)
79     return;
80
81   name = g_dir_read_name (dir);
82   while (name != NULL)
83     {
84       gchar *path, *display_name;
85       gboolean is_dir;
86       
87       /* We ignore hidden files that start with a '.' */
88       if (name[0] != '.')
89         {
90           path = g_build_filename (parent, name, NULL);
91
92           is_dir = g_file_test (path, G_FILE_TEST_IS_DIR);
93           
94           display_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
95
96           gtk_list_store_append (store, &iter);
97           gtk_list_store_set (store, &iter,
98                               COL_PATH, path,
99                               COL_DISPLAY_NAME, display_name,
100                               COL_IS_DIRECTORY, is_dir,
101                               COL_PIXBUF, is_dir ? folder_pixbuf : file_pixbuf,
102                               -1);
103           g_free (path);
104           g_free (display_name);
105         }
106
107       name = g_dir_read_name (dir);      
108     }
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 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 GtkWidget *
248 do_iconview (GtkWidget *do_widget)
249 {
250   if (!window)
251     {
252       GError *error;
253             
254       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
255       gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
256       
257       gtk_window_set_screen (GTK_WINDOW (window),
258                              gtk_widget_get_screen (do_widget));
259       gtk_window_set_title (GTK_WINDOW (window), "GtkIconView demo");
260
261       g_signal_connect (window, "destroy",
262                         G_CALLBACK (gtk_widget_destroyed), &window);
263
264       error = NULL;
265       if (!load_pixbufs (&error))
266         {
267           GtkWidget *dialog;
268
269           dialog = gtk_message_dialog_new (GTK_WINDOW (window),
270                                            GTK_DIALOG_DESTROY_WITH_PARENT,
271                                            GTK_MESSAGE_ERROR,
272                                            GTK_BUTTONS_CLOSE,
273                                            "Failed to load an image: %s",
274                                            error->message);
275
276           g_error_free (error);
277
278           g_signal_connect (dialog, "response",
279                             G_CALLBACK (gtk_widget_destroy), NULL);
280
281           gtk_widget_show (dialog);
282         }
283       else
284         {
285           GtkWidget *sw;
286           GtkWidget *icon_view;
287           GtkListStore *store;
288           GtkWidget *vbox;
289           GtkWidget *tool_bar;
290           GtkToolItem *home_button;
291           
292           vbox = gtk_vbox_new (FALSE, 0);
293           gtk_container_add (GTK_CONTAINER (window), vbox);
294
295           tool_bar = gtk_toolbar_new ();
296           gtk_box_pack_start (GTK_BOX (vbox), tool_bar, FALSE, FALSE, 0);
297           
298           up_button = gtk_tool_button_new_from_stock (GTK_STOCK_GO_UP);
299           gtk_tool_item_set_is_important (up_button, TRUE);
300           gtk_widget_set_sensitive (GTK_WIDGET (up_button), FALSE);
301           gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), up_button, -1);
302
303           home_button = gtk_tool_button_new_from_stock (GTK_STOCK_HOME);
304           gtk_tool_item_set_is_important (home_button, TRUE);
305           gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), home_button, -1);
306           
307           
308           sw = gtk_scrolled_window_new (NULL, NULL);
309           gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
310                                                GTK_SHADOW_ETCHED_IN);
311           gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
312                                           GTK_POLICY_AUTOMATIC,
313                                           GTK_POLICY_AUTOMATIC);
314           
315           gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
316           
317           /* Create the store and fill it with the contents of '/' */
318           parent = g_strdup ("/");
319           store = create_store ();
320           fill_store (store);
321
322           icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store));
323           gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
324                                             GTK_SELECTION_MULTIPLE);
325           g_object_unref (store);
326           
327           /* Connect to the "clicked" signal of the "Up" tool button */
328           g_signal_connect (up_button, "clicked",
329                             G_CALLBACK (up_clicked), store);
330
331           /* Connect to the "clicked" signal of the "Home" tool button */
332           g_signal_connect (home_button, "clicked",
333                             G_CALLBACK (home_clicked), store);
334           
335           /* We now set which model columns that correspont to the text
336            * and pixbuf of each item
337            */
338           gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view), COL_DISPLAY_NAME);
339           gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), COL_PIXBUF);
340
341           /* Connect to the "item_activated" signal */
342           g_signal_connect (icon_view, "item_activated",
343                             G_CALLBACK (item_activated), store);
344           gtk_container_add (GTK_CONTAINER (sw), icon_view);
345
346           gtk_widget_grab_focus (icon_view);
347         }
348     }
349   
350   if (!GTK_WIDGET_VISIBLE (window))
351     gtk_widget_show_all (window);
352   else
353     {
354       gtk_widget_destroy (window);
355       window = NULL;
356     }
357
358   return window;
359 }
360