Mercurial > geeqie.yaz
annotate src/view_file_icon.c @ 276:4f526d436873
Implement secure rc file saving.
First data is written to a temporary file, then if nothing
was wrong, this file is renamed to the final name.
This way the risk of corrupted rc file is greatly reduced.
The code is borrowed from ELinks (http://elinks.cz).
author | zas_ |
---|---|
date | Tue, 08 Apr 2008 21:55:58 +0000 |
parents | fbbb960a3857 |
children | 9995c5fb202a |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
3 * (C) 2006 John Ellis |
9 | 4 * |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 #include "gqview.h" | |
13 #include "view_file_icon.h" | |
14 | |
15 #include "cellrenderericon.h" | |
16 #include "collect.h" | |
17 #include "collect-io.h" | |
18 #include "collect-table.h" | |
19 #include "dnd.h" | |
20 #include "editors.h" | |
21 #include "img-view.h" | |
22 #include "info.h" | |
23 #include "filelist.h" | |
24 #include "layout.h" | |
25 #include "layout_image.h" | |
26 #include "menu.h" | |
27 #include "thumb.h" | |
28 #include "utilops.h" | |
29 #include "ui_bookmark.h" | |
30 #include "ui_fileops.h" | |
31 #include "ui_menu.h" | |
32 #include "ui_tree_edit.h" | |
33 | |
34 | |
35 #include <gdk/gdkkeysyms.h> /* for keyboard values */ | |
36 | |
37 /* between these, the icon width is increased by thumb_max_width / 2 */ | |
38 #define THUMB_MIN_ICON_WIDTH 128 | |
39 #define THUMB_MAX_ICON_WIDTH 150 | |
40 | |
41 #define VFICON_MAX_COLUMNS 32 | |
42 #define THUMB_BORDER_PADDING 2 | |
43 | |
44 #define VFICON_TIP_DELAY 500 | |
45 | |
46 enum { | |
47 FILE_COLUMN_POINTER = 0, | |
48 FILE_COLUMN_COUNT | |
49 }; | |
50 | |
51 typedef enum { | |
52 SELECTION_NONE = 0, | |
53 SELECTION_SELECTED = 1 << 0, | |
54 SELECTION_PRELIGHT = 1 << 1, | |
55 SELECTION_FOCUS = 1 << 2 | |
56 } SelectionType; | |
57 | |
58 typedef struct _IconData IconData; | |
59 struct _IconData | |
60 { | |
61 SelectionType selected; | |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
62 gint row; |
138 | 63 FileData *fd; |
9 | 64 }; |
65 | |
138 | 66 static gint vficon_index_by_id(ViewFileIcon *vfi, IconData *in_id); |
67 | |
68 static IconData *vficon_icon_data(ViewFileIcon *vfi, FileData *fd) | |
69 { | |
70 IconData *id = NULL; | |
71 GList *work; | |
72 | |
73 if (!fd) return NULL; | |
74 work = vfi->list; | |
75 while (work && !id) | |
76 { | |
77 IconData *chk = work->data; | |
78 work = work->next; | |
79 if (chk->fd == fd) id = chk; | |
80 } | |
81 return id; | |
82 } | |
83 | |
9 | 84 |
85 static gint iconlist_read(const gchar *path, GList **list) | |
86 { | |
87 GList *temp; | |
88 GList *work; | |
89 | |
90 if (!filelist_read(path, &temp, NULL)) return FALSE; | |
91 | |
92 work = temp; | |
93 while (work) | |
94 { | |
95 FileData *fd; | |
96 IconData *id; | |
97 | |
98 fd = work->data; | |
138 | 99 g_assert(fd->magick == 0x12345678); |
9 | 100 id = g_new0(IconData, 1); |
101 | |
102 id->selected = SELECTION_NONE; | |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
103 id->row = -1; |
138 | 104 id->fd = fd; |
9 | 105 |
106 work->data = id; | |
107 work = work->next; | |
108 } | |
109 | |
110 *list = temp; | |
111 | |
112 return TRUE; | |
113 } | |
114 | |
115 static void iconlist_free(GList *list) | |
116 { | |
138 | 117 GList *work = list; |
118 while (work) | |
119 { | |
120 IconData *id = work->data; | |
121 file_data_unref(id->fd); | |
122 g_free(id); | |
123 work = work->next; | |
124 } | |
125 | |
126 g_list_free(list); | |
127 | |
128 } | |
129 | |
130 gint iconlist_sort_file_cb(void *a, void *b) | |
131 { | |
132 IconData *ida = a; | |
133 IconData *idb = b; | |
134 return filelist_sort_compare_filedata(ida->fd, idb->fd); | |
135 } | |
136 GList *iconlist_sort(GList *list, SortType method, gint ascend) | |
137 { | |
138 return filelist_sort_full(list, method, ascend, (GCompareFunc) iconlist_sort_file_cb); | |
139 } | |
140 | |
141 GList *iconlist_insert_sort(GList *list, IconData *id, SortType method, gint ascend) | |
142 { | |
143 return filelist_insert_sort_full(list, id, method, ascend, (GCompareFunc) iconlist_sort_file_cb); | |
9 | 144 } |
145 | |
146 | |
147 static void vficon_toggle_filenames(ViewFileIcon *vfi); | |
138 | 148 static void vficon_selection_remove(ViewFileIcon *vfi, IconData *id, SelectionType mask, GtkTreeIter *iter); |
9 | 149 static void vficon_move_focus(ViewFileIcon *vfi, gint row, gint col, gint relative); |
138 | 150 static void vficon_set_focus(ViewFileIcon *vfi, IconData *id); |
9 | 151 static void vficon_thumb_update(ViewFileIcon *vfi); |
152 static void vficon_populate_at_new_size(ViewFileIcon *vfi, gint w, gint h, gint force); | |
153 | |
154 | |
155 /* | |
156 *----------------------------------------------------------------------------- | |
157 * pop-up menu | |
158 *----------------------------------------------------------------------------- | |
159 */ | |
160 | |
161 static GList *vficon_pop_menu_file_list(ViewFileIcon *vfi) | |
162 { | |
138 | 163 if (!vfi->click_id) return NULL; |
164 | |
165 if (vfi->click_id->selected & SELECTION_SELECTED) | |
9 | 166 { |
167 return vficon_selection_get_list(vfi); | |
168 } | |
169 | |
138 | 170 return g_list_append(NULL, file_data_ref(vfi->click_id->fd)); |
9 | 171 } |
172 | |
173 static void vficon_pop_menu_edit_cb(GtkWidget *widget, gpointer data) | |
174 { | |
175 ViewFileIcon *vfi; | |
176 gint n; | |
177 GList *list; | |
178 | |
179 vfi = submenu_item_get_data(widget); | |
180 n = GPOINTER_TO_INT(data); | |
181 | |
182 if (!vfi) return; | |
183 | |
184 list = vficon_pop_menu_file_list(vfi); | |
138 | 185 start_editor_from_filelist(n, list); |
186 filelist_free(list); | |
9 | 187 } |
188 | |
189 static void vficon_pop_menu_info_cb(GtkWidget *widget, gpointer data) | |
190 { | |
191 ViewFileIcon *vfi = data; | |
192 | |
193 info_window_new(NULL, vficon_pop_menu_file_list(vfi)); | |
194 } | |
195 | |
196 static void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data) | |
197 { | |
198 ViewFileIcon *vfi = data; | |
199 | |
138 | 200 if (!vfi->click_id) return; |
201 | |
202 if (vfi->click_id->selected & SELECTION_SELECTED) | |
9 | 203 { |
204 GList *list; | |
205 | |
206 list = vficon_selection_get_list(vfi); | |
207 view_window_new_from_list(list); | |
138 | 208 filelist_free(list); |
9 | 209 } |
210 else | |
211 { | |
138 | 212 view_window_new(vfi->click_id->fd); |
9 | 213 } |
214 } | |
215 | |
216 static void vficon_pop_menu_copy_cb(GtkWidget *widget, gpointer data) | |
217 { | |
218 ViewFileIcon *vfi = data; | |
219 | |
220 file_util_copy(NULL, vficon_pop_menu_file_list(vfi), NULL, vfi->listview); | |
221 } | |
222 | |
223 static void vficon_pop_menu_move_cb(GtkWidget *widget, gpointer data) | |
224 { | |
225 ViewFileIcon *vfi = data; | |
226 | |
227 file_util_move(NULL, vficon_pop_menu_file_list(vfi), NULL, vfi->listview); | |
228 } | |
229 | |
230 static void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data) | |
231 { | |
232 ViewFileIcon *vfi = data; | |
233 | |
234 file_util_rename(NULL, vficon_pop_menu_file_list(vfi), vfi->listview); | |
235 } | |
236 | |
237 static void vficon_pop_menu_delete_cb(GtkWidget *widget, gpointer data) | |
238 { | |
239 ViewFileIcon *vfi = data; | |
240 | |
241 file_util_delete(NULL, vficon_pop_menu_file_list(vfi), vfi->listview); | |
242 } | |
243 | |
244 static void vficon_pop_menu_sort_cb(GtkWidget *widget, gpointer data) | |
245 { | |
246 ViewFileIcon *vfi; | |
247 SortType type; | |
113
55166d93498d
Fri Nov 24 21:37:01 2006 John Ellis <johne@verizon.net>
gqview
parents:
111
diff
changeset
|
248 |
55166d93498d
Fri Nov 24 21:37:01 2006 John Ellis <johne@verizon.net>
gqview
parents:
111
diff
changeset
|
249 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return; |
9 | 250 |
251 vfi = submenu_item_get_data(widget); | |
252 if (!vfi) return; | |
253 | |
254 type = (SortType)GPOINTER_TO_INT(data); | |
255 | |
256 if (vfi->layout) | |
257 { | |
258 layout_sort_set(vfi->layout, type, vfi->sort_ascend); | |
259 } | |
260 else | |
261 { | |
262 vficon_sort_set(vfi, type, vfi->sort_ascend); | |
263 } | |
264 } | |
265 | |
266 static void vficon_pop_menu_sort_ascend_cb(GtkWidget *widget, gpointer data) | |
267 { | |
268 ViewFileIcon *vfi = data; | |
269 | |
270 if (vfi->layout) | |
271 { | |
272 layout_sort_set(vfi->layout, vfi->sort_method, !vfi->sort_ascend); | |
273 } | |
274 else | |
275 { | |
276 vficon_sort_set(vfi, vfi->sort_method, !vfi->sort_ascend); | |
277 } | |
278 } | |
279 | |
280 static void vficon_pop_menu_list_cb(GtkWidget *widget, gpointer data) | |
281 { | |
282 ViewFileIcon *vfi = data; | |
283 | |
284 if (vfi->layout) layout_views_set(vfi->layout, vfi->layout->tree_view, FALSE); | |
285 } | |
286 | |
287 static void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data) | |
288 { | |
289 ViewFileIcon *vfi = data; | |
290 | |
291 vficon_toggle_filenames(vfi); | |
292 } | |
293 | |
294 static void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data) | |
295 { | |
296 ViewFileIcon *vfi = data; | |
297 | |
298 vficon_refresh(vfi); | |
299 } | |
300 | |
301 static void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data) | |
302 { | |
303 ViewFileIcon *vfi = data; | |
138 | 304 vficon_selection_remove(vfi, vfi->click_id, SELECTION_PRELIGHT, NULL); |
305 vfi->click_id = NULL; | |
9 | 306 vfi->popup = NULL; |
307 } | |
308 | |
309 static GtkWidget *vficon_pop_menu(ViewFileIcon *vfi, gint active) | |
310 { | |
311 GtkWidget *menu; | |
312 GtkWidget *item; | |
313 GtkWidget *submenu; | |
314 | |
315 menu = popup_menu_short_lived(); | |
316 | |
317 g_signal_connect(G_OBJECT(menu), "destroy", | |
318 G_CALLBACK(vficon_popup_destroy_cb), vfi); | |
319 | |
320 submenu_add_edit(menu, &item, G_CALLBACK(vficon_pop_menu_edit_cb), vfi); | |
321 gtk_widget_set_sensitive(item, active); | |
322 | |
323 item = menu_item_add_stock(menu, _("_Properties"), GTK_STOCK_PROPERTIES, G_CALLBACK(vficon_pop_menu_info_cb), vfi); | |
324 gtk_widget_set_sensitive(item, active); | |
325 | |
326 item = menu_item_add_stock(menu, _("View in _new window"), GTK_STOCK_NEW, G_CALLBACK(vficon_pop_menu_view_cb), vfi); | |
327 gtk_widget_set_sensitive(item, active); | |
328 | |
329 menu_item_add_divider(menu); | |
330 item = menu_item_add_stock(menu, _("_Copy..."), GTK_STOCK_COPY, G_CALLBACK(vficon_pop_menu_copy_cb), vfi); | |
331 gtk_widget_set_sensitive(item, active); | |
332 item = menu_item_add(menu, _("_Move..."), G_CALLBACK(vficon_pop_menu_move_cb), vfi); | |
333 gtk_widget_set_sensitive(item, active); | |
334 item = menu_item_add(menu, _("_Rename..."), G_CALLBACK(vficon_pop_menu_rename_cb), vfi); | |
335 gtk_widget_set_sensitive(item, active); | |
336 item = menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(vficon_pop_menu_delete_cb), vfi); | |
337 gtk_widget_set_sensitive(item, active); | |
338 | |
339 menu_item_add_divider(menu); | |
340 | |
341 submenu = submenu_add_sort(NULL, G_CALLBACK(vficon_pop_menu_sort_cb), vfi, | |
342 FALSE, FALSE, TRUE, vfi->sort_method); | |
343 menu_item_add_divider(submenu); | |
344 menu_item_add_check(submenu, _("Ascending"), vfi->sort_ascend, | |
345 G_CALLBACK(vficon_pop_menu_sort_ascend_cb), vfi); | |
346 | |
347 item = menu_item_add(menu, _("_Sort"), NULL, NULL); | |
348 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); | |
349 | |
350 menu_item_add_check(menu, _("View as _icons"), TRUE, | |
351 G_CALLBACK(vficon_pop_menu_list_cb), vfi); | |
352 menu_item_add_check(menu, _("Show filename _text"), vfi->show_text, | |
353 G_CALLBACK(vficon_pop_menu_show_names_cb), vfi); | |
354 menu_item_add_stock(menu, _("Re_fresh"), GTK_STOCK_REFRESH, G_CALLBACK(vficon_pop_menu_refresh_cb), vfi); | |
355 | |
356 return menu; | |
357 } | |
358 | |
359 /* | |
360 *------------------------------------------------------------------- | |
361 * signals | |
362 *------------------------------------------------------------------- | |
363 */ | |
364 | |
365 static void vficon_send_update(ViewFileIcon *vfi) | |
366 { | |
367 if (vfi->func_status) vfi->func_status(vfi, vfi->data_status); | |
368 } | |
369 | |
138 | 370 static void vficon_send_layout_select(ViewFileIcon *vfi, IconData *id) |
9 | 371 { |
138 | 372 FileData *read_ahead_fd = NULL; |
144 | 373 FileData *sel_fd; |
374 FileData *cur_fd; | |
375 | |
376 if (!vfi->layout || !id || !id->fd) return; | |
377 | |
378 sel_fd = id->fd; | |
379 | |
380 cur_fd = layout_image_get_fd(vfi->layout); | |
381 if (sel_fd == cur_fd) return; /* no change */ | |
382 | |
9 | 383 if (enable_read_ahead) |
384 { | |
385 gint row; | |
386 | |
138 | 387 row = g_list_index(vfi->list, id); |
144 | 388 if (row > vficon_index_by_fd(vfi, cur_fd) && |
9 | 389 row + 1 < vficon_count(vfi, NULL)) |
390 { | |
144 | 391 read_ahead_fd = vficon_index_get_data(vfi, row + 1); |
9 | 392 } |
393 else if (row > 0) | |
394 { | |
144 | 395 read_ahead_fd = vficon_index_get_data(vfi, row - 1); |
9 | 396 } |
397 } | |
398 | |
144 | 399 layout_image_set_with_ahead(vfi->layout, sel_fd, read_ahead_fd); |
9 | 400 } |
401 | |
402 static void vficon_toggle_filenames(ViewFileIcon *vfi) | |
403 { | |
404 vfi->show_text = !vfi->show_text; | |
405 show_icon_names = vfi->show_text; | |
406 | |
407 vficon_populate_at_new_size(vfi, vfi->listview->allocation.width, vfi->listview->allocation.height, TRUE); | |
408 } | |
409 | |
410 static gint vficon_get_icon_width(ViewFileIcon *vfi) | |
411 { | |
412 gint width; | |
413 | |
414 if (!vfi->show_text) return thumb_max_width; | |
415 | |
416 width = thumb_max_width + thumb_max_width / 2; | |
417 if (width < THUMB_MIN_ICON_WIDTH) width = THUMB_MIN_ICON_WIDTH; | |
418 if (width > THUMB_MAX_ICON_WIDTH) width = thumb_max_width; | |
419 | |
420 return width; | |
421 } | |
422 | |
423 /* | |
424 *------------------------------------------------------------------- | |
425 * misc utils | |
426 *------------------------------------------------------------------- | |
427 */ | |
428 | |
138 | 429 static gint vficon_find_position(ViewFileIcon *vfi, IconData *id, gint *row, gint *col) |
9 | 430 { |
431 gint n; | |
432 | |
138 | 433 n = g_list_index(vfi->list, id); |
9 | 434 |
435 if (n < 0) return FALSE; | |
436 | |
437 *row = n / vfi->columns; | |
438 *col = n - (*row * vfi->columns); | |
439 | |
440 return TRUE; | |
441 } | |
442 | |
138 | 443 static gint vficon_find_iter(ViewFileIcon *vfi, IconData *id, GtkTreeIter *iter, gint *column) |
9 | 444 { |
445 GtkTreeModel *store; | |
446 gint row, col; | |
447 | |
448 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
138 | 449 if (!vficon_find_position(vfi, id, &row, &col)) return FALSE; |
9 | 450 if (!gtk_tree_model_iter_nth_child(store, iter, NULL, row)) return FALSE; |
451 if (column) *column = col; | |
452 | |
453 return TRUE; | |
454 } | |
455 | |
138 | 456 static IconData *vficon_find_data(ViewFileIcon *vfi, gint row, gint col, GtkTreeIter *iter) |
9 | 457 { |
458 GtkTreeModel *store; | |
459 GtkTreeIter p; | |
460 | |
461 if (row < 0 || col < 0) return NULL; | |
462 | |
463 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
464 if (gtk_tree_model_iter_nth_child(store, &p, NULL, row)) | |
465 { | |
466 GList *list; | |
467 | |
468 gtk_tree_model_get(store, &p, FILE_COLUMN_POINTER, &list, -1); | |
469 if (!list) return NULL; | |
470 | |
471 if (iter) *iter = p; | |
472 | |
473 return g_list_nth_data(list, col); | |
474 } | |
475 | |
476 return NULL; | |
477 } | |
478 | |
138 | 479 static IconData *vficon_find_data_by_coord(ViewFileIcon *vfi, gint x, gint y, GtkTreeIter *iter) |
9 | 480 { |
481 GtkTreePath *tpath; | |
482 GtkTreeViewColumn *column; | |
483 | |
484 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vfi->listview), x, y, | |
485 &tpath, &column, NULL, NULL)) | |
486 { | |
487 GtkTreeModel *store; | |
488 GtkTreeIter row; | |
489 GList *list; | |
490 gint n; | |
491 | |
492 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
493 gtk_tree_model_get_iter(store, &row, tpath); | |
494 gtk_tree_path_free(tpath); | |
495 | |
496 gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1); | |
497 | |
498 n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_number")); | |
499 if (list) | |
500 { | |
501 if (iter) *iter = row; | |
502 return g_list_nth_data(list, n); | |
503 } | |
504 } | |
505 | |
506 return NULL; | |
507 } | |
508 | |
509 /* | |
510 *------------------------------------------------------------------- | |
511 * tooltip type window | |
512 *------------------------------------------------------------------- | |
513 */ | |
514 | |
515 static void tip_show(ViewFileIcon *vfi) | |
516 { | |
517 GtkWidget *label; | |
518 gint x, y; | |
519 | |
520 if (vfi->tip_window) return; | |
521 | |
522 gdk_window_get_pointer(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vfi->listview)), &x, &y, NULL); | |
523 | |
138 | 524 vfi->tip_id = vficon_find_data_by_coord(vfi, x, y, NULL); |
525 if (!vfi->tip_id) return; | |
9 | 526 |
527 vfi->tip_window = gtk_window_new(GTK_WINDOW_POPUP); | |
528 gtk_window_set_resizable(GTK_WINDOW(vfi->tip_window), FALSE); | |
529 gtk_container_set_border_width(GTK_CONTAINER(vfi->tip_window), 2); | |
530 | |
138 | 531 label = gtk_label_new(vfi->tip_id->fd->name); |
9 | 532 |
533 g_object_set_data(G_OBJECT(vfi->tip_window), "tip_label", label); | |
534 gtk_container_add(GTK_CONTAINER(vfi->tip_window), label); | |
535 gtk_widget_show(label); | |
536 | |
537 gdk_window_get_pointer(NULL, &x, &y, NULL); | |
538 | |
539 if (!GTK_WIDGET_REALIZED(vfi->tip_window)) gtk_widget_realize(vfi->tip_window); | |
540 gtk_window_move(GTK_WINDOW(vfi->tip_window), x + 16, y + 16); | |
541 gtk_widget_show(vfi->tip_window); | |
542 } | |
543 | |
544 static void tip_hide(ViewFileIcon *vfi) | |
545 { | |
546 if (vfi->tip_window) gtk_widget_destroy(vfi->tip_window); | |
547 vfi->tip_window = NULL; | |
548 } | |
549 | |
550 static gint tip_schedule_cb(gpointer data) | |
551 { | |
552 ViewFileIcon *vfi = data; | |
553 GtkWidget *window; | |
554 | |
555 if (vfi->tip_delay_id == -1) return FALSE; | |
556 | |
557 window = gtk_widget_get_toplevel(vfi->listview); | |
558 | |
559 if (GTK_WIDGET_SENSITIVE(window) && | |
560 GTK_WINDOW(window)->has_focus) | |
561 { | |
562 tip_show(vfi); | |
563 } | |
564 | |
565 vfi->tip_delay_id = -1; | |
566 return FALSE; | |
567 } | |
568 | |
569 static void tip_schedule(ViewFileIcon *vfi) | |
570 { | |
571 tip_hide(vfi); | |
572 | |
573 if (vfi->tip_delay_id != -1) | |
574 { | |
575 g_source_remove(vfi->tip_delay_id); | |
576 vfi->tip_delay_id = -1; | |
577 } | |
578 | |
579 if (!vfi->show_text) | |
580 { | |
581 vfi->tip_delay_id = g_timeout_add(VFICON_TIP_DELAY, tip_schedule_cb, vfi); | |
582 } | |
583 } | |
584 | |
585 static void tip_unschedule(ViewFileIcon *vfi) | |
586 { | |
587 tip_hide(vfi); | |
588 | |
589 if (vfi->tip_delay_id != -1) g_source_remove(vfi->tip_delay_id); | |
590 vfi->tip_delay_id = -1; | |
591 } | |
592 | |
138 | 593 static void tip_update(ViewFileIcon *vfi, IconData *id) |
9 | 594 { |
595 if (vfi->tip_window) | |
596 { | |
597 gint x, y; | |
598 | |
599 gdk_window_get_pointer(NULL, &x, &y, NULL); | |
600 gtk_window_move(GTK_WINDOW(vfi->tip_window), x + 16, y + 16); | |
601 | |
138 | 602 if (id != vfi->tip_id) |
9 | 603 { |
604 GtkWidget *label; | |
605 | |
138 | 606 vfi->tip_id = id; |
607 | |
608 if (!vfi->tip_id) | |
9 | 609 { |
610 tip_hide(vfi); | |
611 tip_schedule(vfi); | |
612 return; | |
613 } | |
614 | |
615 label = g_object_get_data(G_OBJECT(vfi->tip_window), "tip_label"); | |
138 | 616 gtk_label_set_text(GTK_LABEL(label), vfi->tip_id->fd->name); |
9 | 617 } |
618 } | |
619 else | |
620 { | |
621 tip_schedule(vfi); | |
622 } | |
623 } | |
624 | |
625 /* | |
626 *------------------------------------------------------------------- | |
627 * dnd | |
628 *------------------------------------------------------------------- | |
629 */ | |
630 | |
631 static void vficon_dnd_get(GtkWidget *widget, GdkDragContext *context, | |
632 GtkSelectionData *selection_data, guint info, | |
633 guint time, gpointer data) | |
634 { | |
635 ViewFileIcon *vfi = data; | |
636 GList *list = NULL; | |
637 gchar *uri_text = NULL; | |
638 gint total; | |
639 | |
138 | 640 if (!vfi->click_id) return; |
641 | |
642 if (vfi->click_id->selected & SELECTION_SELECTED) | |
9 | 643 { |
644 list = vficon_selection_get_list(vfi); | |
645 } | |
646 else | |
647 { | |
138 | 648 list = g_list_append(NULL, file_data_ref(vfi->click_id->fd)); |
9 | 649 } |
650 | |
651 if (!list) return; | |
138 | 652 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN)); |
653 filelist_free(list); | |
9 | 654 |
655 if (debug) printf(uri_text); | |
656 | |
657 gtk_selection_data_set(selection_data, selection_data->target, | |
64
04ff0df3ad2f
Mon Aug 15 17:13:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
658 8, (guchar *)uri_text, total); |
9 | 659 g_free(uri_text); |
660 } | |
661 | |
662 static void vficon_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data) | |
663 { | |
664 ViewFileIcon *vfi = data; | |
665 | |
666 tip_unschedule(vfi); | |
667 | |
138 | 668 if (vfi->click_id && vfi->click_id->fd->pixbuf) |
9 | 669 { |
670 gint items; | |
671 | |
138 | 672 if (vfi->click_id->selected & SELECTION_SELECTED) |
9 | 673 items = g_list_length(vfi->selection); |
674 else | |
675 items = 1; | |
676 | |
138 | 677 dnd_set_drag_icon(widget, context, vfi->click_id->fd->pixbuf, items); |
9 | 678 } |
679 } | |
680 | |
681 static void vficon_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data) | |
682 { | |
683 ViewFileIcon *vfi = data; | |
684 | |
138 | 685 vficon_selection_remove(vfi, vfi->click_id, SELECTION_PRELIGHT, NULL); |
9 | 686 |
687 if (context->action == GDK_ACTION_MOVE) | |
688 { | |
689 vficon_refresh(vfi); | |
690 } | |
691 | |
692 tip_unschedule(vfi); | |
693 } | |
694 | |
695 static void vficon_dnd_init(ViewFileIcon *vfi) | |
696 { | |
697 gtk_drag_source_set(vfi->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, | |
698 dnd_file_drag_types, dnd_file_drag_types_count, | |
699 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); | |
700 g_signal_connect(G_OBJECT(vfi->listview), "drag_data_get", | |
701 G_CALLBACK(vficon_dnd_get), vfi); | |
702 g_signal_connect(G_OBJECT(vfi->listview), "drag_begin", | |
703 G_CALLBACK(vficon_dnd_begin), vfi); | |
704 g_signal_connect(G_OBJECT(vfi->listview), "drag_end", | |
705 G_CALLBACK(vficon_dnd_end), vfi); | |
706 } | |
707 | |
708 /* | |
709 *------------------------------------------------------------------- | |
710 * cell updates | |
711 *------------------------------------------------------------------- | |
712 */ | |
713 | |
138 | 714 static void vficon_selection_set(ViewFileIcon *vfi, IconData *id, SelectionType value, GtkTreeIter *iter) |
9 | 715 { |
716 GtkTreeModel *store; | |
717 GList *list; | |
718 | |
138 | 719 if (!id) return; |
720 | |
9 | 721 |
722 if (id->selected == value) return; | |
723 id->selected = value; | |
724 | |
725 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
726 if (iter) | |
727 { | |
728 gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1); | |
729 if (list) gtk_list_store_set(GTK_LIST_STORE(store), iter, FILE_COLUMN_POINTER, list, -1); | |
730 } | |
731 else | |
732 { | |
733 GtkTreeIter row; | |
734 | |
138 | 735 if (vficon_find_iter(vfi, id, &row, NULL)) |
9 | 736 { |
737 gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1); | |
738 if (list) gtk_list_store_set(GTK_LIST_STORE(store), &row, FILE_COLUMN_POINTER, list, -1); | |
739 } | |
740 } | |
741 } | |
742 | |
138 | 743 static void vficon_selection_add(ViewFileIcon *vfi, IconData *id, SelectionType mask, GtkTreeIter *iter) |
9 | 744 { |
138 | 745 if (!id) return; |
746 | |
747 vficon_selection_set(vfi, id, id->selected | mask, iter); | |
9 | 748 } |
749 | |
138 | 750 static void vficon_selection_remove(ViewFileIcon *vfi, IconData *id, SelectionType mask, GtkTreeIter *iter) |
9 | 751 { |
138 | 752 if (!id) return; |
753 | |
754 vficon_selection_set(vfi, id, id->selected & ~mask, iter); | |
9 | 755 } |
756 | |
757 /* | |
758 *------------------------------------------------------------------- | |
759 * selections | |
760 *------------------------------------------------------------------- | |
761 */ | |
762 | |
763 static void vficon_verify_selections(ViewFileIcon *vfi) | |
764 { | |
765 GList *work; | |
766 | |
767 work = vfi->selection; | |
768 while (work) | |
769 { | |
138 | 770 IconData *id = work->data; |
9 | 771 work = work->next; |
138 | 772 if (vficon_index_by_id(vfi, id) < 0) |
9 | 773 { |
138 | 774 vfi->selection = g_list_remove(vfi->selection, id); |
9 | 775 } |
776 } | |
777 } | |
778 | |
779 void vficon_select_all(ViewFileIcon *vfi) | |
780 { | |
781 GList *work; | |
782 | |
783 g_list_free(vfi->selection); | |
784 vfi->selection = NULL; | |
785 | |
786 work = vfi->list; | |
787 while (work) | |
788 { | |
138 | 789 IconData *id = work->data; |
790 vfi->selection = g_list_append(vfi->selection, id); | |
9 | 791 vficon_selection_add(vfi, work->data, SELECTION_SELECTED, NULL); |
792 work = work->next; | |
793 } | |
794 | |
795 vficon_send_update(vfi); | |
796 } | |
797 | |
798 void vficon_select_none(ViewFileIcon *vfi) | |
799 { | |
800 GList *work; | |
801 | |
802 work = vfi->selection; | |
803 while (work) | |
804 { | |
805 vficon_selection_remove(vfi, work->data, SELECTION_SELECTED, NULL); | |
806 work = work->next; | |
807 } | |
808 | |
809 g_list_free(vfi->selection); | |
810 vfi->selection = NULL; | |
811 | |
812 vficon_send_update(vfi); | |
813 } | |
814 | |
138 | 815 static void vficon_select(ViewFileIcon *vfi, IconData *id) |
9 | 816 { |
138 | 817 vfi->prev_selection = id; |
818 | |
819 if (!id || id->selected & SELECTION_SELECTED) return; | |
820 | |
821 vfi->selection = g_list_append(vfi->selection, id); | |
822 vficon_selection_add(vfi, id, SELECTION_SELECTED, NULL); | |
9 | 823 |
824 vficon_send_update(vfi); | |
825 } | |
826 | |
138 | 827 static void vficon_unselect(ViewFileIcon *vfi, IconData *id) |
9 | 828 { |
138 | 829 vfi->prev_selection = id; |
830 | |
831 if (!id || !(id->selected & SELECTION_SELECTED) ) return; | |
832 | |
833 vfi->selection = g_list_remove(vfi->selection, id); | |
834 vficon_selection_remove(vfi, id, SELECTION_SELECTED, NULL); | |
9 | 835 |
836 vficon_send_update(vfi); | |
837 } | |
838 | |
138 | 839 static void vficon_select_util(ViewFileIcon *vfi, IconData *id, gint select) |
9 | 840 { |
841 if (select) | |
842 { | |
138 | 843 vficon_select(vfi, id); |
9 | 844 } |
845 else | |
846 { | |
138 | 847 vficon_unselect(vfi, id); |
9 | 848 } |
849 } | |
850 | |
138 | 851 static void vficon_select_region_util(ViewFileIcon *vfi, IconData *start, IconData *end, gint select) |
9 | 852 { |
853 gint row1, col1; | |
854 gint row2, col2; | |
855 gint t; | |
856 gint i, j; | |
857 | |
858 if (!vficon_find_position(vfi, start, &row1, &col1) || | |
859 !vficon_find_position(vfi, end, &row2, &col2) ) return; | |
860 | |
861 vfi->prev_selection = end; | |
862 | |
863 if (!collection_rectangular_selection) | |
864 { | |
865 GList *work; | |
138 | 866 IconData *id; |
9 | 867 |
868 if (g_list_index(vfi->list, start) > g_list_index(vfi->list, end)) | |
869 { | |
138 | 870 id = start; |
9 | 871 start = end; |
138 | 872 end = id; |
9 | 873 } |
874 | |
875 work = g_list_find(vfi->list, start); | |
876 while (work) | |
877 { | |
138 | 878 id = work->data; |
879 vficon_select_util(vfi, id, select); | |
9 | 880 |
881 if (work->data != end) | |
882 work = work->next; | |
883 else | |
884 work = NULL; | |
885 } | |
886 return; | |
887 } | |
888 | |
889 if (row2 < row1) | |
890 { | |
891 t = row1; | |
892 row1 = row2; | |
893 row2 = t; | |
894 } | |
895 if (col2 < col1) | |
896 { | |
897 t = col1; | |
898 col1 = col2; | |
899 col2 = t; | |
900 } | |
901 | |
902 if (debug) printf("table: %d x %d to %d x %d\n", row1, col1, row2, col2); | |
903 | |
904 for (i = row1; i <= row2; i++) | |
905 { | |
906 for (j = col1; j <= col2; j++) | |
907 { | |
138 | 908 IconData *id = vficon_find_data(vfi, i, j, NULL); |
909 if (id) vficon_select_util(vfi, id, select); | |
9 | 910 } |
911 } | |
912 } | |
913 | |
914 gint vficon_index_is_selected(ViewFileIcon *vfi, gint row) | |
915 { | |
138 | 916 IconData *id = g_list_nth_data(vfi->list, row); |
917 | |
918 if (!id) return FALSE; | |
919 | |
920 return (id->selected & SELECTION_SELECTED); | |
9 | 921 } |
922 | |
923 gint vficon_selection_count(ViewFileIcon *vfi, gint64 *bytes) | |
924 { | |
925 if (bytes) | |
926 { | |
927 gint64 b = 0; | |
928 GList *work; | |
929 | |
930 work = vfi->selection; | |
931 while (work) | |
932 { | |
138 | 933 IconData *id = work->data; |
934 FileData *fd = id->fd; | |
935 g_assert(fd->magick == 0x12345678); | |
9 | 936 b += fd->size; |
937 | |
938 work = work->next; | |
939 } | |
940 | |
941 *bytes = b; | |
942 } | |
943 | |
944 return g_list_length(vfi->selection); | |
945 } | |
946 | |
947 GList *vficon_selection_get_list(ViewFileIcon *vfi) | |
948 { | |
949 GList *list = NULL; | |
950 GList *work; | |
951 | |
952 work = vfi->selection; | |
953 while (work) | |
954 { | |
138 | 955 IconData *id = work->data; |
956 FileData *fd = id->fd; | |
957 g_assert(fd->magick == 0x12345678); | |
958 | |
959 list = g_list_prepend(list, file_data_ref(fd)); | |
9 | 960 |
961 work = work->next; | |
962 } | |
963 | |
964 list = g_list_reverse(list); | |
965 | |
966 return list; | |
967 } | |
968 | |
969 GList *vficon_selection_get_list_by_index(ViewFileIcon *vfi) | |
970 { | |
971 GList *list = NULL; | |
972 GList *work; | |
973 | |
974 work = vfi->selection; | |
975 while (work) | |
976 { | |
977 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vfi->list, work->data))); | |
978 work = work->next; | |
979 } | |
980 | |
981 return g_list_reverse(list); | |
982 } | |
983 | |
138 | 984 static void vficon_select_by_id(ViewFileIcon *vfi, IconData *id) |
985 { | |
986 if (!id) return; | |
987 | |
988 if (!(id->selected & SELECTION_SELECTED)) | |
989 { | |
990 vficon_select_none(vfi); | |
991 vficon_select(vfi, id); | |
992 } | |
993 | |
994 vficon_set_focus(vfi, id); | |
995 } | |
996 | |
997 | |
9 | 998 void vficon_select_by_path(ViewFileIcon *vfi, const gchar *path) |
999 { | |
138 | 1000 IconData *id = NULL; |
9 | 1001 GList *work; |
1002 | |
1003 if (!path) return; | |
1004 | |
1005 work = vfi->list; | |
138 | 1006 while (work && !id) |
9 | 1007 { |
138 | 1008 IconData *chk = work->data; |
9 | 1009 work = work->next; |
138 | 1010 if (strcmp(chk->fd->path, path) == 0) id = chk; |
9 | 1011 } |
138 | 1012 vficon_select_by_id(vfi, id); |
1013 } | |
1014 | |
1015 void vficon_select_by_fd(ViewFileIcon *vfi, FileData *fd) | |
1016 { | |
1017 IconData *id = NULL; | |
1018 GList *work; | |
9 | 1019 |
1020 if (!fd) return; | |
138 | 1021 work = vfi->list; |
1022 while (work && !id) | |
9 | 1023 { |
138 | 1024 IconData *chk = work->data; |
1025 work = work->next; | |
1026 if (chk->fd == fd) id = chk; | |
9 | 1027 } |
138 | 1028 vficon_select_by_id(vfi, id); |
9 | 1029 } |
1030 | |
165 | 1031 void vficon_mark_to_selection(ViewFileIcon *vfi, gint mark, MarkToSelectionMode mode) |
1032 { | |
1033 GList *work; | |
1034 | |
1035 work = vfi->list; | |
1036 while (work) | |
1037 { | |
1038 IconData *id = work->data; | |
1039 FileData *fd = id->fd; | |
1040 gboolean mark_val, selected; | |
1041 | |
1042 g_assert(fd->magick == 0x12345678); | |
1043 | |
1044 mark_val = fd->marks[mark]; | |
1045 selected = (id->selected & SELECTION_SELECTED); | |
1046 | |
1047 switch (mode) | |
1048 { | |
1049 case MTS_MODE_SET: selected = mark_val; | |
1050 break; | |
1051 case MTS_MODE_OR: selected = mark_val | selected; | |
1052 break; | |
1053 case MTS_MODE_AND: selected = mark_val & selected; | |
1054 break; | |
1055 case MTS_MODE_MINUS: selected = !mark_val & selected; | |
1056 break; | |
1057 } | |
1058 | |
1059 vficon_select_util(vfi, id, selected); | |
1060 | |
1061 work = work->next; | |
1062 } | |
1063 } | |
1064 | |
1065 void vficon_selection_to_mark(ViewFileIcon *vfi, gint mark, SelectionToMarkMode mode) | |
1066 { | |
1067 GList *slist; | |
1068 GList *work; | |
1069 | |
1070 g_assert(mark >= 0 && mark < FILEDATA_MARKS_SIZE); | |
1071 | |
1072 slist = vficon_selection_get_list(vfi); | |
1073 work = slist; | |
1074 while (work) | |
1075 { | |
1076 FileData *fd = work->data; | |
1077 | |
1078 switch (mode) | |
1079 { | |
1080 case STM_MODE_SET: fd->marks[mark] = 1; | |
1081 break; | |
1082 case STM_MODE_RESET: fd->marks[mark] = 0; | |
1083 break; | |
1084 case STM_MODE_TOGGLE: fd->marks[mark] = !fd->marks[mark]; | |
1085 break; | |
1086 } | |
1087 | |
1088 work = work->next; | |
1089 } | |
1090 filelist_free(slist); | |
1091 } | |
138 | 1092 |
1093 | |
9 | 1094 /* |
1095 *------------------------------------------------------------------- | |
1096 * focus | |
1097 *------------------------------------------------------------------- | |
1098 */ | |
1099 | |
1100 static void vficon_move_focus(ViewFileIcon *vfi, gint row, gint col, gint relative) | |
1101 { | |
1102 gint new_row; | |
1103 gint new_col; | |
1104 | |
1105 if (relative) | |
1106 { | |
1107 new_row = vfi->focus_row; | |
1108 new_col = vfi->focus_column; | |
1109 | |
1110 new_row += row; | |
1111 if (new_row < 0) new_row = 0; | |
1112 if (new_row >= vfi->rows) new_row = vfi->rows - 1; | |
1113 | |
1114 while(col != 0) | |
1115 { | |
1116 if (col < 0) | |
1117 { | |
1118 new_col--; | |
1119 col++; | |
1120 } | |
1121 else | |
1122 { | |
1123 new_col++; | |
1124 col--; | |
1125 } | |
1126 | |
1127 if (new_col < 0) | |
1128 { | |
1129 if (new_row > 0) | |
1130 { | |
1131 new_row--; | |
1132 new_col = vfi->columns - 1; | |
1133 } | |
1134 else | |
1135 { | |
1136 new_col = 0; | |
1137 } | |
1138 } | |
1139 if (new_col >= vfi->columns) | |
1140 { | |
1141 if (new_row < vfi->rows - 1) | |
1142 { | |
1143 new_row++; | |
1144 new_col = 0; | |
1145 } | |
1146 else | |
1147 { | |
1148 new_col = vfi->columns - 1; | |
1149 } | |
1150 } | |
1151 } | |
1152 } | |
1153 else | |
1154 { | |
1155 new_row = row; | |
1156 new_col = col; | |
1157 | |
1158 if (new_row >= vfi->rows) | |
1159 { | |
1160 if (vfi->rows > 0) | |
1161 new_row = vfi->rows - 1; | |
1162 else | |
1163 new_row = 0; | |
1164 new_col = vfi->columns - 1; | |
1165 } | |
1166 if (new_col >= vfi->columns) new_col = vfi->columns - 1; | |
1167 } | |
1168 | |
1169 if (new_row == vfi->rows - 1) | |
1170 { | |
1171 gint l; | |
1172 | |
1173 /* if we moved beyond the last image, go to the last image */ | |
1174 | |
1175 l = g_list_length(vfi->list); | |
1176 if (vfi->rows > 1) l -= (vfi->rows - 1) * vfi->columns; | |
1177 if (new_col >= l) new_col = l - 1; | |
1178 } | |
1179 | |
1180 vficon_set_focus(vfi, vficon_find_data(vfi, new_row, new_col, NULL)); | |
1181 } | |
1182 | |
138 | 1183 static void vficon_set_focus(ViewFileIcon *vfi, IconData *id) |
9 | 1184 { |
1185 GtkTreeIter iter; | |
1186 gint row, col; | |
1187 | |
138 | 1188 if (g_list_find(vfi->list, vfi->focus_id)) |
9 | 1189 { |
138 | 1190 if (id == vfi->focus_id) |
9 | 1191 { |
1192 /* ensure focus row col are correct */ | |
138 | 1193 vficon_find_position(vfi, vfi->focus_id, &vfi->focus_row, &vfi->focus_column); |
9 | 1194 return; |
1195 } | |
138 | 1196 vficon_selection_remove(vfi, vfi->focus_id, SELECTION_FOCUS, NULL); |
9 | 1197 } |
1198 | |
138 | 1199 if (!vficon_find_position(vfi, id, &row, &col)) |
9 | 1200 { |
138 | 1201 vfi->focus_id = NULL; |
9 | 1202 vfi->focus_row = -1; |
1203 vfi->focus_column = -1; | |
1204 return; | |
1205 } | |
1206 | |
138 | 1207 vfi->focus_id = id; |
9 | 1208 vfi->focus_row = row; |
1209 vfi->focus_column = col; | |
138 | 1210 vficon_selection_add(vfi, vfi->focus_id, SELECTION_FOCUS, NULL); |
1211 | |
1212 if (vficon_find_iter(vfi, vfi->focus_id, &iter, NULL)) | |
9 | 1213 { |
1214 GtkTreePath *tpath; | |
1215 GtkTreeViewColumn *column; | |
1216 GtkTreeModel *store; | |
1217 | |
1218 tree_view_row_make_visible(GTK_TREE_VIEW(vfi->listview), &iter, FALSE); | |
1219 | |
1220 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
1221 tpath = gtk_tree_model_get_path(store, &iter); | |
1222 /* focus is set to an extra column with 0 width to hide focus, we draw it ourself */ | |
1223 column = gtk_tree_view_get_column(GTK_TREE_VIEW(vfi->listview), VFICON_MAX_COLUMNS); | |
1224 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vfi->listview), tpath, column, FALSE); | |
1225 gtk_tree_path_free(tpath); | |
1226 } | |
1227 } | |
1228 | |
1229 static void vficon_update_focus(ViewFileIcon *vfi) | |
1230 { | |
1231 gint new_row = 0; | |
1232 gint new_col = 0; | |
1233 | |
138 | 1234 if (vfi->focus_id && vficon_find_position(vfi, vfi->focus_id, &new_row, &new_col)) |
9 | 1235 { |
1236 /* first find the old focus, if it exists and is valid */ | |
1237 } | |
1238 else | |
1239 { | |
1240 /* (try to) stay where we were */ | |
1241 new_row = vfi->focus_row; | |
1242 new_col = vfi->focus_column; | |
1243 } | |
1244 | |
1245 vficon_move_focus(vfi, new_row, new_col, FALSE); | |
1246 } | |
1247 | |
1248 /* used to figure the page up/down distances */ | |
1249 static gint page_height(ViewFileIcon *vfi) | |
1250 { | |
1251 GtkAdjustment *adj; | |
1252 gint page_size; | |
1253 gint row_height; | |
1254 gint ret; | |
1255 | |
1256 adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(vfi->listview)); | |
1257 page_size = (gint)adj->page_increment; | |
1258 | |
1259 row_height = thumb_max_height + THUMB_BORDER_PADDING * 2; | |
1260 if (vfi->show_text) row_height += thumb_max_height / 3; | |
1261 | |
1262 ret = page_size / row_height; | |
1263 if (ret < 1) ret = 1; | |
1264 | |
1265 return ret; | |
1266 } | |
1267 | |
1268 /* | |
1269 *------------------------------------------------------------------- | |
1270 * keyboard | |
1271 *------------------------------------------------------------------- | |
1272 */ | |
1273 | |
1274 static void vfi_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data) | |
1275 { | |
1276 ViewFileIcon *vfi = data; | |
1277 GtkTreeModel *store; | |
1278 GtkTreeIter iter; | |
1279 gint column; | |
1280 GtkTreePath *tpath; | |
1281 gint cw, ch; | |
1282 | |
138 | 1283 if (!vficon_find_iter(vfi, vfi->click_id, &iter, &column)) return; |
9 | 1284 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); |
1285 tpath = gtk_tree_model_get_path(store, &iter); | |
1286 tree_view_get_cell_clamped(GTK_TREE_VIEW(vfi->listview), tpath, column, FALSE, x, y, &cw, &ch); | |
1287 gtk_tree_path_free(tpath); | |
1288 *y += ch; | |
1289 popup_menu_position_clamp(menu, x, y, 0); | |
1290 } | |
1291 | |
1292 static gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
1293 { | |
1294 ViewFileIcon *vfi = data; | |
1295 gint focus_row = 0; | |
1296 gint focus_col = 0; | |
138 | 1297 IconData *id; |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1298 gint stop_signal; |
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1299 |
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1300 stop_signal = TRUE; |
9 | 1301 switch (event->keyval) |
1302 { | |
1303 case GDK_Left: case GDK_KP_Left: | |
1304 focus_col = -1; | |
1305 break; | |
1306 case GDK_Right: case GDK_KP_Right: | |
1307 focus_col = 1; | |
1308 break; | |
1309 case GDK_Up: case GDK_KP_Up: | |
1310 focus_row = -1; | |
1311 break; | |
1312 case GDK_Down: case GDK_KP_Down: | |
1313 focus_row = 1; | |
1314 break; | |
1315 case GDK_Page_Up: case GDK_KP_Page_Up: | |
1316 focus_row = -page_height(vfi); | |
1317 break; | |
1318 case GDK_Page_Down: case GDK_KP_Page_Down: | |
1319 focus_row = page_height(vfi); | |
1320 break; | |
1321 case GDK_Home: case GDK_KP_Home: | |
1322 focus_row = -vfi->focus_row; | |
1323 focus_col = -vfi->focus_column; | |
1324 break; | |
1325 case GDK_End: case GDK_KP_End: | |
1326 focus_row = vfi->rows - 1 - vfi->focus_row; | |
1327 focus_col = vfi->columns - 1 - vfi->focus_column; | |
1328 break; | |
1329 case GDK_space: | |
138 | 1330 id = vficon_find_data(vfi, vfi->focus_row, vfi->focus_column, NULL); |
1331 if (id) | |
9 | 1332 { |
138 | 1333 vfi->click_id = id; |
9 | 1334 if (event->state & GDK_CONTROL_MASK) |
1335 { | |
1336 gint selected; | |
1337 | |
138 | 1338 selected = id->selected & SELECTION_SELECTED; |
9 | 1339 if (selected) |
1340 { | |
138 | 1341 vficon_unselect(vfi, id); |
9 | 1342 } |
1343 else | |
1344 { | |
138 | 1345 vficon_select(vfi, id); |
1346 vficon_send_layout_select(vfi, id); | |
9 | 1347 } |
1348 } | |
1349 else | |
1350 { | |
1351 vficon_select_none(vfi); | |
138 | 1352 vficon_select(vfi, id); |
1353 vficon_send_layout_select(vfi, id); | |
9 | 1354 } |
1355 } | |
1356 break; | |
1357 case GDK_Menu: | |
138 | 1358 id = vficon_find_data(vfi, vfi->focus_row, vfi->focus_column, NULL); |
1359 vfi->click_id = id; | |
1360 | |
1361 vficon_selection_add(vfi, vfi->click_id, SELECTION_PRELIGHT, NULL); | |
9 | 1362 tip_unschedule(vfi); |
1363 | |
138 | 1364 vfi->popup = vficon_pop_menu(vfi, (id != NULL)); |
9 | 1365 gtk_menu_popup(GTK_MENU(vfi->popup), NULL, NULL, vfi_menu_position_cb, vfi, 0, GDK_CURRENT_TIME); |
1366 break; | |
1367 default: | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1368 stop_signal = FALSE; |
9 | 1369 break; |
1370 } | |
1371 | |
1372 if (focus_row != 0 || focus_col != 0) | |
1373 { | |
138 | 1374 IconData *new_id; |
1375 IconData *old_id; | |
1376 | |
1377 old_id = vficon_find_data(vfi, vfi->focus_row, vfi->focus_column, NULL); | |
9 | 1378 vficon_move_focus(vfi, focus_row, focus_col, TRUE); |
138 | 1379 new_id = vficon_find_data(vfi, vfi->focus_row, vfi->focus_column, NULL); |
1380 | |
1381 if (new_id != old_id) | |
9 | 1382 { |
1383 if (event->state & GDK_SHIFT_MASK) | |
1384 { | |
1385 if (!collection_rectangular_selection) | |
1386 { | |
138 | 1387 vficon_select_region_util(vfi, old_id, new_id, FALSE); |
9 | 1388 } |
1389 else | |
1390 { | |
138 | 1391 vficon_select_region_util(vfi, vfi->click_id, old_id, FALSE); |
9 | 1392 } |
138 | 1393 vficon_select_region_util(vfi, vfi->click_id, new_id, TRUE); |
1394 vficon_send_layout_select(vfi, new_id); | |
9 | 1395 } |
1396 else if (event->state & GDK_CONTROL_MASK) | |
1397 { | |
138 | 1398 vfi->click_id = new_id; |
9 | 1399 } |
1400 else | |
1401 { | |
138 | 1402 vfi->click_id = new_id; |
9 | 1403 vficon_select_none(vfi); |
138 | 1404 vficon_select(vfi, new_id); |
1405 vficon_send_layout_select(vfi, new_id); | |
9 | 1406 } |
1407 } | |
1408 } | |
1409 | |
1410 if (stop_signal) | |
1411 { | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1412 #if 0 |
9 | 1413 g_signal_stop_emission_by_name(GTK_OBJECT(widget), "key_press_event"); |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1414 #endif |
9 | 1415 tip_unschedule(vfi); |
1416 } | |
1417 | |
1418 return stop_signal; | |
1419 } | |
1420 | |
1421 /* | |
1422 *------------------------------------------------------------------- | |
1423 * mouse | |
1424 *------------------------------------------------------------------- | |
1425 */ | |
1426 | |
1427 static gint vficon_motion_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
1428 { | |
1429 ViewFileIcon *vfi = data; | |
138 | 1430 IconData *id; |
1431 | |
1432 id = vficon_find_data_by_coord(vfi, (gint)bevent->x, (gint)bevent->y, NULL); | |
1433 tip_update(vfi, id); | |
9 | 1434 |
1435 return FALSE; | |
1436 } | |
1437 | |
1438 static gint vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
1439 { | |
1440 ViewFileIcon *vfi = data; | |
1441 GtkTreeIter iter; | |
138 | 1442 IconData *id; |
9 | 1443 |
1444 tip_unschedule(vfi); | |
1445 | |
138 | 1446 id = vficon_find_data_by_coord(vfi, (gint)bevent->x, (gint)bevent->y, &iter); |
1447 | |
1448 vfi->click_id = id; | |
1449 vficon_selection_add(vfi, vfi->click_id, SELECTION_PRELIGHT, &iter); | |
9 | 1450 |
1451 switch (bevent->button) | |
1452 { | |
1453 case 1: | |
1454 if (!GTK_WIDGET_HAS_FOCUS(vfi->listview)) | |
1455 { | |
1456 gtk_widget_grab_focus(vfi->listview); | |
1457 } | |
1458 #if 0 | |
1459 if (bevent->type == GDK_2BUTTON_PRESS && | |
1460 vfi->layout) | |
1461 { | |
138 | 1462 vficon_selection_remove(vfi, vfi->click_id, SELECTION_PRELIGHT, &iter); |
9 | 1463 layout_image_full_screen_start(vfi->layout); |
1464 } | |
1465 #endif | |
1466 break; | |
1467 case 3: | |
138 | 1468 vfi->popup = vficon_pop_menu(vfi, (id != NULL)); |
9 | 1469 gtk_menu_popup(GTK_MENU(vfi->popup), NULL, NULL, NULL, NULL, bevent->button, bevent->time); |
1470 break; | |
1471 default: | |
1472 break; | |
1473 } | |
1474 | |
1475 return TRUE; | |
1476 } | |
1477 | |
1478 static gint vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
1479 { | |
1480 ViewFileIcon *vfi = data; | |
1481 GtkTreeIter iter; | |
138 | 1482 IconData *id = NULL; |
9 | 1483 gint was_selected = FALSE; |
1484 | |
1485 tip_schedule(vfi); | |
1486 | |
1487 if ((gint)bevent->x != 0 || (gint) bevent->y != 0) | |
1488 { | |
138 | 1489 id = vficon_find_data_by_coord(vfi, (gint)bevent->x, (gint)bevent->y, &iter); |
9 | 1490 } |
1491 | |
138 | 1492 if (vfi->click_id) |
9 | 1493 { |
138 | 1494 vficon_selection_remove(vfi, vfi->click_id, SELECTION_PRELIGHT, NULL); |
9 | 1495 } |
1496 | |
138 | 1497 if (id) was_selected = (id->selected & SELECTION_SELECTED); |
9 | 1498 |
1499 if (bevent->button == 1 && | |
138 | 1500 id && vfi->click_id == id) |
9 | 1501 { |
138 | 1502 vficon_set_focus(vfi, id); |
9 | 1503 |
1504 if (bevent->state & GDK_CONTROL_MASK) | |
1505 { | |
1506 gint select; | |
1507 | |
138 | 1508 select = !(id->selected & SELECTION_SELECTED); |
9 | 1509 if ((bevent->state & GDK_SHIFT_MASK) && vfi->prev_selection) |
1510 { | |
138 | 1511 vficon_select_region_util(vfi, vfi->prev_selection, id, select); |
9 | 1512 } |
1513 else | |
1514 { | |
138 | 1515 vficon_select_util(vfi, id, select); |
9 | 1516 } |
1517 } | |
1518 else | |
1519 { | |
1520 vficon_select_none(vfi); | |
1521 | |
1522 if ((bevent->state & GDK_SHIFT_MASK) && | |
1523 vfi->prev_selection) | |
1524 { | |
138 | 1525 vficon_select_region_util(vfi, vfi->prev_selection, id, TRUE); |
9 | 1526 } |
1527 else | |
1528 { | |
138 | 1529 vficon_select_util(vfi, id, TRUE); |
9 | 1530 was_selected = FALSE; |
1531 } | |
1532 } | |
1533 } | |
1534 else if (bevent->button == 2 && | |
138 | 1535 id && vfi->click_id == id) |
9 | 1536 { |
138 | 1537 vficon_select_util(vfi, id, !(id->selected & SELECTION_SELECTED)); |
9 | 1538 } |
1539 | |
138 | 1540 if (id && !was_selected && |
1541 (id->selected & SELECTION_SELECTED)) | |
9 | 1542 { |
138 | 1543 vficon_send_layout_select(vfi, id); |
9 | 1544 } |
1545 | |
1546 return TRUE; | |
1547 } | |
1548 | |
1549 static gint vficon_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data) | |
1550 { | |
1551 ViewFileIcon *vfi = data; | |
1552 | |
1553 tip_unschedule(vfi); | |
1554 return FALSE; | |
1555 } | |
1556 | |
1557 /* | |
1558 *------------------------------------------------------------------- | |
1559 * population | |
1560 *------------------------------------------------------------------- | |
1561 */ | |
1562 | |
1563 static gboolean vficon_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GtkTreeIter *iter, gpointer data) | |
1564 { | |
1565 GList *list; | |
1566 | |
1567 gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1); | |
1568 g_list_free(list); | |
1569 | |
1570 return FALSE; | |
1571 } | |
1572 | |
1573 static void vficon_clear_store(ViewFileIcon *vfi) | |
1574 { | |
1575 GtkTreeModel *store; | |
1576 | |
1577 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
1578 gtk_tree_model_foreach(store, vficon_destroy_node_cb, NULL); | |
1579 | |
1580 gtk_list_store_clear(GTK_LIST_STORE(store)); | |
1581 } | |
1582 | |
1583 static void vficon_set_thumb(ViewFileIcon *vfi, FileData *fd, GdkPixbuf *pb) | |
1584 { | |
1585 GtkTreeModel *store; | |
1586 GtkTreeIter iter; | |
1587 GList *list; | |
1588 | |
138 | 1589 if (!vficon_find_iter(vfi, vficon_icon_data(vfi, fd), &iter, NULL)) return; |
9 | 1590 |
1591 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
1592 | |
1593 if (pb) g_object_ref(pb); | |
1594 if (fd->pixbuf) g_object_unref(fd->pixbuf); | |
1595 fd->pixbuf = pb; | |
1596 | |
1597 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); | |
1598 gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1); | |
1599 } | |
1600 | |
1601 static GList *vficon_add_row(ViewFileIcon *vfi, GtkTreeIter *iter) | |
1602 { | |
1603 GtkListStore *store; | |
1604 GList *list = NULL; | |
1605 gint i; | |
1606 | |
1607 for (i = 0; i < vfi->columns; i++) list = g_list_prepend(list, NULL); | |
1608 | |
1609 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview))); | |
1610 gtk_list_store_append(store, iter); | |
1611 gtk_list_store_set(store, iter, FILE_COLUMN_POINTER, list, -1); | |
1612 | |
1613 return list; | |
1614 } | |
1615 | |
1616 static void vficon_populate(ViewFileIcon *vfi, gint resize, gint keep_position) | |
1617 { | |
1618 GtkTreeModel *store; | |
1619 GtkTreePath *tpath; | |
1620 gint row; | |
1621 GList *work; | |
138 | 1622 IconData *visible_id = NULL; |
9 | 1623 |
1624 vficon_verify_selections(vfi); | |
1625 | |
1626 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
1627 | |
1628 if (keep_position && GTK_WIDGET_REALIZED(vfi->listview) && | |
1629 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vfi->listview), 0, 0, &tpath, NULL, NULL, NULL)) | |
1630 { | |
1631 GtkTreeIter iter; | |
1632 GList *list; | |
1633 | |
1634 gtk_tree_model_get_iter(store, &iter, tpath); | |
1635 gtk_tree_path_free(tpath); | |
1636 | |
1637 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); | |
138 | 1638 if (list) visible_id = list->data; |
9 | 1639 } |
1640 | |
1641 vficon_clear_store(vfi); | |
1642 | |
1643 if (resize) | |
1644 { | |
1645 gint i; | |
1646 gint thumb_width; | |
1647 | |
1648 thumb_width = vficon_get_icon_width(vfi); | |
1649 | |
1650 for (i = 0; i < VFICON_MAX_COLUMNS; i++) | |
1651 { | |
1652 GtkTreeViewColumn *column; | |
1653 GtkCellRenderer *cell; | |
1654 GList *list; | |
1655 | |
1656 column = gtk_tree_view_get_column(GTK_TREE_VIEW(vfi->listview), i); | |
1657 gtk_tree_view_column_set_visible(column, (i < vfi->columns)); | |
1658 gtk_tree_view_column_set_fixed_width(column, thumb_width + (THUMB_BORDER_PADDING * 6)); | |
1659 | |
1660 list = gtk_tree_view_column_get_cell_renderers(column); | |
1661 cell = (list) ? list->data : NULL; | |
1662 g_list_free(list); | |
1663 | |
1664 if (cell && GQV_IS_CELL_RENDERER_ICON(cell)) | |
1665 { | |
1666 g_object_set(G_OBJECT(cell), "fixed_width", thumb_width, | |
1667 "fixed_height", thumb_max_height, | |
1668 "show_text", vfi->show_text, NULL); | |
1669 } | |
1670 } | |
1671 if (GTK_WIDGET_REALIZED(vfi->listview)) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vfi->listview)); | |
1672 } | |
1673 | |
1674 row = -1; | |
1675 work = vfi->list; | |
1676 while (work) | |
1677 { | |
1678 GList *list; | |
1679 GtkTreeIter iter; | |
1680 | |
1681 row++; | |
1682 | |
1683 list = vficon_add_row(vfi, &iter); | |
1684 while (work && list) | |
1685 { | |
138 | 1686 IconData *id; |
1687 | |
1688 id = work->data; | |
1689 id->row = row; | |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
1690 |
9 | 1691 list->data = work->data; |
1692 list = list->next; | |
1693 work = work->next; | |
1694 } | |
1695 } | |
1696 | |
138 | 1697 if (visible_id && |
9 | 1698 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vfi->listview), 0, 0, &tpath, NULL, NULL, NULL)) |
1699 { | |
1700 GtkTreeIter iter; | |
1701 GList *list; | |
1702 | |
1703 gtk_tree_model_get_iter(store, &iter, tpath); | |
1704 gtk_tree_path_free(tpath); | |
1705 | |
1706 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); | |
138 | 1707 if (g_list_find(list, visible_id) == NULL && |
1708 vficon_find_iter(vfi, visible_id, &iter, NULL)) | |
9 | 1709 { |
1710 tree_view_row_make_visible(GTK_TREE_VIEW(vfi->listview), &iter, FALSE); | |
1711 } | |
1712 } | |
1713 | |
1714 vfi->rows = row + 1; | |
1715 | |
1716 vficon_send_update(vfi); | |
1717 vficon_thumb_update(vfi); | |
1718 } | |
1719 | |
1720 static void vficon_populate_at_new_size(ViewFileIcon *vfi, gint w, gint h, gint force) | |
1721 { | |
1722 gint new_cols; | |
1723 gint thumb_width; | |
1724 | |
1725 thumb_width = vficon_get_icon_width(vfi); | |
1726 | |
1727 new_cols = w / (thumb_width + (THUMB_BORDER_PADDING * 6)); | |
1728 if (new_cols < 1) new_cols = 1; | |
1729 | |
1730 if (!force && new_cols == vfi->columns) return; | |
1731 | |
1732 vfi->columns = new_cols; | |
1733 | |
1734 vficon_populate(vfi, TRUE, TRUE); | |
1735 | |
1736 if (debug) printf("col tab pop cols=%d rows=%d\n", vfi->columns, vfi->rows); | |
1737 } | |
1738 | |
1739 static void vficon_sync(ViewFileIcon *vfi) | |
1740 { | |
1741 GtkTreeModel *store; | |
1742 GtkTreeIter iter; | |
1743 GList *work; | |
1744 gint r, c; | |
1745 | |
1746 if (vfi->rows == 0) return; | |
1747 | |
1748 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
1749 | |
1750 r = -1; | |
1751 c = 0; | |
1752 | |
1753 work = vfi->list; | |
1754 while (work) | |
1755 { | |
1756 GList *list; | |
1757 r++; | |
1758 c = 0; | |
1759 if (gtk_tree_model_iter_nth_child(store, &iter, NULL, r)) | |
1760 { | |
1761 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); | |
1762 gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1); | |
1763 } | |
1764 else | |
1765 { | |
1766 list = vficon_add_row(vfi, &iter); | |
1767 } | |
1768 | |
1769 while (list) | |
1770 { | |
138 | 1771 IconData *id; |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
1772 |
9 | 1773 if (work) |
1774 { | |
138 | 1775 id = work->data; |
9 | 1776 work = work->next; |
1777 c++; | |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
1778 |
138 | 1779 id->row = r; |
9 | 1780 } |
1781 else | |
1782 { | |
138 | 1783 id = NULL; |
9 | 1784 } |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
1785 |
138 | 1786 list->data = id; |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
1787 list = list->next; |
9 | 1788 } |
1789 } | |
1790 | |
1791 r++; | |
1792 while (gtk_tree_model_iter_nth_child(store, &iter, NULL, r)) | |
1793 { | |
1794 GList *list; | |
1795 | |
1796 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); | |
1797 gtk_list_store_remove(GTK_LIST_STORE(store), &iter); | |
1798 g_list_free(list); | |
1799 } | |
1800 | |
1801 vfi->rows = r; | |
1802 | |
1803 vficon_update_focus(vfi); | |
1804 } | |
1805 | |
1806 static gint vficon_sync_idle_cb(gpointer data) | |
1807 { | |
1808 ViewFileIcon *vfi = data; | |
1809 | |
1810 if (vfi->sync_idle_id == -1) return FALSE; | |
1811 vfi->sync_idle_id = -1; | |
1812 | |
1813 vficon_sync(vfi); | |
1814 return FALSE; | |
1815 } | |
1816 | |
1817 static void vficon_sync_idle(ViewFileIcon *vfi) | |
1818 { | |
1819 if (vfi->sync_idle_id == -1) | |
1820 { | |
1821 /* high priority, the view needs to be resynced before a redraw | |
1822 * may contain invalid pointers at this time | |
1823 */ | |
1824 vfi->sync_idle_id = g_idle_add_full(G_PRIORITY_HIGH, vficon_sync_idle_cb, vfi, NULL); | |
1825 } | |
1826 } | |
1827 | |
1828 static void vficon_sized_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data) | |
1829 { | |
1830 ViewFileIcon *vfi = data; | |
1831 | |
1832 vficon_populate_at_new_size(vfi, allocation->width, allocation->height, FALSE); | |
1833 } | |
1834 | |
1835 /* | |
1836 *----------------------------------------------------------------------------- | |
1837 * misc | |
1838 *----------------------------------------------------------------------------- | |
1839 */ | |
1840 | |
1841 void vficon_sort_set(ViewFileIcon *vfi, SortType type, gint ascend) | |
1842 { | |
1843 if (vfi->sort_method == type && vfi->sort_ascend == ascend) return; | |
1844 | |
1845 vfi->sort_method = type; | |
1846 vfi->sort_ascend = ascend; | |
1847 | |
1848 if (!vfi->list) return; | |
1849 | |
138 | 1850 vfi->list = iconlist_sort(vfi->list, vfi->sort_method, vfi->sort_ascend); |
9 | 1851 vficon_sync(vfi); |
1852 } | |
1853 | |
1854 /* | |
1855 *----------------------------------------------------------------------------- | |
1856 * thumb updates | |
1857 *----------------------------------------------------------------------------- | |
1858 */ | |
1859 | |
1860 static gint vficon_thumb_next(ViewFileIcon *vfi); | |
1861 | |
1862 static void vficon_thumb_status(ViewFileIcon *vfi, gdouble val, const gchar *text) | |
1863 { | |
1864 if (vfi->func_thumb_status) | |
1865 { | |
1866 vfi->func_thumb_status(vfi, val, text, vfi->data_thumb_status); | |
1867 } | |
1868 } | |
1869 | |
1870 static void vficon_thumb_cleanup(ViewFileIcon *vfi) | |
1871 { | |
1872 vficon_thumb_status(vfi, 0.0, NULL); | |
1873 | |
1874 g_list_free(vfi->thumbs_list); | |
1875 vfi->thumbs_list = NULL; | |
1876 vfi->thumbs_count = 0; | |
1877 vfi->thumbs_running = FALSE; | |
1878 | |
1879 thumb_loader_free(vfi->thumbs_loader); | |
1880 vfi->thumbs_loader = NULL; | |
1881 | |
1882 vfi->thumbs_fd = NULL; | |
1883 } | |
1884 | |
1885 static void vficon_thumb_stop(ViewFileIcon *vfi) | |
1886 { | |
1887 if (vfi->thumbs_running) vficon_thumb_cleanup(vfi); | |
1888 } | |
1889 | |
1890 static void vficon_thumb_do(ViewFileIcon *vfi, ThumbLoader *tl, FileData *fd) | |
1891 { | |
1892 GdkPixbuf *pixbuf; | |
1893 | |
1894 if (!fd) return; | |
1895 | |
1896 pixbuf = thumb_loader_get_pixbuf(tl, TRUE); | |
1897 vficon_set_thumb(vfi, fd, pixbuf); | |
1898 g_object_unref(pixbuf); | |
1899 | |
1900 vficon_thumb_status(vfi, (gdouble)(vfi->thumbs_count) / g_list_length(vfi->list), _("Loading thumbs...")); | |
1901 } | |
1902 | |
1903 static void vficon_thumb_error_cb(ThumbLoader *tl, gpointer data) | |
1904 { | |
1905 ViewFileIcon *vfi = data; | |
1906 | |
1907 if (vfi->thumbs_fd && vfi->thumbs_loader == tl) | |
1908 { | |
1909 vficon_thumb_do(vfi, tl, vfi->thumbs_fd); | |
1910 } | |
1911 | |
1912 while (vficon_thumb_next(vfi)); | |
1913 } | |
1914 | |
1915 static void vficon_thumb_done_cb(ThumbLoader *tl, gpointer data) | |
1916 { | |
1917 ViewFileIcon *vfi = data; | |
1918 | |
1919 if (vfi->thumbs_fd && vfi->thumbs_loader == tl) | |
1920 { | |
1921 vficon_thumb_do(vfi, tl, vfi->thumbs_fd); | |
1922 } | |
1923 | |
1924 while (vficon_thumb_next(vfi)); | |
1925 } | |
1926 | |
1927 static gint vficon_thumb_next(ViewFileIcon *vfi) | |
1928 { | |
1929 GtkTreePath *tpath; | |
1930 FileData *fd = NULL; | |
1931 | |
1932 if (!GTK_WIDGET_REALIZED(vfi->listview)) | |
1933 { | |
1934 vficon_thumb_status(vfi, 0.0, NULL); | |
1935 return FALSE; | |
1936 } | |
1937 | |
1938 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vfi->listview), 0, 0, &tpath, NULL, NULL, NULL)) | |
1939 { | |
1940 GtkTreeModel *store; | |
1941 GtkTreeIter iter; | |
1942 gint valid = TRUE; | |
1943 | |
1944 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
1945 gtk_tree_model_get_iter(store, &iter, tpath); | |
1946 gtk_tree_path_free(tpath); | |
1947 | |
1948 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vfi->listview), &iter, FALSE) == 0) | |
1949 { | |
1950 GList *list; | |
1951 | |
1952 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); | |
1953 | |
1954 while (!fd && list) | |
1955 { | |
138 | 1956 IconData *id = list->data; |
1957 if (id && !id->fd->pixbuf) fd = id->fd; | |
9 | 1958 list = list->next; |
1959 } | |
1960 | |
1961 valid = gtk_tree_model_iter_next(store, &iter); | |
1962 } | |
1963 } | |
1964 | |
1965 /* then find first undone */ | |
1966 | |
1967 if (!fd) | |
1968 { | |
1969 GList *work = vfi->list; | |
1970 while (work && !fd) | |
1971 { | |
138 | 1972 IconData *id = work->data; |
1973 FileData *fd_p = id->fd; | |
9 | 1974 work = work->next; |
1975 | |
1976 if (!fd_p->pixbuf) fd = fd_p; | |
1977 } | |
1978 } | |
1979 | |
1980 if (!fd) | |
1981 { | |
1982 /* done */ | |
1983 vficon_thumb_cleanup(vfi); | |
1984 return FALSE; | |
1985 } | |
1986 | |
1987 vfi->thumbs_count++; | |
1988 | |
1989 vfi->thumbs_fd = fd; | |
1990 | |
1991 thumb_loader_free(vfi->thumbs_loader); | |
1992 | |
1993 vfi->thumbs_loader = thumb_loader_new(thumb_max_width, thumb_max_height); | |
1994 thumb_loader_set_callbacks(vfi->thumbs_loader, | |
1995 vficon_thumb_done_cb, | |
1996 vficon_thumb_error_cb, | |
1997 NULL, | |
1998 vfi); | |
1999 | |
2000 if (!thumb_loader_start(vfi->thumbs_loader, fd->path)) | |
2001 { | |
2002 /* set icon to unknown, continue */ | |
2003 if (debug) printf("thumb loader start failed %s\n", vfi->thumbs_loader->path); | |
2004 vficon_thumb_do(vfi, vfi->thumbs_loader, fd); | |
2005 | |
2006 return TRUE; | |
2007 } | |
2008 | |
2009 return FALSE; | |
2010 } | |
2011 | |
2012 static void vficon_thumb_update(ViewFileIcon *vfi) | |
2013 { | |
2014 vficon_thumb_stop(vfi); | |
2015 | |
2016 vficon_thumb_status(vfi, 0.0, _("Loading thumbs...")); | |
2017 vfi->thumbs_running = TRUE; | |
2018 | |
2019 while (vficon_thumb_next(vfi)); | |
2020 } | |
2021 | |
2022 /* | |
2023 *----------------------------------------------------------------------------- | |
2024 * row stuff | |
2025 *----------------------------------------------------------------------------- | |
2026 */ | |
2027 | |
2028 FileData *vficon_index_get_data(ViewFileIcon *vfi, gint row) | |
2029 { | |
138 | 2030 IconData *id; |
2031 | |
2032 id = g_list_nth_data(vfi->list, row); | |
2033 return id ? id->fd : NULL; | |
9 | 2034 } |
2035 | |
2036 gchar *vficon_index_get_path(ViewFileIcon *vfi, gint row) | |
2037 { | |
2038 FileData *fd; | |
138 | 2039 IconData *id; |
2040 | |
2041 id = g_list_nth_data(vfi->list, row); | |
2042 fd = id ? id->fd : NULL; | |
9 | 2043 |
2044 return (fd ? fd->path : NULL); | |
2045 } | |
2046 | |
2047 gint vficon_index_by_path(ViewFileIcon *vfi, const gchar *path) | |
2048 { | |
2049 gint p = 0; | |
2050 GList *work; | |
2051 | |
2052 if (!path) return -1; | |
2053 | |
2054 work = vfi->list; | |
2055 while (work) | |
2056 { | |
138 | 2057 IconData *id = work->data; |
2058 FileData *fd = id->fd; | |
9 | 2059 if (strcmp(path, fd->path) == 0) return p; |
2060 work = work->next; | |
2061 p++; | |
2062 } | |
2063 | |
2064 return -1; | |
2065 } | |
2066 | |
138 | 2067 gint vficon_index_by_fd(ViewFileIcon *vfi, FileData *in_fd) |
2068 { | |
2069 gint p = 0; | |
2070 GList *work; | |
2071 | |
2072 if (!in_fd) return -1; | |
2073 | |
2074 work = vfi->list; | |
2075 while (work) | |
2076 { | |
2077 IconData *id = work->data; | |
2078 FileData *fd = id->fd; | |
2079 if (fd == in_fd) return p; | |
2080 work = work->next; | |
2081 p++; | |
2082 } | |
2083 | |
2084 return -1; | |
2085 } | |
2086 | |
2087 static gint vficon_index_by_id(ViewFileIcon *vfi, IconData *in_id) | |
2088 { | |
2089 gint p = 0; | |
2090 GList *work; | |
2091 | |
2092 if (!in_id) return -1; | |
2093 | |
2094 work = vfi->list; | |
2095 while (work) | |
2096 { | |
2097 IconData *id = work->data; | |
2098 if (id == in_id) return p; | |
2099 work = work->next; | |
2100 p++; | |
2101 } | |
2102 | |
2103 return -1; | |
2104 } | |
2105 | |
9 | 2106 gint vficon_count(ViewFileIcon *vfi, gint64 *bytes) |
2107 { | |
2108 if (bytes) | |
2109 { | |
2110 gint64 b = 0; | |
2111 GList *work; | |
2112 | |
2113 work = vfi->list; | |
2114 while (work) | |
2115 { | |
138 | 2116 |
2117 IconData *id = work->data; | |
2118 FileData *fd = id->fd; | |
9 | 2119 work = work->next; |
2120 b += fd->size; | |
2121 } | |
2122 | |
2123 *bytes = b; | |
2124 } | |
2125 | |
2126 return g_list_length(vfi->list); | |
2127 } | |
2128 | |
2129 GList *vficon_get_list(ViewFileIcon *vfi) | |
2130 { | |
2131 GList *list = NULL; | |
2132 GList *work; | |
2133 | |
2134 work = vfi->list; | |
2135 while (work) | |
2136 { | |
138 | 2137 IconData *id = work->data; |
2138 FileData *fd = id->fd; | |
9 | 2139 work = work->next; |
2140 | |
138 | 2141 list = g_list_prepend(list, file_data_ref(fd)); |
9 | 2142 } |
2143 | |
2144 return g_list_reverse(list); | |
2145 } | |
2146 | |
2147 /* | |
2148 *----------------------------------------------------------------------------- | |
2149 * | |
2150 *----------------------------------------------------------------------------- | |
2151 */ | |
2152 | |
2153 static gint vficon_refresh_real(ViewFileIcon *vfi, gint keep_position) | |
2154 { | |
2155 gint ret = TRUE; | |
2156 GList *old_list; | |
2157 GList *work; | |
138 | 2158 IconData *focus_id; |
2159 | |
2160 focus_id = vfi->focus_id; | |
9 | 2161 |
2162 old_list = vfi->list; | |
2163 vfi->list = NULL; | |
2164 | |
2165 if (vfi->path) | |
2166 { | |
2167 ret = iconlist_read(vfi->path, &vfi->list); | |
2168 } | |
2169 | |
2170 /* check for same files from old_list */ | |
2171 work = old_list; | |
2172 while (work) | |
2173 { | |
138 | 2174 IconData *id; |
9 | 2175 FileData *fd; |
138 | 2176 |
9 | 2177 GList *needle; |
2178 | |
138 | 2179 id = work->data; |
2180 fd = id->fd; | |
2181 | |
9 | 2182 needle = vfi->list; |
2183 while (needle) | |
2184 { | |
138 | 2185 IconData *idn = needle->data; |
2186 FileData *fdn = idn->fd; | |
167 | 2187 if (fdn == fd) |
9 | 2188 { |
2189 /* swap, to retain old thumb, selection */ | |
138 | 2190 needle->data = id; |
2191 work->data = idn; | |
9 | 2192 needle = NULL; |
2193 } | |
2194 else | |
2195 { | |
2196 needle = needle->next; | |
2197 } | |
2198 } | |
2199 | |
2200 work = work->next; | |
2201 } | |
2202 | |
138 | 2203 vfi->list = iconlist_sort(vfi->list, vfi->sort_method, vfi->sort_ascend); |
9 | 2204 |
2205 work = old_list; | |
2206 while (work) | |
2207 { | |
138 | 2208 IconData *id = work->data; |
9 | 2209 work = work->next; |
2210 | |
138 | 2211 if (id == vfi->prev_selection) vfi->prev_selection = NULL; |
2212 if (id == vfi->click_id) vfi->click_id = NULL; | |
9 | 2213 } |
2214 | |
2215 vficon_populate(vfi, TRUE, keep_position); | |
2216 | |
2217 /* attempt to keep focus on same icon when refreshing */ | |
138 | 2218 if (focus_id && g_list_find(vfi->list, focus_id)) |
9 | 2219 { |
138 | 2220 vficon_set_focus(vfi, focus_id); |
9 | 2221 } |
2222 | |
2223 iconlist_free(old_list); | |
2224 | |
2225 return ret; | |
2226 } | |
2227 | |
2228 gint vficon_refresh(ViewFileIcon *vfi) | |
2229 { | |
2230 return vficon_refresh_real(vfi, TRUE); | |
2231 } | |
2232 | |
2233 /* | |
2234 *----------------------------------------------------------------------------- | |
2235 * draw, etc. | |
2236 *----------------------------------------------------------------------------- | |
2237 */ | |
2238 | |
2239 typedef struct _ColumnData ColumnData; | |
2240 struct _ColumnData | |
2241 { | |
2242 ViewFileIcon *vfi; | |
2243 gint number; | |
2244 }; | |
2245 | |
2246 static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, | |
2247 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) | |
2248 { | |
2249 ColumnData *cd = data; | |
2250 ViewFileIcon *vfi; | |
2251 GtkStyle *style; | |
2252 GList *list; | |
2253 GdkColor color_fg; | |
2254 GdkColor color_bg; | |
138 | 2255 IconData *id; |
9 | 2256 |
2257 vfi = cd->vfi; | |
2258 | |
2259 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_POINTER, &list, -1); | |
138 | 2260 |
2261 id = g_list_nth_data(list, cd->number); | |
2262 | |
2263 if (id) g_assert(id->fd->magick == 0x12345678); | |
2264 | |
9 | 2265 style = gtk_widget_get_style(vfi->listview); |
138 | 2266 if (id && id->selected & SELECTION_SELECTED) |
9 | 2267 { |
2268 memcpy(&color_fg, &style->text[GTK_STATE_SELECTED], sizeof(color_fg)); | |
2269 memcpy(&color_bg, &style->base[GTK_STATE_SELECTED], sizeof(color_bg)); | |
2270 } | |
2271 else | |
2272 { | |
2273 memcpy(&color_fg, &style->text[GTK_STATE_NORMAL], sizeof(color_fg)); | |
2274 memcpy(&color_bg, &style->base[GTK_STATE_NORMAL], sizeof(color_bg)); | |
2275 } | |
2276 | |
138 | 2277 if (id && id->selected & SELECTION_PRELIGHT) |
9 | 2278 { |
2279 #if 0 | |
2280 shift_color(&color_fg, -1, 0); | |
2281 #endif | |
2282 shift_color(&color_bg, -1, 0); | |
2283 } | |
2284 | |
2285 if (GQV_IS_CELL_RENDERER_ICON(cell)) | |
2286 { | |
138 | 2287 if (id) |
9 | 2288 { |
138 | 2289 g_object_set(cell, "pixbuf", id->fd->pixbuf, |
2290 "text", id->fd->name, | |
9 | 2291 "cell-background-gdk", &color_bg, |
2292 "cell-background-set", TRUE, | |
2293 "foreground-gdk", &color_fg, | |
2294 "foreground-set", TRUE, | |
138 | 2295 "has-focus", (vfi->focus_id == id), NULL); |
9 | 2296 } |
2297 else | |
2298 { | |
2299 g_object_set(cell, "pixbuf", NULL, | |
2300 "text", NULL, | |
2301 "cell-background-set", FALSE, | |
2302 "foreground-set", FALSE, | |
2303 "has-focus", FALSE, NULL); | |
2304 } | |
2305 } | |
2306 } | |
2307 | |
2308 static void vficon_append_column(ViewFileIcon *vfi, gint n) | |
2309 { | |
2310 ColumnData *cd; | |
2311 GtkTreeViewColumn *column; | |
2312 GtkCellRenderer *renderer; | |
2313 | |
2314 column = gtk_tree_view_column_new(); | |
2315 gtk_tree_view_column_set_min_width(column, 0); | |
2316 | |
2317 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); | |
2318 gtk_tree_view_column_set_alignment(column, 0.5); | |
2319 | |
2320 renderer = gqv_cell_renderer_icon_new(); | |
2321 gtk_tree_view_column_pack_start(column, renderer, FALSE); | |
2322 g_object_set(G_OBJECT(renderer), "xpad", THUMB_BORDER_PADDING * 2, | |
2323 "ypad", THUMB_BORDER_PADDING, | |
2324 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); | |
2325 | |
2326 g_object_set_data(G_OBJECT(column), "column_number", GINT_TO_POINTER(n)); | |
2327 | |
2328 cd = g_new0(ColumnData, 1); | |
2329 cd->vfi = vfi; | |
2330 cd->number = n; | |
2331 gtk_tree_view_column_set_cell_data_func(column, renderer, vficon_cell_data_cb, cd, g_free); | |
2332 | |
2333 gtk_tree_view_append_column(GTK_TREE_VIEW(vfi->listview), column); | |
2334 } | |
2335 | |
2336 /* | |
2337 *----------------------------------------------------------------------------- | |
2338 * base | |
2339 *----------------------------------------------------------------------------- | |
2340 */ | |
2341 | |
2342 gint vficon_set_path(ViewFileIcon *vfi, const gchar *path) | |
2343 { | |
2344 gint ret; | |
2345 | |
2346 if (!path) return FALSE; | |
2347 if (vfi->path && strcmp(path, vfi->path) == 0) return TRUE; | |
2348 | |
2349 g_free(vfi->path); | |
2350 vfi->path = g_strdup(path); | |
2351 | |
2352 g_list_free(vfi->selection); | |
2353 vfi->selection = NULL; | |
2354 | |
2355 iconlist_free(vfi->list); | |
2356 vfi->list = NULL; | |
2357 | |
2358 /* NOTE: populate will clear the store for us */ | |
2359 ret = vficon_refresh_real(vfi, FALSE); | |
2360 | |
138 | 2361 vfi->focus_id = NULL; |
9 | 2362 vficon_move_focus(vfi, 0, 0, FALSE); |
2363 | |
2364 return ret; | |
2365 } | |
2366 | |
2367 static void vficon_destroy_cb(GtkWidget *widget, gpointer data) | |
2368 { | |
2369 ViewFileIcon *vfi = data; | |
2370 | |
2371 if (vfi->popup) | |
2372 { | |
2373 g_signal_handlers_disconnect_matched(G_OBJECT(vfi->popup), G_SIGNAL_MATCH_DATA, | |
2374 0, 0, 0, NULL, vfi); | |
2375 gtk_widget_destroy(vfi->popup); | |
2376 } | |
2377 | |
2378 if (vfi->sync_idle_id != -1) g_source_remove(vfi->sync_idle_id); | |
2379 | |
2380 tip_unschedule(vfi); | |
2381 | |
2382 vficon_thumb_cleanup(vfi); | |
2383 | |
2384 g_free(vfi->path); | |
2385 | |
2386 iconlist_free(vfi->list); | |
2387 g_list_free(vfi->selection); | |
2388 g_free(vfi); | |
2389 } | |
2390 | |
2391 ViewFileIcon *vficon_new(const gchar *path) | |
2392 { | |
2393 ViewFileIcon *vfi; | |
2394 GtkListStore *store; | |
2395 GtkTreeSelection *selection; | |
2396 gint i; | |
2397 | |
2398 vfi = g_new0(ViewFileIcon, 1); | |
2399 | |
2400 vfi->path = NULL; | |
2401 vfi->sort_method = SORT_NAME; | |
2402 vfi->sort_ascend = TRUE; | |
2403 | |
2404 vfi->selection = NULL; | |
2405 vfi->prev_selection = NULL; | |
2406 | |
2407 vfi->tip_window = NULL; | |
2408 vfi->tip_delay_id = -1; | |
2409 | |
2410 vfi->focus_row = 0; | |
2411 vfi->focus_column = 0; | |
138 | 2412 vfi->focus_id = NULL; |
9 | 2413 |
2414 vfi->show_text = show_icon_names; | |
2415 | |
2416 vfi->sync_idle_id = -1; | |
2417 | |
2418 vfi->popup = NULL; | |
2419 | |
2420 vfi->widget = gtk_scrolled_window_new(NULL, NULL); | |
2421 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(vfi->widget), GTK_SHADOW_IN); | |
2422 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vfi->widget), | |
2423 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
2424 g_signal_connect(G_OBJECT(vfi->widget), "destroy", | |
2425 G_CALLBACK(vficon_destroy_cb), vfi); | |
2426 | |
2427 store = gtk_list_store_new(1, G_TYPE_POINTER); | |
2428 vfi->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); | |
2429 g_object_unref(store); | |
2430 | |
2431 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfi->listview)); | |
2432 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_NONE); | |
2433 | |
2434 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vfi->listview), FALSE); | |
2435 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vfi->listview), FALSE); | |
2436 | |
2437 for (i = 0; i < VFICON_MAX_COLUMNS; i++) | |
2438 { | |
2439 vficon_append_column(vfi, i); | |
2440 } | |
2441 | |
2442 /* zero width column to hide tree view focus, we draw it ourselves */ | |
2443 vficon_append_column(vfi, i); | |
2444 /* end column to fill white space */ | |
2445 vficon_append_column(vfi, i); | |
2446 | |
2447 g_signal_connect(G_OBJECT(vfi->listview), "size_allocate", | |
2448 G_CALLBACK(vficon_sized_cb), vfi); | |
2449 g_signal_connect(G_OBJECT(vfi->listview), "key_press_event", | |
2450 G_CALLBACK(vficon_press_key_cb), vfi); | |
2451 | |
2452 gtk_container_add(GTK_CONTAINER(vfi->widget), vfi->listview); | |
2453 gtk_widget_show(vfi->listview); | |
2454 | |
2455 vficon_dnd_init(vfi); | |
2456 | |
2457 gtk_widget_set_events(vfi->listview, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | | |
2458 GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK); | |
2459 g_signal_connect(G_OBJECT(vfi->listview), "button_press_event", | |
2460 G_CALLBACK(vficon_press_cb), vfi); | |
2461 g_signal_connect(G_OBJECT(vfi->listview), "button_release_event", | |
2462 G_CALLBACK(vficon_release_cb), vfi); | |
2463 g_signal_connect(G_OBJECT(vfi->listview),"motion_notify_event", | |
2464 G_CALLBACK(vficon_motion_cb), vfi); | |
2465 g_signal_connect(G_OBJECT(vfi->listview), "leave_notify_event", | |
2466 G_CALLBACK(vficon_leave_cb), vfi); | |
2467 | |
2468 /* force vfi->columns to be at least 1 (sane) - this will be corrected in the size_cb */ | |
2469 vficon_populate_at_new_size(vfi, 1, 1, FALSE); | |
2470 | |
2471 if (path) vficon_set_path(vfi, path); | |
2472 | |
2473 return vfi; | |
2474 } | |
2475 | |
2476 void vficon_set_status_func(ViewFileIcon *vfi, | |
2477 void (*func)(ViewFileIcon *vfi, gpointer data), gpointer data) | |
2478 { | |
2479 vfi->func_status = func; | |
2480 vfi->data_status = data; | |
2481 } | |
2482 | |
2483 void vficon_set_thumb_status_func(ViewFileIcon *vfi, | |
2484 void (*func)(ViewFileIcon *vfi, gdouble val, const gchar *text, gpointer data), | |
2485 gpointer data) | |
2486 { | |
2487 vfi->func_thumb_status = func; | |
2488 vfi->data_thumb_status = data; | |
2489 } | |
2490 | |
2491 void vficon_set_layout(ViewFileIcon *vfi, LayoutWindow *layout) | |
2492 { | |
2493 vfi->layout = layout; | |
2494 } | |
2495 | |
2496 /* | |
2497 *----------------------------------------------------------------------------- | |
2498 * maintenance (for rename, move, remove) | |
2499 *----------------------------------------------------------------------------- | |
2500 */ | |
2501 | |
2502 static gint vficon_maint_find_closest(ViewFileIcon *vfi, gint row, gint count, GList *ignore_list) | |
2503 { | |
2504 GList *list = NULL; | |
2505 GList *work; | |
2506 gint rev = row - 1; | |
2507 row ++; | |
2508 | |
2509 work = ignore_list; | |
2510 while (work) | |
2511 { | |
138 | 2512 FileData *fd = work->data; |
2513 gint f = vficon_index_by_fd(vfi, work->data); | |
2514 g_assert(fd->magick == 0x12345678); | |
9 | 2515 if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f)); |
2516 work = work->next; | |
2517 } | |
2518 | |
2519 while (list) | |
2520 { | |
2521 gint c = TRUE; | |
2522 work = list; | |
2523 while (work && c) | |
2524 { | |
2525 gpointer p = work->data; | |
2526 work = work->next; | |
2527 if (row == GPOINTER_TO_INT(p)) | |
2528 { | |
2529 row++; | |
2530 c = FALSE; | |
2531 } | |
2532 if (rev == GPOINTER_TO_INT(p)) | |
2533 { | |
2534 rev--; | |
2535 c = FALSE; | |
2536 } | |
2537 if (!c) list = g_list_remove(list, p); | |
2538 } | |
2539 if (c && list) | |
2540 { | |
2541 g_list_free(list); | |
2542 list = NULL; | |
2543 } | |
2544 } | |
2545 if (row > count - 1) | |
2546 { | |
2547 if (rev < 0) | |
2548 return -1; | |
2549 else | |
2550 return rev; | |
2551 } | |
2552 else | |
2553 { | |
2554 return row; | |
2555 } | |
2556 } | |
2557 | |
138 | 2558 gint vficon_maint_renamed(ViewFileIcon *vfi, FileData *fd) |
9 | 2559 { |
2560 gint ret = FALSE; | |
2561 gint row; | |
2562 gchar *source_base; | |
2563 gchar *dest_base; | |
138 | 2564 IconData *id = vficon_icon_data(vfi, fd); |
2565 | |
2566 if (!id) return FALSE; | |
2567 | |
2568 row = vficon_index_by_id(vfi, id); | |
9 | 2569 if (row < 0) return FALSE; |
2570 | |
138 | 2571 source_base = remove_level_from_path(fd->change->source); |
2572 dest_base = remove_level_from_path(fd->change->dest); | |
9 | 2573 |
2574 if (strcmp(source_base, dest_base) == 0) | |
2575 { | |
138 | 2576 vfi->list = g_list_remove(vfi->list, id); |
2577 vfi->list = iconlist_insert_sort(vfi->list, id, vfi->sort_method, vfi->sort_ascend); | |
9 | 2578 |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
2579 vficon_sync_idle(vfi); |
9 | 2580 ret = TRUE; |
2581 } | |
2582 else | |
2583 { | |
138 | 2584 ret = vficon_maint_removed(vfi, fd, NULL); |
9 | 2585 } |
2586 | |
2587 g_free(source_base); | |
2588 g_free(dest_base); | |
2589 | |
2590 return ret; | |
2591 } | |
2592 | |
138 | 2593 gint vficon_maint_removed(ViewFileIcon *vfi, FileData *fd, GList *ignore_list) |
9 | 2594 { |
2595 gint row; | |
2596 gint new_row = -1; | |
2597 GtkTreeModel *store; | |
2598 GtkTreeIter iter; | |
138 | 2599 IconData *id = vficon_icon_data(vfi, fd); |
2600 | |
2601 if (!id) return FALSE; | |
2602 | |
2603 row = g_list_index(vfi->list, id); | |
9 | 2604 if (row < 0) return FALSE; |
2605 | |
138 | 2606 if ((id->selected & SELECTION_SELECTED) && |
9 | 2607 layout_image_get_collection(vfi->layout, NULL) == NULL) |
2608 { | |
138 | 2609 vficon_unselect(vfi, id); |
9 | 2610 |
2611 if (!vfi->selection) | |
2612 { | |
2613 gint n; | |
2614 | |
2615 n = vficon_count(vfi, NULL); | |
2616 if (ignore_list) | |
2617 { | |
2618 new_row = vficon_maint_find_closest(vfi, row, n, ignore_list); | |
2619 if (debug) printf("row = %d, closest is %d\n", row, new_row); | |
2620 } | |
2621 else | |
2622 { | |
2623 if (row + 1 < n) | |
2624 { | |
2625 new_row = row + 1; | |
2626 } | |
2627 else if (row > 0) | |
2628 { | |
2629 new_row = row - 1; | |
2630 } | |
2631 } | |
2632 } | |
2633 else if (ignore_list) | |
2634 { | |
2635 GList *work; | |
2636 | |
2637 work = vfi->selection; | |
2638 while (work) | |
2639 { | |
138 | 2640 IconData *ignore_id; |
9 | 2641 FileData *ignore_fd; |
2642 GList *tmp; | |
2643 gint match = FALSE; | |
2644 | |
138 | 2645 ignore_id = work->data; |
2646 ignore_fd = ignore_id->fd; | |
2647 g_assert(ignore_fd->magick == 0x12345678); | |
9 | 2648 work = work->next; |
2649 | |
2650 tmp = ignore_list; | |
2651 while (tmp && !match) | |
2652 { | |
138 | 2653 FileData *ignore_list_fd = tmp->data; |
2654 g_assert(ignore_list_fd->magick == 0x12345678); | |
9 | 2655 tmp = tmp->next; |
2656 | |
138 | 2657 if (ignore_list_fd == ignore_fd) |
9 | 2658 { |
2659 match = TRUE; | |
2660 } | |
2661 } | |
2662 if (!match) | |
2663 { | |
138 | 2664 new_row = g_list_index(vfi->list, ignore_id); |
9 | 2665 work = NULL; |
2666 } | |
2667 } | |
2668 if (new_row == -1) | |
2669 { | |
2670 /* selection all ignored, use closest */ | |
2671 new_row = vficon_maint_find_closest(vfi, row, vficon_count(vfi, NULL), ignore_list); | |
2672 } | |
2673 } | |
2674 else | |
2675 { | |
2676 new_row = g_list_index(vfi->list, vfi->selection->data); | |
2677 } | |
2678 if (new_row >= 0) | |
2679 { | |
272 | 2680 IconData *idn = g_list_nth_data(vfi->list, new_row); |
9 | 2681 |
138 | 2682 vficon_select(vfi, idn); |
2683 vficon_send_layout_select(vfi, idn); | |
9 | 2684 } |
2685 } | |
2686 | |
2687 /* Thumb loader check */ | |
2688 if (fd == vfi->thumbs_fd) vfi->thumbs_fd = NULL; | |
111
3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
2689 if (vfi->thumbs_count > 0) vfi->thumbs_count--; |
9 | 2690 |
138 | 2691 if (vfi->prev_selection == id) vfi->prev_selection = NULL; |
2692 if (vfi->click_id == id) vfi->click_id = NULL; | |
9 | 2693 |
2694 /* remove pointer to this fd from grid */ | |
2695 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfi->listview)); | |
138 | 2696 if (id->row >= 0 && |
2697 gtk_tree_model_iter_nth_child(store, &iter, NULL, id->row)) | |
9 | 2698 { |
2699 GList *list; | |
2700 | |
2701 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); | |
138 | 2702 list = g_list_find(list, id); |
9 | 2703 if (list) list->data = NULL; |
2704 } | |
2705 | |
138 | 2706 vfi->list = g_list_remove(vfi->list, id); |
2707 file_data_unref(fd); | |
2708 g_free(id); | |
9 | 2709 |
2710 vficon_sync_idle(vfi); | |
2711 vficon_send_update(vfi); | |
2712 | |
2713 return TRUE; | |
2714 } | |
2715 | |
138 | 2716 gint vficon_maint_moved(ViewFileIcon *vfi, FileData *fd, GList *ignore_list) |
9 | 2717 { |
2718 gint ret = FALSE; | |
2719 gchar *buf; | |
2720 | |
138 | 2721 if (!fd->change->source || !vfi->path) return FALSE; |
2722 | |
2723 buf = remove_level_from_path(fd->change->source); | |
9 | 2724 |
2725 if (strcmp(buf, vfi->path) == 0) | |
2726 { | |
138 | 2727 ret = vficon_maint_removed(vfi, fd, ignore_list); |
9 | 2728 } |
2729 | |
2730 g_free(buf); | |
2731 | |
2732 return ret; | |
2733 } | |
2734 |