4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
14 #include "view_file_icon.h"
16 #include "cellrenderericon.h"
18 #include "collect-io.h"
19 #include "collect-table.h"
27 #include "layout_image.h"
31 #include "ui_bookmark.h"
32 #include "ui_fileops.h"
34 #include "ui_tree_edit.h"
35 #include "view_file.h"
37 #include <gdk/gdkkeysyms.h> /* for keyboard values */
40 /* between these, the icon width is increased by thumb_max_width / 2 */
41 #define THUMB_MIN_ICON_WIDTH 128
42 #define THUMB_MAX_ICON_WIDTH 150
44 #define VFICON_MAX_COLUMNS 32
45 #define THUMB_BORDER_PADDING 2
47 #define VFICON_TIP_DELAY 500
50 FILE_COLUMN_POINTER = 0,
56 SELECTION_SELECTED = 1 << 0,
57 SELECTION_PRELIGHT = 1 << 1,
58 SELECTION_FOCUS = 1 << 2
61 typedef struct _IconData IconData;
64 SelectionType selected;
69 static gint vficon_index_by_id(ViewFile *vf, IconData *in_id);
71 static IconData *vficon_icon_data(ViewFile *vf, FileData *fd)
80 IconData *chk = work->data;
82 if (chk->fd == fd) id = chk;
88 static gint iconlist_read(const gchar *path, GList **list)
93 if (!filelist_read(path, &temp, NULL)) return FALSE;
102 g_assert(fd->magick == 0x12345678);
103 id = g_new0(IconData, 1);
105 id->selected = SELECTION_NONE;
118 static void iconlist_free(GList *list)
123 IconData *id = work->data;
124 file_data_unref(id->fd);
133 gint iconlist_sort_file_cb(void *a, void *b)
137 return filelist_sort_compare_filedata(ida->fd, idb->fd);
140 GList *iconlist_sort(GList *list, SortType method, gint ascend)
142 return filelist_sort_full(list, method, ascend, (GCompareFunc) iconlist_sort_file_cb);
145 GList *iconlist_insert_sort(GList *list, IconData *id, SortType method, gint ascend)
147 return filelist_insert_sort_full(list, id, method, ascend, (GCompareFunc) iconlist_sort_file_cb);
151 static void vficon_toggle_filenames(ViewFile *vf);
152 static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter);
153 static void vficon_move_focus(ViewFile *vf, gint row, gint col, gint relative);
154 static void vficon_set_focus(ViewFile *vf, IconData *id);
155 static void vficon_thumb_update(ViewFile *vf);
156 static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gint force);
160 *-----------------------------------------------------------------------------
162 *-----------------------------------------------------------------------------
165 GList *vficon_pop_menu_file_list(ViewFile *vf)
167 if (!VFICON_INFO(vf, click_id)) return NULL;
169 if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED)
171 return vf_selection_get_list(vf);
174 return g_list_append(NULL, file_data_ref(VFICON_INFO(vf, click_id)->fd));
177 void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data)
181 if (!VFICON_INFO(vf, click_id)) return;
183 if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED)
187 list = vf_selection_get_list(vf);
188 view_window_new_from_list(list);
193 view_window_new(VFICON_INFO(vf, click_id)->fd);
197 void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
201 file_util_rename(NULL, vf_pop_menu_file_list(vf), vf->listview);
204 static void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data)
208 vficon_toggle_filenames(vf);
211 void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
218 void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data)
221 vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL);
222 VFICON_INFO(vf, click_id) = NULL;
226 static GtkWidget *vficon_pop_menu(ViewFile *vf)
233 active = (VFICON_INFO(vf, click_id) != NULL);
235 menu = popup_menu_short_lived();
237 g_signal_connect(G_OBJECT(menu), "destroy",
238 G_CALLBACK(vf_popup_destroy_cb), vf);
240 submenu_add_edit(menu, &item, G_CALLBACK(vf_pop_menu_edit_cb), vf);
241 gtk_widget_set_sensitive(item, active);
243 menu_item_add_stock_sensitive(menu, _("_Properties"), GTK_STOCK_PROPERTIES, active,
244 G_CALLBACK(vf_pop_menu_info_cb), vf);
246 menu_item_add_stock_sensitive(menu, _("View in _new window"), GTK_STOCK_NEW, active,
247 G_CALLBACK(vficon_pop_menu_view_cb), vf);
248 menu_item_add_divider(menu);
250 menu_item_add_stock_sensitive(menu, _("_Copy..."), GTK_STOCK_COPY, active,
251 G_CALLBACK(vf_pop_menu_copy_cb), vf);
252 menu_item_add_sensitive(menu, _("_Move..."), active,
253 G_CALLBACK(vf_pop_menu_move_cb), vf);
254 menu_item_add_sensitive(menu, _("_Rename..."), active,
255 G_CALLBACK(vf_pop_menu_rename_cb), vf);
256 menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, active,
257 G_CALLBACK(vf_pop_menu_delete_cb), vf);
258 if (options->show_copy_path)
259 menu_item_add_sensitive(menu, _("_Copy path"), active,
260 G_CALLBACK(vf_pop_menu_copy_path_cb), vf);
261 menu_item_add_divider(menu);
263 submenu = submenu_add_sort(NULL, G_CALLBACK(vf_pop_menu_sort_cb), vf,
264 FALSE, FALSE, TRUE, vf->sort_method);
265 menu_item_add_divider(submenu);
266 menu_item_add_check(submenu, _("Ascending"), vf->sort_ascend,
267 G_CALLBACK(vf_pop_menu_sort_ascend_cb), vf);
269 item = menu_item_add(menu, _("_Sort"), NULL, NULL);
270 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
272 menu_item_add_check(menu, _("View as _icons"), TRUE,
273 G_CALLBACK(vf_pop_menu_toggle_view_type_cb), vf);
274 menu_item_add_check(menu, _("Show filename _text"), VFICON_INFO(vf, show_text),
275 G_CALLBACK(vficon_pop_menu_show_names_cb), vf);
276 menu_item_add_stock(menu, _("Re_fresh"), GTK_STOCK_REFRESH, G_CALLBACK(vf_pop_menu_refresh_cb), vf);
282 *-------------------------------------------------------------------
284 *-------------------------------------------------------------------
287 static void vficon_send_layout_select(ViewFile *vf, IconData *id)
289 FileData *read_ahead_fd = NULL;
293 if (!vf->layout || !id || !id->fd) return;
297 cur_fd = layout_image_get_fd(vf->layout);
298 if (sel_fd == cur_fd) return; /* no change */
300 if (options->image.enable_read_ahead)
304 row = g_list_index(vf->list, id);
305 if (row > vficon_index_by_fd(vf, cur_fd) &&
306 row + 1 < vf_count(vf, NULL))
308 read_ahead_fd = vf_index_get_data(vf, row + 1);
312 read_ahead_fd = vf_index_get_data(vf, row - 1);
316 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
319 static void vficon_toggle_filenames(ViewFile *vf)
321 VFICON_INFO(vf, show_text) = !VFICON_INFO(vf, show_text);
322 options->show_icon_names = VFICON_INFO(vf, show_text);
324 vficon_populate_at_new_size(vf, vf->listview->allocation.width, vf->listview->allocation.height, TRUE);
327 static gint vficon_get_icon_width(ViewFile *vf)
331 if (!VFICON_INFO(vf, show_text)) return options->thumbnails.max_width;
333 width = options->thumbnails.max_width + options->thumbnails.max_width / 2;
334 if (width < THUMB_MIN_ICON_WIDTH) width = THUMB_MIN_ICON_WIDTH;
335 if (width > THUMB_MAX_ICON_WIDTH) width = options->thumbnails.max_width;
341 *-------------------------------------------------------------------
343 *-------------------------------------------------------------------
346 static gint vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint *col)
350 n = g_list_index(vf->list, id);
352 if (n < 0) return FALSE;
354 *row = n / VFICON_INFO(vf, columns);
355 *col = n - (*row * VFICON_INFO(vf, columns));
360 static gint vficon_find_iter(ViewFile *vf, IconData *id, GtkTreeIter *iter, gint *column)
365 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
366 if (!vficon_find_position(vf, id, &row, &col)) return FALSE;
367 if (!gtk_tree_model_iter_nth_child(store, iter, NULL, row)) return FALSE;
368 if (column) *column = col;
373 static IconData *vficon_find_data(ViewFile *vf, gint row, gint col, GtkTreeIter *iter)
378 if (row < 0 || col < 0) return NULL;
380 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
381 if (gtk_tree_model_iter_nth_child(store, &p, NULL, row))
385 gtk_tree_model_get(store, &p, FILE_COLUMN_POINTER, &list, -1);
386 if (!list) return NULL;
390 return g_list_nth_data(list, col);
396 static IconData *vficon_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
399 GtkTreeViewColumn *column;
401 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
402 &tpath, &column, NULL, NULL))
409 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
410 gtk_tree_model_get_iter(store, &row, tpath);
411 gtk_tree_path_free(tpath);
413 gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
415 n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_number"));
418 if (iter) *iter = row;
419 return g_list_nth_data(list, n);
427 *-------------------------------------------------------------------
428 * tooltip type window
429 *-------------------------------------------------------------------
432 static void tip_show(ViewFile *vf)
437 if (VFICON_INFO(vf, tip_window)) return;
439 gdk_window_get_pointer(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)), &x, &y, NULL);
441 VFICON_INFO(vf, tip_id) = vficon_find_data_by_coord(vf, x, y, NULL);
442 if (!VFICON_INFO(vf, tip_id)) return;
444 VFICON_INFO(vf, tip_window) = gtk_window_new(GTK_WINDOW_POPUP);
445 gtk_window_set_resizable(GTK_WINDOW(VFICON_INFO(vf, tip_window)), FALSE);
446 gtk_container_set_border_width(GTK_CONTAINER(VFICON_INFO(vf, tip_window)), 2);
448 label = gtk_label_new(VFICON_INFO(vf, tip_id)->fd->name);
450 g_object_set_data(G_OBJECT(VFICON_INFO(vf, tip_window)), "tip_label", label);
451 gtk_container_add(GTK_CONTAINER(VFICON_INFO(vf, tip_window)), label);
452 gtk_widget_show(label);
454 gdk_window_get_pointer(NULL, &x, &y, NULL);
456 if (!GTK_WIDGET_REALIZED(VFICON_INFO(vf, tip_window))) gtk_widget_realize(VFICON_INFO(vf, tip_window));
457 gtk_window_move(GTK_WINDOW(VFICON_INFO(vf, tip_window)), x + 16, y + 16);
458 gtk_widget_show(VFICON_INFO(vf, tip_window));
461 static void tip_hide(ViewFile *vf)
463 if (VFICON_INFO(vf, tip_window)) gtk_widget_destroy(VFICON_INFO(vf, tip_window));
464 VFICON_INFO(vf, tip_window) = NULL;
467 static gint tip_schedule_cb(gpointer data)
472 if (VFICON_INFO(vf, tip_delay_id) == -1) return FALSE;
474 window = gtk_widget_get_toplevel(vf->listview);
476 if (GTK_WIDGET_SENSITIVE(window) &&
477 GTK_WINDOW(window)->has_focus)
482 VFICON_INFO(vf, tip_delay_id) = -1;
486 static void tip_schedule(ViewFile *vf)
490 if (VFICON_INFO(vf, tip_delay_id) != -1)
492 g_source_remove(VFICON_INFO(vf, tip_delay_id));
493 VFICON_INFO(vf, tip_delay_id) = -1;
496 if (!VFICON_INFO(vf, show_text))
498 VFICON_INFO(vf, tip_delay_id) = g_timeout_add(VFICON_TIP_DELAY, tip_schedule_cb, vf);
502 static void tip_unschedule(ViewFile *vf)
506 if (VFICON_INFO(vf, tip_delay_id) != -1) g_source_remove(VFICON_INFO(vf, tip_delay_id));
507 VFICON_INFO(vf, tip_delay_id) = -1;
510 static void tip_update(ViewFile *vf, IconData *id)
512 if (VFICON_INFO(vf, tip_window))
516 gdk_window_get_pointer(NULL, &x, &y, NULL);
517 gtk_window_move(GTK_WINDOW(VFICON_INFO(vf, tip_window)), x + 16, y + 16);
519 if (id != VFICON_INFO(vf, tip_id))
523 VFICON_INFO(vf, tip_id) = id;
525 if (!VFICON_INFO(vf, tip_id))
532 label = g_object_get_data(G_OBJECT(VFICON_INFO(vf, tip_window)), "tip_label");
533 gtk_label_set_text(GTK_LABEL(label), VFICON_INFO(vf, tip_id)->fd->name);
543 *-------------------------------------------------------------------
545 *-------------------------------------------------------------------
548 static void vficon_dnd_get(GtkWidget *widget, GdkDragContext *context,
549 GtkSelectionData *selection_data, guint info,
550 guint time, gpointer data)
554 gchar *uri_text = NULL;
557 if (!VFICON_INFO(vf, click_id)) return;
559 if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED)
561 list = vf_selection_get_list(vf);
565 list = g_list_append(NULL, file_data_ref(VFICON_INFO(vf, click_id)->fd));
569 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
574 gtk_selection_data_set(selection_data, selection_data->target,
575 8, (guchar *)uri_text, total);
579 static void vficon_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
585 if (VFICON_INFO(vf, click_id) && VFICON_INFO(vf, click_id)->fd->pixbuf)
589 if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED)
590 items = g_list_length(VFICON_INFO(vf, selection));
594 dnd_set_drag_icon(widget, context, VFICON_INFO(vf, click_id)->fd->pixbuf, items);
598 static void vficon_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
602 vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL);
604 if (context->action == GDK_ACTION_MOVE)
612 void vficon_dnd_init(ViewFile *vf)
614 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
615 dnd_file_drag_types, dnd_file_drag_types_count,
616 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
617 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
618 G_CALLBACK(vficon_dnd_get), vf);
619 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
620 G_CALLBACK(vficon_dnd_begin), vf);
621 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
622 G_CALLBACK(vficon_dnd_end), vf);
626 *-------------------------------------------------------------------
628 *-------------------------------------------------------------------
631 static void vficon_selection_set(ViewFile *vf, IconData *id, SelectionType value, GtkTreeIter *iter)
639 if (id->selected == value) return;
640 id->selected = value;
642 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
645 gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1);
646 if (list) gtk_list_store_set(GTK_LIST_STORE(store), iter, FILE_COLUMN_POINTER, list, -1);
652 if (vficon_find_iter(vf, id, &row, NULL))
654 gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
655 if (list) gtk_list_store_set(GTK_LIST_STORE(store), &row, FILE_COLUMN_POINTER, list, -1);
660 static void vficon_selection_add(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
664 vficon_selection_set(vf, id, id->selected | mask, iter);
667 static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
671 vficon_selection_set(vf, id, id->selected & ~mask, iter);
675 *-------------------------------------------------------------------
677 *-------------------------------------------------------------------
680 static void vficon_verify_selections(ViewFile *vf)
684 work = VFICON_INFO(vf, selection);
687 IconData *id = work->data;
690 if (vficon_index_by_id(vf, id) >= 0) continue;
692 VFICON_INFO(vf, selection) = g_list_remove(VFICON_INFO(vf, selection), id);
696 void vficon_select_all(ViewFile *vf)
700 g_list_free(VFICON_INFO(vf, selection));
701 VFICON_INFO(vf, selection) = NULL;
706 IconData *id = work->data;
709 VFICON_INFO(vf, selection) = g_list_append(VFICON_INFO(vf, selection), id);
710 vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
716 void vficon_select_none(ViewFile *vf)
720 work = VFICON_INFO(vf, selection);
723 IconData *id = work->data;
726 vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
729 g_list_free(VFICON_INFO(vf, selection));
730 VFICON_INFO(vf, selection) = NULL;
735 void vficon_select_invert(ViewFile *vf)
742 IconData *id = work->data;
745 if (id->selected & SELECTION_SELECTED)
747 VFICON_INFO(vf, selection) = g_list_remove(VFICON_INFO(vf, selection), id);
748 vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
752 VFICON_INFO(vf, selection) = g_list_append(VFICON_INFO(vf, selection), id);
753 vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
760 static void vficon_select(ViewFile *vf, IconData *id)
762 VFICON_INFO(vf, prev_selection) = id;
764 if (!id || id->selected & SELECTION_SELECTED) return;
766 VFICON_INFO(vf, selection) = g_list_append(VFICON_INFO(vf, selection), id);
767 vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
772 static void vficon_unselect(ViewFile *vf, IconData *id)
774 VFICON_INFO(vf, prev_selection) = id;
776 if (!id || !(id->selected & SELECTION_SELECTED) ) return;
778 VFICON_INFO(vf, selection) = g_list_remove(VFICON_INFO(vf, selection), id);
779 vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
784 static void vficon_select_util(ViewFile *vf, IconData *id, gint select)
788 vficon_select(vf, id);
792 vficon_unselect(vf, id);
796 static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *end, gint select)
803 if (!vficon_find_position(vf, start, &row1, &col1) ||
804 !vficon_find_position(vf, end, &row2, &col2) ) return;
806 VFICON_INFO(vf, prev_selection) = end;
808 if (!options->collections.rectangular_selection)
813 if (g_list_index(vf->list, start) > g_list_index(vf->list, end))
820 work = g_list_find(vf->list, start);
824 vficon_select_util(vf, id, select);
826 if (work->data != end)
847 DEBUG_1("table: %d x %d to %d x %d", row1, col1, row2, col2);
849 for (i = row1; i <= row2; i++)
851 for (j = col1; j <= col2; j++)
853 IconData *id = vficon_find_data(vf, i, j, NULL);
854 if (id) vficon_select_util(vf, id, select);
859 gint vficon_index_is_selected(ViewFile *vf, gint row)
861 IconData *id = g_list_nth_data(vf->list, row);
863 if (!id) return FALSE;
865 return (id->selected & SELECTION_SELECTED);
868 gint vficon_selection_count(ViewFile *vf, gint64 *bytes)
875 work = VFICON_INFO(vf, selection);
878 IconData *id = work->data;
879 FileData *fd = id->fd;
880 g_assert(fd->magick == 0x12345678);
889 return g_list_length(VFICON_INFO(vf, selection));
892 GList *vficon_selection_get_list(ViewFile *vf)
897 work = VFICON_INFO(vf, selection);
900 IconData *id = work->data;
901 FileData *fd = id->fd;
902 g_assert(fd->magick == 0x12345678);
904 list = g_list_prepend(list, file_data_ref(fd));
909 list = g_list_reverse(list);
914 GList *vficon_selection_get_list_by_index(ViewFile *vf)
919 work = VFICON_INFO(vf, selection);
922 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, work->data)));
926 return g_list_reverse(list);
929 static void vficon_select_by_id(ViewFile *vf, IconData *id)
933 if (!(id->selected & SELECTION_SELECTED))
936 vficon_select(vf, id);
939 vficon_set_focus(vf, id);
942 void vficon_select_by_fd(ViewFile *vf, FileData *fd)
951 IconData *chk = work->data;
953 if (chk->fd == fd) id = chk;
955 vficon_select_by_id(vf, id);
958 void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
963 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
968 IconData *id = work->data;
969 FileData *fd = id->fd;
970 gboolean mark_val, selected;
972 g_assert(fd->magick == 0x12345678);
974 mark_val = fd->marks[n];
975 selected = (id->selected & SELECTION_SELECTED);
979 case MTS_MODE_SET: selected = mark_val;
981 case MTS_MODE_OR: selected = mark_val | selected;
983 case MTS_MODE_AND: selected = mark_val & selected;
985 case MTS_MODE_MINUS: selected = !mark_val & selected;
989 vficon_select_util(vf, id, selected);
995 void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1001 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1003 slist = vf_selection_get_list(vf);
1007 FileData *fd = work->data;
1011 case STM_MODE_SET: fd->marks[n] = 1;
1013 case STM_MODE_RESET: fd->marks[n] = 0;
1015 case STM_MODE_TOGGLE: fd->marks[n] = !fd->marks[mark];
1021 filelist_free(slist);
1026 *-------------------------------------------------------------------
1028 *-------------------------------------------------------------------
1031 static void vficon_move_focus(ViewFile *vf, gint row, gint col, gint relative)
1038 new_row = VFICON_INFO(vf, focus_row);
1039 new_col = VFICON_INFO(vf, focus_column);
1042 if (new_row < 0) new_row = 0;
1043 if (new_row >= VFICON_INFO(vf, rows)) new_row = VFICON_INFO(vf, rows) - 1;
1063 new_col = VFICON_INFO(vf, columns) - 1;
1070 if (new_col >= VFICON_INFO(vf, columns))
1072 if (new_row < VFICON_INFO(vf, rows) - 1)
1079 new_col = VFICON_INFO(vf, columns) - 1;
1089 if (new_row >= VFICON_INFO(vf, rows))
1091 if (VFICON_INFO(vf, rows) > 0)
1092 new_row = VFICON_INFO(vf, rows) - 1;
1095 new_col = VFICON_INFO(vf, columns) - 1;
1097 if (new_col >= VFICON_INFO(vf, columns)) new_col = VFICON_INFO(vf, columns) - 1;
1100 if (new_row == VFICON_INFO(vf, rows) - 1)
1104 /* if we moved beyond the last image, go to the last image */
1106 l = g_list_length(vf->list);
1107 if (VFICON_INFO(vf, rows) > 1) l -= (VFICON_INFO(vf, rows) - 1) * VFICON_INFO(vf, columns);
1108 if (new_col >= l) new_col = l - 1;
1111 vficon_set_focus(vf, vficon_find_data(vf, new_row, new_col, NULL));
1114 static void vficon_set_focus(ViewFile *vf, IconData *id)
1119 if (g_list_find(vf->list, VFICON_INFO(vf, focus_id)))
1121 if (id == VFICON_INFO(vf, focus_id))
1123 /* ensure focus row col are correct */
1124 vficon_find_position(vf, VFICON_INFO(vf, focus_id), &VFICON_INFO(vf, focus_row), &VFICON_INFO(vf, focus_column));
1127 vficon_selection_remove(vf, VFICON_INFO(vf, focus_id), SELECTION_FOCUS, NULL);
1130 if (!vficon_find_position(vf, id, &row, &col))
1132 VFICON_INFO(vf, focus_id) = NULL;
1133 VFICON_INFO(vf, focus_row) = -1;
1134 VFICON_INFO(vf, focus_column) = -1;
1138 VFICON_INFO(vf, focus_id) = id;
1139 VFICON_INFO(vf, focus_row) = row;
1140 VFICON_INFO(vf, focus_column) = col;
1141 vficon_selection_add(vf, VFICON_INFO(vf, focus_id), SELECTION_FOCUS, NULL);
1143 if (vficon_find_iter(vf, VFICON_INFO(vf, focus_id), &iter, NULL))
1146 GtkTreeViewColumn *column;
1147 GtkTreeModel *store;
1149 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
1151 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1152 tpath = gtk_tree_model_get_path(store, &iter);
1153 /* focus is set to an extra column with 0 width to hide focus, we draw it ourself */
1154 column = gtk_tree_view_get_column(GTK_TREE_VIEW(vf->listview), VFICON_MAX_COLUMNS);
1155 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, column, FALSE);
1156 gtk_tree_path_free(tpath);
1160 static void vficon_update_focus(ViewFile *vf)
1165 if (VFICON_INFO(vf, focus_id) && vficon_find_position(vf, VFICON_INFO(vf, focus_id), &new_row, &new_col))
1167 /* first find the old focus, if it exists and is valid */
1171 /* (try to) stay where we were */
1172 new_row = VFICON_INFO(vf, focus_row);
1173 new_col = VFICON_INFO(vf, focus_column);
1176 vficon_move_focus(vf, new_row, new_col, FALSE);
1179 /* used to figure the page up/down distances */
1180 static gint page_height(ViewFile *vf)
1187 adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(vf->listview));
1188 page_size = (gint)adj->page_increment;
1190 row_height = options->thumbnails.max_height + THUMB_BORDER_PADDING * 2;
1191 if (VFICON_INFO(vf, show_text)) row_height += options->thumbnails.max_height / 3;
1193 ret = page_size / row_height;
1194 if (ret < 1) ret = 1;
1200 *-------------------------------------------------------------------
1202 *-------------------------------------------------------------------
1205 static void vfi_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
1207 ViewFile *vf = data;
1208 GtkTreeModel *store;
1214 if (!vficon_find_iter(vf, VFICON_INFO(vf, click_id), &iter, &column)) return;
1215 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1216 tpath = gtk_tree_model_get_path(store, &iter);
1217 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, column, FALSE, x, y, &cw, &ch);
1218 gtk_tree_path_free(tpath);
1220 popup_menu_position_clamp(menu, x, y, 0);
1223 gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
1225 ViewFile *vf = data;
1232 switch (event->keyval)
1234 case GDK_Left: case GDK_KP_Left:
1237 case GDK_Right: case GDK_KP_Right:
1240 case GDK_Up: case GDK_KP_Up:
1243 case GDK_Down: case GDK_KP_Down:
1246 case GDK_Page_Up: case GDK_KP_Page_Up:
1247 focus_row = -page_height(vf);
1249 case GDK_Page_Down: case GDK_KP_Page_Down:
1250 focus_row = page_height(vf);
1252 case GDK_Home: case GDK_KP_Home:
1253 focus_row = -VFICON_INFO(vf, focus_row);
1254 focus_col = -VFICON_INFO(vf, focus_column);
1256 case GDK_End: case GDK_KP_End:
1257 focus_row = VFICON_INFO(vf, rows) - 1 - VFICON_INFO(vf, focus_row);
1258 focus_col = VFICON_INFO(vf, columns) - 1 - VFICON_INFO(vf, focus_column);
1261 id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL);
1264 VFICON_INFO(vf, click_id) = id;
1265 if (event->state & GDK_CONTROL_MASK)
1269 selected = id->selected & SELECTION_SELECTED;
1272 vficon_unselect(vf, id);
1276 vficon_select(vf, id);
1277 vficon_send_layout_select(vf, id);
1283 vficon_select(vf, id);
1284 vficon_send_layout_select(vf, id);
1289 id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL);
1290 VFICON_INFO(vf, click_id) = id;
1292 vficon_selection_add(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL);
1295 vf->popup = vficon_pop_menu(vf);
1296 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vfi_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
1299 stop_signal = FALSE;
1303 if (focus_row != 0 || focus_col != 0)
1308 old_id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL);
1309 vficon_move_focus(vf, focus_row, focus_col, TRUE);
1310 new_id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL);
1312 if (new_id != old_id)
1314 if (event->state & GDK_SHIFT_MASK)
1316 if (!options->collections.rectangular_selection)
1318 vficon_select_region_util(vf, old_id, new_id, FALSE);
1322 vficon_select_region_util(vf, VFICON_INFO(vf, click_id), old_id, FALSE);
1324 vficon_select_region_util(vf, VFICON_INFO(vf, click_id), new_id, TRUE);
1325 vficon_send_layout_select(vf, new_id);
1327 else if (event->state & GDK_CONTROL_MASK)
1329 VFICON_INFO(vf, click_id) = new_id;
1333 VFICON_INFO(vf, click_id) = new_id;
1335 vficon_select(vf, new_id);
1336 vficon_send_layout_select(vf, new_id);
1344 g_signal_stop_emission_by_name(GTK_OBJECT(widget), "key_press_event");
1353 *-------------------------------------------------------------------
1355 *-------------------------------------------------------------------
1358 static gint vficon_motion_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
1360 ViewFile *vf = data;
1363 id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, NULL);
1369 gint vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
1371 ViewFile *vf = data;
1377 id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
1379 VFICON_INFO(vf, click_id) = id;
1380 vficon_selection_add(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, &iter);
1382 switch (bevent->button)
1384 case MOUSE_BUTTON_LEFT:
1385 if (!GTK_WIDGET_HAS_FOCUS(vf->listview))
1387 gtk_widget_grab_focus(vf->listview);
1390 if (bevent->type == GDK_2BUTTON_PRESS &&
1393 vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, &iter);
1394 layout_image_full_screen_start(vf->layout);
1398 case MOUSE_BUTTON_RIGHT:
1399 vf->popup = vficon_pop_menu(vf);
1400 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
1409 gint vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
1411 ViewFile *vf = data;
1413 IconData *id = NULL;
1418 if ((gint)bevent->x != 0 || (gint)bevent->y != 0)
1420 id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
1423 if (VFICON_INFO(vf, click_id))
1425 vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL);
1428 if (!id || VFICON_INFO(vf, click_id) != id) return TRUE;
1430 was_selected = (id->selected & SELECTION_SELECTED);
1432 switch (bevent->button)
1434 case MOUSE_BUTTON_LEFT:
1436 vficon_set_focus(vf, id);
1438 if (bevent->state & GDK_CONTROL_MASK)
1442 select = !(id->selected & SELECTION_SELECTED);
1443 if ((bevent->state & GDK_SHIFT_MASK) && VFICON_INFO(vf, prev_selection))
1445 vficon_select_region_util(vf, VFICON_INFO(vf, prev_selection), id, select);
1449 vficon_select_util(vf, id, select);
1456 if ((bevent->state & GDK_SHIFT_MASK) && VFICON_INFO(vf, prev_selection))
1458 vficon_select_region_util(vf, VFICON_INFO(vf, prev_selection), id, TRUE);
1462 vficon_select_util(vf, id, TRUE);
1463 was_selected = FALSE;
1468 case MOUSE_BUTTON_MIDDLE:
1470 vficon_select_util(vf, id, !(id->selected & SELECTION_SELECTED));
1477 if (!was_selected && (id->selected & SELECTION_SELECTED))
1479 vficon_send_layout_select(vf, id);
1485 static gint vficon_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
1487 ViewFile *vf = data;
1494 *-------------------------------------------------------------------
1496 *-------------------------------------------------------------------
1499 static gboolean vficon_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GtkTreeIter *iter, gpointer data)
1503 gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1);
1509 static void vficon_clear_store(ViewFile *vf)
1511 GtkTreeModel *store;
1513 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1514 gtk_tree_model_foreach(store, vficon_destroy_node_cb, NULL);
1516 gtk_list_store_clear(GTK_LIST_STORE(store));
1519 static void vficon_set_thumb(ViewFile *vf, FileData *fd, GdkPixbuf *pb)
1521 GtkTreeModel *store;
1525 if (!vficon_find_iter(vf, vficon_icon_data(vf, fd), &iter, NULL)) return;
1527 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1529 if (pb) g_object_ref(pb);
1530 if (fd->pixbuf) g_object_unref(fd->pixbuf);
1533 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
1534 gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1);
1537 static GList *vficon_add_row(ViewFile *vf, GtkTreeIter *iter)
1539 GtkListStore *store;
1543 for (i = 0; i < VFICON_INFO(vf, columns); i++) list = g_list_prepend(list, NULL);
1545 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1546 gtk_list_store_append(store, iter);
1547 gtk_list_store_set(store, iter, FILE_COLUMN_POINTER, list, -1);
1552 static void vficon_populate(ViewFile *vf, gint resize, gint keep_position)
1554 GtkTreeModel *store;
1558 IconData *visible_id = NULL;
1560 vficon_verify_selections(vf);
1562 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1564 if (keep_position && GTK_WIDGET_REALIZED(vf->listview) &&
1565 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1570 gtk_tree_model_get_iter(store, &iter, tpath);
1571 gtk_tree_path_free(tpath);
1573 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
1574 if (list) visible_id = list->data;
1577 vficon_clear_store(vf);
1584 thumb_width = vficon_get_icon_width(vf);
1586 for (i = 0; i < VFICON_MAX_COLUMNS; i++)
1588 GtkTreeViewColumn *column;
1589 GtkCellRenderer *cell;
1592 column = gtk_tree_view_get_column(GTK_TREE_VIEW(vf->listview), i);
1593 gtk_tree_view_column_set_visible(column, (i < VFICON_INFO(vf, columns)));
1594 gtk_tree_view_column_set_fixed_width(column, thumb_width + (THUMB_BORDER_PADDING * 6));
1596 list = gtk_tree_view_column_get_cell_renderers(column);
1597 cell = (list) ? list->data : NULL;
1600 if (cell && GQV_IS_CELL_RENDERER_ICON(cell))
1602 g_object_set(G_OBJECT(cell), "fixed_width", thumb_width,
1603 "fixed_height", options->thumbnails.max_height,
1604 "show_text", VFICON_INFO(vf, show_text), NULL);
1607 if (GTK_WIDGET_REALIZED(vf->listview)) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
1619 list = vficon_add_row(vf, &iter);
1620 while (work && list)
1627 list->data = work->data;
1634 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1639 gtk_tree_model_get_iter(store, &iter, tpath);
1640 gtk_tree_path_free(tpath);
1642 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
1643 if (g_list_find(list, visible_id) == NULL &&
1644 vficon_find_iter(vf, visible_id, &iter, NULL))
1646 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
1650 VFICON_INFO(vf, rows) = row + 1;
1653 vficon_thumb_update(vf);
1656 static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gint force)
1661 thumb_width = vficon_get_icon_width(vf);
1663 new_cols = w / (thumb_width + (THUMB_BORDER_PADDING * 6));
1664 if (new_cols < 1) new_cols = 1;
1666 if (!force && new_cols == VFICON_INFO(vf, columns)) return;
1668 VFICON_INFO(vf, columns) = new_cols;
1670 vficon_populate(vf, TRUE, TRUE);
1672 DEBUG_1("col tab pop cols=%d rows=%d", VFICON_INFO(vf, columns), VFICON_INFO(vf, rows));
1675 static void vficon_sync(ViewFile *vf)
1677 GtkTreeModel *store;
1682 if (VFICON_INFO(vf, rows) == 0) return;
1684 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1695 if (gtk_tree_model_iter_nth_child(store, &iter, NULL, r))
1697 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
1698 gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1);
1702 list = vficon_add_row(vf, &iter);
1728 while (gtk_tree_model_iter_nth_child(store, &iter, NULL, r))
1732 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
1733 gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
1737 VFICON_INFO(vf, rows) = r;
1739 vficon_update_focus(vf);
1742 static gint vficon_sync_idle_cb(gpointer data)
1744 ViewFile *vf = data;
1746 if (VFICON_INFO(vf, sync_idle_id) == -1) return FALSE;
1747 VFICON_INFO(vf, sync_idle_id) = -1;
1753 static void vficon_sync_idle(ViewFile *vf)
1755 if (VFICON_INFO(vf, sync_idle_id) == -1)
1757 /* high priority, the view needs to be resynced before a redraw
1758 * may contain invalid pointers at this time
1760 VFICON_INFO(vf, sync_idle_id) = g_idle_add_full(G_PRIORITY_HIGH, vficon_sync_idle_cb, vf, NULL);
1764 static void vficon_sized_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
1766 ViewFile *vf = data;
1768 vficon_populate_at_new_size(vf, allocation->width, allocation->height, FALSE);
1772 *-----------------------------------------------------------------------------
1774 *-----------------------------------------------------------------------------
1777 void vficon_sort_set(ViewFile *vf, SortType type, gint ascend)
1779 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
1781 vf->sort_method = type;
1782 vf->sort_ascend = ascend;
1784 if (!vf->list) return;
1786 vf->list = iconlist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1791 *-----------------------------------------------------------------------------
1793 *-----------------------------------------------------------------------------
1796 static gint vficon_thumb_next(ViewFile *vf);
1798 static void vficon_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
1800 if (vf->func_thumb_status)
1802 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1806 static void vficon_thumb_cleanup(ViewFile *vf)
1808 vficon_thumb_status(vf, 0.0, NULL);
1810 vf->thumbs_count = 0;
1811 vf->thumbs_running = FALSE;
1813 thumb_loader_free(vf->thumbs_loader);
1814 vf->thumbs_loader = NULL;
1816 vf->thumbs_filedata = NULL;
1819 static void vficon_thumb_stop(ViewFile *vf)
1821 if (vf->thumbs_running) vficon_thumb_cleanup(vf);
1824 static void vficon_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1830 pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
1831 vficon_set_thumb(vf, fd, pixbuf);
1832 g_object_unref(pixbuf);
1834 vficon_thumb_status(vf, (gdouble)(vf->thumbs_count) / g_list_length(vf->list), _("Loading thumbs..."));
1837 static void vficon_thumb_error_cb(ThumbLoader *tl, gpointer data)
1839 ViewFile *vf = data;
1841 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1843 vficon_thumb_do(vf, tl, vf->thumbs_filedata);
1846 while (vficon_thumb_next(vf));
1849 static void vficon_thumb_done_cb(ThumbLoader *tl, gpointer data)
1851 ViewFile *vf = data;
1853 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1855 vficon_thumb_do(vf, tl, vf->thumbs_filedata);
1858 while (vficon_thumb_next(vf));
1861 static gint vficon_thumb_next(ViewFile *vf)
1864 FileData *fd = NULL;
1866 if (!GTK_WIDGET_REALIZED(vf->listview))
1868 vficon_thumb_status(vf, 0.0, NULL);
1872 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1874 GtkTreeModel *store;
1878 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1879 gtk_tree_model_get_iter(store, &iter, tpath);
1880 gtk_tree_path_free(tpath);
1882 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1886 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
1890 IconData *id = list->data;
1891 if (id && !id->fd->pixbuf) fd = id->fd;
1895 valid = gtk_tree_model_iter_next(store, &iter);
1899 /* then find first undone */
1903 GList *work = vf->list;
1906 IconData *id = work->data;
1907 FileData *fd_p = id->fd;
1910 if (!fd_p->pixbuf) fd = fd_p;
1917 vficon_thumb_cleanup(vf);
1923 vf->thumbs_filedata = fd;
1925 thumb_loader_free(vf->thumbs_loader);
1927 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1928 thumb_loader_set_callbacks(vf->thumbs_loader,
1929 vficon_thumb_done_cb,
1930 vficon_thumb_error_cb,
1934 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1936 /* set icon to unknown, continue */
1937 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1938 vficon_thumb_do(vf, vf->thumbs_loader, fd);
1946 static void vficon_thumb_update(ViewFile *vf)
1948 vficon_thumb_stop(vf);
1950 vficon_thumb_status(vf, 0.0, _("Loading thumbs..."));
1951 vf->thumbs_running = TRUE;
1953 while (vficon_thumb_next(vf));
1957 *-----------------------------------------------------------------------------
1959 *-----------------------------------------------------------------------------
1962 FileData *vficon_index_get_data(ViewFile *vf, gint row)
1966 id = g_list_nth_data(vf->list, row);
1967 return id ? id->fd : NULL;
1970 gint vficon_index_by_path(ViewFile *vf, const gchar *path)
1975 if (!path) return -1;
1980 IconData *id = work->data;
1981 FileData *fd = id->fd;
1982 if (strcmp(path, fd->path) == 0) return p;
1990 gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd)
1995 if (!in_fd) return -1;
2000 IconData *id = work->data;
2001 FileData *fd = id->fd;
2002 if (fd == in_fd) return p;
2010 static gint vficon_index_by_id(ViewFile *vf, IconData *in_id)
2015 if (!in_id) return -1;
2020 IconData *id = work->data;
2021 if (id == in_id) return p;
2029 gint vficon_count(ViewFile *vf, gint64 *bytes)
2039 IconData *id = work->data;
2040 FileData *fd = id->fd;
2049 return g_list_length(vf->list);
2052 GList *vficon_get_list(ViewFile *vf)
2060 IconData *id = work->data;
2061 FileData *fd = id->fd;
2064 list = g_list_prepend(list, file_data_ref(fd));
2067 return g_list_reverse(list);
2071 *-----------------------------------------------------------------------------
2073 *-----------------------------------------------------------------------------
2076 static gint vficon_refresh_real(ViewFile *vf, gint keep_position)
2083 focus_id = VFICON_INFO(vf, focus_id);
2085 old_list = vf->list;
2090 ret = iconlist_read(vf->path, &vf->list);
2093 /* check for same files from old_list */
2097 IconData *id = work->data;
2098 FileData *fd = id->fd;
2099 GList *needle = vf->list;
2103 IconData *idn = needle->data;
2104 FileData *fdn = idn->fd;
2108 /* swap, to retain old thumb, selection */
2115 needle = needle->next;
2122 vf->list = iconlist_sort(vf->list, vf->sort_method, vf->sort_ascend);
2127 IconData *id = work->data;
2130 if (id == VFICON_INFO(vf, prev_selection)) VFICON_INFO(vf, prev_selection) = NULL;
2131 if (id == VFICON_INFO(vf, click_id)) VFICON_INFO(vf, click_id) = NULL;
2134 vficon_populate(vf, TRUE, keep_position);
2136 /* attempt to keep focus on same icon when refreshing */
2137 if (focus_id && g_list_find(vf->list, focus_id))
2139 vficon_set_focus(vf, focus_id);
2142 iconlist_free(old_list);
2147 gint vficon_refresh(ViewFile *vf)
2149 return vficon_refresh_real(vf, TRUE);
2153 *-----------------------------------------------------------------------------
2155 *-----------------------------------------------------------------------------
2158 typedef struct _ColumnData ColumnData;
2165 static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
2166 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
2168 ColumnData *cd = data;
2178 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_POINTER, &list, -1);
2180 id = g_list_nth_data(list, cd->number);
2182 if (id) g_assert(id->fd->magick == 0x12345678);
2184 style = gtk_widget_get_style(vf->listview);
2185 if (id && id->selected & SELECTION_SELECTED)
2187 memcpy(&color_fg, &style->text[GTK_STATE_SELECTED], sizeof(color_fg));
2188 memcpy(&color_bg, &style->base[GTK_STATE_SELECTED], sizeof(color_bg));
2192 memcpy(&color_fg, &style->text[GTK_STATE_NORMAL], sizeof(color_fg));
2193 memcpy(&color_bg, &style->base[GTK_STATE_NORMAL], sizeof(color_bg));
2196 if (id && id->selected & SELECTION_PRELIGHT)
2199 shift_color(&color_fg, -1, 0);
2201 shift_color(&color_bg, -1, 0);
2204 if (GQV_IS_CELL_RENDERER_ICON(cell))
2208 g_object_set(cell, "pixbuf", id->fd->pixbuf,
2209 "text", id->fd->name,
2210 "cell-background-gdk", &color_bg,
2211 "cell-background-set", TRUE,
2212 "foreground-gdk", &color_fg,
2213 "foreground-set", TRUE,
2214 "has-focus", (VFICON_INFO(vf, focus_id) == id), NULL);
2218 g_object_set(cell, "pixbuf", NULL,
2220 "cell-background-set", FALSE,
2221 "foreground-set", FALSE,
2222 "has-focus", FALSE, NULL);
2227 static void vficon_append_column(ViewFile *vf, gint n)
2230 GtkTreeViewColumn *column;
2231 GtkCellRenderer *renderer;
2233 column = gtk_tree_view_column_new();
2234 gtk_tree_view_column_set_min_width(column, 0);
2236 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2237 gtk_tree_view_column_set_alignment(column, 0.5);
2239 renderer = gqv_cell_renderer_icon_new();
2240 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2241 g_object_set(G_OBJECT(renderer), "xpad", THUMB_BORDER_PADDING * 2,
2242 "ypad", THUMB_BORDER_PADDING,
2243 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
2245 g_object_set_data(G_OBJECT(column), "column_number", GINT_TO_POINTER(n));
2247 cd = g_new0(ColumnData, 1);
2250 gtk_tree_view_column_set_cell_data_func(column, renderer, vficon_cell_data_cb, cd, g_free);
2252 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
2256 *-----------------------------------------------------------------------------
2258 *-----------------------------------------------------------------------------
2261 gint vficon_set_path(ViewFile *vf, const gchar *path)
2265 if (!path) return FALSE;
2266 if (vf->path && strcmp(path, vf->path) == 0) return TRUE;
2269 vf->path = g_strdup(path);
2271 g_list_free(VFICON_INFO(vf, selection));
2272 VFICON_INFO(vf, selection) = NULL;
2274 iconlist_free(vf->list);
2277 /* NOTE: populate will clear the store for us */
2278 ret = vficon_refresh_real(vf, FALSE);
2280 VFICON_INFO(vf, focus_id) = NULL;
2281 vficon_move_focus(vf, 0, 0, FALSE);
2286 void vficon_destroy_cb(GtkWidget *widget, gpointer data)
2288 ViewFile *vf = data;
2290 if (VFICON_INFO(vf, sync_idle_id) != -1) g_source_remove(VFICON_INFO(vf, sync_idle_id));
2294 vficon_thumb_cleanup(vf);
2296 iconlist_free(vf->list);
2297 g_list_free(VFICON_INFO(vf, selection));
2300 ViewFile *vficon_new(ViewFile *vf, const gchar *path)
2302 GtkListStore *store;
2303 GtkTreeSelection *selection;
2306 vf->info = g_new0(ViewFileInfoIcon, 1);
2308 VFICON_INFO(vf, selection) = NULL;
2309 VFICON_INFO(vf, prev_selection) = NULL;
2311 VFICON_INFO(vf, tip_window) = NULL;
2312 VFICON_INFO(vf, tip_delay_id) = -1;
2314 VFICON_INFO(vf, focus_row) = 0;
2315 VFICON_INFO(vf, focus_column) = 0;
2316 VFICON_INFO(vf, focus_id) = NULL;
2318 VFICON_INFO(vf, show_text) = options->show_icon_names;
2320 VFICON_INFO(vf, sync_idle_id) = -1;
2322 store = gtk_list_store_new(1, G_TYPE_POINTER);
2323 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
2324 g_object_unref(store);
2326 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
2327 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_NONE);
2329 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
2330 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
2332 for (i = 0; i < VFICON_MAX_COLUMNS; i++)
2334 vficon_append_column(vf, i);
2337 /* zero width column to hide tree view focus, we draw it ourselves */
2338 vficon_append_column(vf, i);
2339 /* end column to fill white space */
2340 vficon_append_column(vf, i);
2342 g_signal_connect(G_OBJECT(vf->listview), "size_allocate",
2343 G_CALLBACK(vficon_sized_cb), vf);
2345 gtk_widget_set_events(vf->listview, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK |
2346 GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK);
2348 g_signal_connect(G_OBJECT(vf->listview),"motion_notify_event",
2349 G_CALLBACK(vficon_motion_cb), vf);
2350 g_signal_connect(G_OBJECT(vf->listview), "leave_notify_event",
2351 G_CALLBACK(vficon_leave_cb), vf);
2353 /* force VFICON_INFO(vf, columns) to be at least 1 (sane) - this will be corrected in the size_cb */
2354 vficon_populate_at_new_size(vf, 1, 1, FALSE);
2360 *-----------------------------------------------------------------------------
2361 * maintenance (for rename, move, remove)
2362 *-----------------------------------------------------------------------------
2365 static gint vficon_maint_find_closest(ViewFile *vf, gint row, gint count, GList *ignore_list)
2376 FileData *fd = work->data;
2377 gint f = vficon_index_by_fd(vf, fd);
2378 g_assert(fd->magick == 0x12345678);
2380 if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f));
2391 gpointer p = work->data;
2394 if (row == GPOINTER_TO_INT(p))
2399 if (rev == GPOINTER_TO_INT(p))
2404 if (!c) list = g_list_remove(list, p);
2414 if (row > count - 1)
2427 gint vficon_maint_renamed(ViewFile *vf, FileData *fd)
2433 IconData *id = vficon_icon_data(vf, fd);
2435 if (!id) return FALSE;
2437 row = vficon_index_by_id(vf, id);
2438 if (row < 0) return FALSE;
2440 source_base = remove_level_from_path(fd->change->source);
2441 dest_base = remove_level_from_path(fd->change->dest);
2443 if (strcmp(source_base, dest_base) == 0)
2445 vf->list = g_list_remove(vf->list, id);
2446 vf->list = iconlist_insert_sort(vf->list, id, vf->sort_method, vf->sort_ascend);
2448 vficon_sync_idle(vf);
2453 ret = vficon_maint_removed(vf, fd, NULL);
2456 g_free(source_base);
2462 gint vficon_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
2466 GtkTreeModel *store;
2468 IconData *id = vficon_icon_data(vf, fd);
2470 if (!id) return FALSE;
2472 row = g_list_index(vf->list, id);
2473 if (row < 0) return FALSE;
2475 if ((id->selected & SELECTION_SELECTED) &&
2476 layout_image_get_collection(vf->layout, NULL) == NULL)
2478 vficon_unselect(vf, id);
2480 if (!VFICON_INFO(vf, selection))
2484 n = vf_count(vf, NULL);
2487 new_row = vficon_maint_find_closest(vf, row, n, ignore_list);
2488 DEBUG_1("row = %d, closest is %d", row, new_row);
2502 else if (ignore_list)
2506 work = VFICON_INFO(vf, selection);
2509 IconData *ignore_id;
2510 FileData *ignore_fd;
2514 ignore_id = work->data;
2515 ignore_fd = ignore_id->fd;
2516 g_assert(ignore_fd->magick == 0x12345678);
2520 while (tmp && !match)
2522 FileData *ignore_list_fd = tmp->data;
2523 g_assert(ignore_list_fd->magick == 0x12345678);
2526 if (ignore_list_fd == ignore_fd)
2534 new_row = g_list_index(vf->list, ignore_id);
2541 /* selection all ignored, use closest */
2542 new_row = vficon_maint_find_closest(vf, row, vf_count(vf, NULL), ignore_list);
2547 new_row = g_list_index(vf->list, VFICON_INFO(vf, selection)->data);
2552 IconData *idn = g_list_nth_data(vf->list, new_row);
2554 vficon_select(vf, idn);
2555 vficon_send_layout_select(vf, idn);
2559 /* Thumb loader check */
2560 if (fd == vf->thumbs_filedata) vf->thumbs_filedata = NULL;
2561 if (vf->thumbs_count > 0) vf->thumbs_count--;
2563 if (VFICON_INFO(vf, prev_selection) == id) VFICON_INFO(vf, prev_selection) = NULL;
2564 if (VFICON_INFO(vf, click_id) == id) VFICON_INFO(vf, click_id) = NULL;
2566 /* remove pointer to this fd from grid */
2567 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
2569 gtk_tree_model_iter_nth_child(store, &iter, NULL, id->row))
2573 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
2574 list = g_list_find(list, id);
2575 if (list) list->data = NULL;
2578 vf->list = g_list_remove(vf->list, id);
2579 file_data_unref(fd);
2582 vficon_sync_idle(vf);
2588 gint vficon_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
2593 if (!fd->change->source || !vf->path) return FALSE;
2595 buf = remove_level_from_path(fd->change->source);
2597 if (strcmp(buf, vf->path) == 0)
2599 ret = vficon_maint_removed(vf, fd, ignore_list);