Mercurial > geeqie.yaz
annotate src/view_file_icon.c @ 454:57459cf0952c
Prefix editor entries in the main menu with numbers.
It allows Alt+E+number as shortcut to start an editor.
author | zas_ |
---|---|
date | Sun, 20 Apr 2008 22:29:23 +0000 |
parents | a73cc0fa14d0 |
children | 48c8e49b571c |
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 | |
281 | 12 #include "main.h" |
9 | 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; | |
442 | 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); | |
442 | 123 work = work->next; |
124 } | |
125 | |
126 g_list_free(list); | |
138 | 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; | |
442 | 205 |
9 | 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; |
442 | 250 |
9 | 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 | |
380
5afe77bb563a
Introduce a new struct ViewDir to handle directory views common
zas_
parents:
334
diff
changeset
|
284 if (vfi->layout) layout_views_set(vfi->layout, vfi->layout->dir_view_type, FALSE); |
9 | 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 { | |
442 | 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; | |
442 | 379 |
144 | 380 cur_fd = layout_image_get_fd(vfi->layout); |
381 if (sel_fd == cur_fd) return; /* no change */ | |
442 | 382 |
334 | 383 if (options->image.enable_read_ahead) |
9 | 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; | |
320 | 405 options->show_icon_names = vfi->show_text; |
9 | 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 | |
333 | 414 if (!vfi->show_text) return options->thumbnails.max_width; |
415 | |
416 width = options->thumbnails.max_width + options->thumbnails.max_width / 2; | |
9 | 417 if (width < THUMB_MIN_ICON_WIDTH) width = THUMB_MIN_ICON_WIDTH; |
333 | 418 if (width > THUMB_MAX_ICON_WIDTH) width = options->thumbnails.max_width; |
9 | 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 | |
330 | 863 if (!options->collections.rectangular_selection) |
9 | 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); | |
442 | 880 |
9 | 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; | |
442 | 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; | |
442 | 957 g_assert(fd->magick == 0x12345678); |
138 | 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 | |
442 | 974 work = vfi->selection; |
9 | 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 | |
442 | 1042 g_assert(fd->magick == 0x12345678); |
165 | 1043 |
1044 mark_val = fd->marks[mark]; | |
1045 selected = (id->selected & SELECTION_SELECTED); | |
442 | 1046 |
1047 switch (mode) | |
165 | 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 } | |
442 | 1058 |
165 | 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; | |
442 | 1077 |
165 | 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 } | |
442 | 1087 |
165 | 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 | |
333 | 1259 row_height = options->thumbnails.max_height + THUMB_BORDER_PADDING * 2; |
1260 if (vfi->show_text) row_height += options->thumbnails.max_height / 3; | |
9 | 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 { | |
330 | 1385 if (!options->collections.rectangular_selection) |
9 | 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); | |
442 | 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 { | |
448
a73cc0fa14d0
Use explicit names for mouse buttons instead of numbers.
zas_
parents:
446
diff
changeset
|
1453 case MOUSE_BUTTON_LEFT: |
9 | 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; | |
448
a73cc0fa14d0
Use explicit names for mouse buttons instead of numbers.
zas_
parents:
446
diff
changeset
|
1467 case MOUSE_BUTTON_RIGHT: |
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 |
448
a73cc0fa14d0
Use explicit names for mouse buttons instead of numbers.
zas_
parents:
446
diff
changeset
|
1499 if (bevent->button == MOUSE_BUTTON_LEFT && |
138 | 1500 id && vfi->click_id == id) |
9 | 1501 { |
138 | 1502 vficon_set_focus(vfi, id); |
442 | 1503 |
9 | 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 } | |
448
a73cc0fa14d0
Use explicit names for mouse buttons instead of numbers.
zas_
parents:
446
diff
changeset
|
1534 else if (bevent->button == MOUSE_BUTTON_MIDDLE && |
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, | |
333 | 1667 "fixed_height", options->thumbnails.max_height, |
9 | 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 } | |
442 | 1768 |
9 | 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 | |
333 | 1993 vfi->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height); |
9 | 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; |
442 | 2031 |
138 | 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; |
442 | 2040 |
138 | 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 { | |
442 | 2116 |
138 | 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; |
442 | 2176 |
9 | 2177 GList *needle; |
2178 | |
138 | 2179 id = work->data; |
2180 fd = id->fd; | |
442 | 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); | |
442 | 2260 |
138 | 2261 id = g_list_nth_data(list, cd->number); |
442 | 2262 |
138 | 2263 if (id) g_assert(id->fd->magick == 0x12345678); |
442 | 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)) | |
442 | 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); | |
442 | 2304 } |
9 | 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 |
320 | 2414 vfi->show_text = options->show_icon_names; |
9 | 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; | |
442 | 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; |
442 | 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 } |