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