Mercurial > geeqie
annotate src/collect-table.c @ 274:2710d14f6a28
Fix the "continuous display" of tooltips in the collection view
(before the tooltip delay occured once, then changing icon to icon never hide the
tooltip again, now the tip is displayed shortly after the cursor moved on the icon,
but disappears when moving cursor to another icon).
Display the full path to the file when Show filename text is on (before nothing
was displayed).
When Show filename text is off, behavior is unchanged, the (short) filename is
displayed.
author | zas_ |
---|---|
date | Tue, 08 Apr 2008 21:33:29 +0000 |
parents | f6e307c7bad6 |
children | 9995c5fb202a |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
9 | 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 | |
13 #include "gqview.h" | |
14 #include "collect-table.h" | |
15 | |
16 #include "cellrenderericon.h" | |
17 #include "collect-dlg.h" | |
18 #include "collect-io.h" | |
19 #include "dnd.h" | |
20 #include "dupe.h" | |
21 #include "editors.h" | |
22 #include "filelist.h" | |
23 #include "img-view.h" | |
24 #include "info.h" | |
25 #include "layout.h" | |
26 #include "layout_image.h" | |
27 #include "menu.h" | |
28 #include "print.h" | |
29 #include "utilops.h" | |
30 #include "ui_bookmark.h" | |
31 #include "ui_fileops.h" | |
32 #include "ui_menu.h" | |
33 #include "ui_tree_edit.h" | |
34 | |
35 #include "icons/marker.xpm" | |
36 #define MARKER_WIDTH 26 | |
37 #define MARKER_HEIGHT 32 | |
38 | |
39 #include <gdk/gdkkeysyms.h> /* for keyboard values */ | |
40 | |
41 /* between these, the icon width is increased by thumb_max_width / 2 */ | |
42 #define THUMB_MIN_ICON_WIDTH 128 | |
43 #define THUMB_MAX_ICON_WIDTH 150 | |
44 | |
45 #define COLLECT_TABLE_MAX_COLUMNS 32 | |
46 #define THUMB_BORDER_PADDING 2 | |
47 | |
48 #define COLLECT_TABLE_TIP_DELAY 500 | |
274
2710d14f6a28
Fix the "continuous display" of tooltips in the collection view
zas_
parents:
196
diff
changeset
|
49 #define COLLECT_TABLE_TIP_DELAY_PATH (COLLECT_TABLE_TIP_DELAY * 1.7) |
9 | 50 |
51 | |
52 enum { | |
53 CTABLE_COLUMN_POINTER = 0, | |
54 CTABLE_COLUMN_COUNT | |
55 }; | |
56 | |
57 typedef enum { | |
58 SELECTION_NONE = 0, | |
59 SELECTION_SELECTED = 1 << 0, | |
60 SELECTION_PRELIGHT = 1 << 1, | |
61 SELECTION_FOCUS = 1 << 2 | |
62 } SelectionType; | |
63 | |
64 | |
65 #define INFO_SELECTED(x) (x->flag_mask & SELECTION_SELECTED) | |
66 | |
67 | |
68 static void collection_table_populate_at_new_size(CollectTable *ct, gint w, gint h, gint force); | |
69 | |
70 | |
71 /* | |
72 *------------------------------------------------------------------- | |
73 * more misc | |
74 *------------------------------------------------------------------- | |
75 */ | |
76 | |
77 static gint collection_table_find_position(CollectTable *ct, CollectInfo *info, gint *row, gint *col) | |
78 { | |
79 gint n; | |
80 | |
81 n = g_list_index(ct->cd->list, info); | |
82 | |
83 if (n < 0) return FALSE; | |
84 | |
85 *row = n / ct->columns; | |
86 *col = n - (*row * ct->columns); | |
87 | |
88 return TRUE; | |
89 } | |
90 | |
91 static gint collection_table_find_iter(CollectTable *ct, CollectInfo *info, GtkTreeIter *iter, gint *column) | |
92 { | |
93 GtkTreeModel *store; | |
94 gint row, col; | |
95 | |
96 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
97 if (!collection_table_find_position(ct, info, &row, &col)) return FALSE; | |
98 if (!gtk_tree_model_iter_nth_child(store, iter, NULL, row)) return FALSE; | |
99 if (column) *column = col; | |
100 | |
101 return TRUE; | |
102 } | |
103 | |
104 static CollectInfo *collection_table_find_data(CollectTable *ct, gint row, gint col, GtkTreeIter *iter) | |
105 { | |
106 GtkTreeModel *store; | |
107 GtkTreeIter p; | |
108 | |
109 if (row < 0 || col < 0) return NULL; | |
110 | |
111 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
112 if (gtk_tree_model_iter_nth_child(store, &p, NULL, row)) | |
113 { | |
114 GList *list; | |
115 | |
116 gtk_tree_model_get(store, &p, CTABLE_COLUMN_POINTER, &list, -1); | |
117 if (!list) return NULL; | |
118 | |
119 if (iter) *iter = p; | |
120 | |
121 return g_list_nth_data(list, col); | |
122 } | |
123 | |
124 return NULL; | |
125 } | |
126 | |
127 static CollectInfo *collection_table_find_data_by_coord(CollectTable *ct, gint x, gint y, GtkTreeIter *iter) | |
128 { | |
129 GtkTreePath *tpath; | |
130 GtkTreeViewColumn *column; | |
131 | |
132 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(ct->listview), x, y, | |
133 &tpath, &column, NULL, NULL)) | |
134 { | |
135 GtkTreeModel *store; | |
136 GtkTreeIter row; | |
137 GList *list; | |
138 gint n; | |
139 | |
140 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
141 gtk_tree_model_get_iter(store, &row, tpath); | |
142 gtk_tree_path_free(tpath); | |
143 | |
144 gtk_tree_model_get(store, &row, CTABLE_COLUMN_POINTER, &list, -1); | |
145 | |
146 n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_number")); | |
147 if (list) | |
148 { | |
149 if (iter) *iter = row; | |
150 return g_list_nth_data(list, n); | |
151 } | |
152 } | |
153 | |
154 return NULL; | |
155 } | |
156 | |
157 static void collection_table_update_status(CollectTable *ct) | |
158 { | |
159 if (ct->status_label) | |
160 { | |
161 gchar *buf; | |
162 | |
163 if (!ct->cd->list) | |
164 { | |
165 buf = g_strdup(_("Empty")); | |
166 } | |
167 else if (ct->selection) | |
168 { | |
169 buf = g_strdup_printf(_("%d images (%d)"), g_list_length(ct->cd->list), g_list_length(ct->selection)); | |
170 } | |
171 else | |
172 { | |
173 buf = g_strdup_printf(_("%d images"), g_list_length(ct->cd->list)); | |
174 } | |
175 | |
176 gtk_label_set_text(GTK_LABEL(ct->status_label), buf); | |
177 g_free(buf); | |
178 } | |
179 } | |
180 | |
181 static void collection_table_update_extras(CollectTable *ct, gint loading, gdouble value) | |
182 { | |
183 if (ct->extra_label) | |
184 { | |
185 gchar *text; | |
186 if (loading) | |
187 text = _("Loading thumbs..."); | |
188 else | |
189 text = " "; | |
190 | |
191 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ct->extra_label), value); | |
192 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ct->extra_label), text); | |
193 } | |
194 } | |
195 | |
196 static void collection_table_toggle_filenames(CollectTable *ct) | |
197 { | |
198 ct->show_text = !ct->show_text; | |
199 show_icon_names = ct->show_text; | |
200 | |
201 collection_table_populate_at_new_size(ct, ct->listview->allocation.width, ct->listview->allocation.height, TRUE); | |
202 } | |
203 | |
204 static gint collection_table_get_icon_width(CollectTable *ct) | |
205 { | |
206 gint width; | |
207 | |
208 if (!ct->show_text) return thumb_max_width; | |
209 | |
210 width = thumb_max_width + thumb_max_width / 2; | |
211 if (width < THUMB_MIN_ICON_WIDTH) width = THUMB_MIN_ICON_WIDTH; | |
212 if (width > THUMB_MAX_ICON_WIDTH) width = thumb_max_width; | |
213 | |
214 return width; | |
215 } | |
216 | |
217 /* | |
218 *------------------------------------------------------------------- | |
219 * cell updates | |
220 *------------------------------------------------------------------- | |
221 */ | |
222 | |
223 static void collection_table_selection_set(CollectTable *ct, CollectInfo *info, SelectionType value, GtkTreeIter *iter) | |
224 { | |
225 GtkTreeModel *store; | |
226 GList *list; | |
227 | |
228 if (!info) return; | |
229 | |
230 if (info->flag_mask == value) return; | |
231 info->flag_mask = value; | |
232 | |
233 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
234 if (iter) | |
235 { | |
236 gtk_tree_model_get(store, iter, CTABLE_COLUMN_POINTER, &list, -1); | |
237 if (list) gtk_list_store_set(GTK_LIST_STORE(store), iter, CTABLE_COLUMN_POINTER, list, -1); | |
238 } | |
239 else | |
240 { | |
241 GtkTreeIter row; | |
242 | |
243 if (collection_table_find_iter(ct, info, &row, NULL)) | |
244 { | |
245 gtk_tree_model_get(store, &row, CTABLE_COLUMN_POINTER, &list, -1); | |
246 if (list) gtk_list_store_set(GTK_LIST_STORE(store), &row, CTABLE_COLUMN_POINTER, list, -1); | |
247 } | |
248 } | |
249 } | |
250 | |
251 static void collection_table_selection_add(CollectTable *ct, CollectInfo *info, SelectionType mask, GtkTreeIter *iter) | |
252 { | |
253 if (!info) return; | |
254 | |
255 collection_table_selection_set(ct, info, info->flag_mask | mask, iter); | |
256 } | |
257 | |
258 static void collection_table_selection_remove(CollectTable *ct, CollectInfo *info, SelectionType mask, GtkTreeIter *iter) | |
259 { | |
260 if (!info) return; | |
261 | |
262 collection_table_selection_set(ct, info, info->flag_mask & ~mask, iter); | |
263 } | |
264 /* | |
265 *------------------------------------------------------------------- | |
266 * selections | |
267 *------------------------------------------------------------------- | |
268 */ | |
269 | |
270 static void collection_table_verify_selections(CollectTable *ct) | |
271 { | |
272 GList *work; | |
273 | |
274 work = ct->selection; | |
275 while (work) | |
276 { | |
277 CollectInfo *info = work->data; | |
278 work = work->next; | |
279 if (!g_list_find(ct->cd->list, info)) | |
280 { | |
281 ct->selection = g_list_remove(ct->selection, info); | |
282 } | |
283 } | |
284 } | |
285 | |
286 void collection_table_select_all(CollectTable *ct) | |
287 { | |
288 GList *work; | |
289 | |
290 g_list_free(ct->selection); | |
291 ct->selection = NULL; | |
292 | |
293 work = ct->cd->list; | |
294 while(work) | |
295 { | |
296 ct->selection = g_list_append(ct->selection, work->data); | |
297 collection_table_selection_add(ct, work->data, SELECTION_SELECTED, NULL); | |
298 work = work->next; | |
299 } | |
300 | |
301 collection_table_update_status(ct); | |
302 } | |
303 | |
304 void collection_table_unselect_all(CollectTable *ct) | |
305 { | |
306 GList *work; | |
307 | |
308 work = ct->selection; | |
309 while (work) | |
310 { | |
311 collection_table_selection_remove(ct, work->data, SELECTION_SELECTED, NULL); | |
312 work = work->next; | |
313 } | |
314 | |
315 g_list_free(ct->selection); | |
316 ct->selection = NULL; | |
317 | |
318 collection_table_update_status(ct); | |
319 } | |
320 | |
321 static void collection_table_select(CollectTable *ct, CollectInfo *info) | |
322 { | |
323 ct->prev_selection = info; | |
324 | |
325 if (!info || INFO_SELECTED(info)) return; | |
326 | |
327 ct->selection = g_list_append(ct->selection, info); | |
328 collection_table_selection_add(ct, info, SELECTION_SELECTED, NULL); | |
329 | |
330 collection_table_update_status(ct); | |
331 } | |
332 | |
333 static void collection_table_unselect(CollectTable *ct, CollectInfo *info) | |
334 { | |
335 ct->prev_selection = info; | |
336 | |
337 if (!info || !INFO_SELECTED(info) ) return; | |
338 | |
339 ct->selection = g_list_remove(ct->selection, info); | |
340 collection_table_selection_remove(ct, info, SELECTION_SELECTED, NULL); | |
341 | |
342 collection_table_update_status(ct); | |
343 } | |
344 | |
345 static void collection_table_select_util(CollectTable *ct, CollectInfo *info, gint select) | |
346 { | |
347 if (select) | |
348 { | |
349 collection_table_select(ct, info); | |
350 } | |
351 else | |
352 { | |
353 collection_table_unselect(ct, info); | |
354 } | |
355 } | |
356 | |
357 static void collection_table_select_region_util(CollectTable *ct, CollectInfo *start, CollectInfo *end, gint select) | |
358 { | |
359 gint row1, col1; | |
360 gint row2, col2; | |
361 gint t; | |
362 gint i, j; | |
363 | |
364 if (!collection_table_find_position(ct, start, &row1, &col1) || | |
365 !collection_table_find_position(ct, end, &row2, &col2) ) return; | |
366 | |
367 ct->prev_selection = end; | |
368 | |
369 if (!collection_rectangular_selection) | |
370 { | |
371 GList *work; | |
372 CollectInfo *info; | |
373 | |
374 if (g_list_index(ct->cd->list, start) > g_list_index(ct->cd->list, end)) | |
375 { | |
376 info = start; | |
377 start = end; | |
378 end = info; | |
379 } | |
380 | |
381 work = g_list_find(ct->cd->list, start); | |
382 while (work) | |
383 { | |
384 info = work->data; | |
385 collection_table_select_util(ct, info, select); | |
386 | |
387 if (work->data != end) | |
388 work = work->next; | |
389 else | |
390 work = NULL; | |
391 } | |
392 return; | |
393 } | |
394 | |
395 if (row2 < row1) | |
396 { | |
397 t = row1; | |
398 row1 = row2; | |
399 row2 = t; | |
400 } | |
401 if (col2 < col1) | |
402 { | |
403 t = col1; | |
404 col1 = col2; | |
405 col2 = t; | |
406 } | |
407 | |
408 if (debug) printf("table: %d x %d to %d x %d\n", row1, col1, row2, col2); | |
409 | |
410 for (i = row1; i <= row2; i++) | |
411 { | |
412 for (j = col1; j <= col2; j++) | |
413 { | |
414 CollectInfo *info = collection_table_find_data(ct, i, j, NULL); | |
415 if (info) collection_table_select_util(ct, info, select); | |
416 } | |
417 } | |
418 } | |
419 | |
420 GList *collection_table_selection_get_list(CollectTable *ct) | |
421 { | |
138 | 422 return collection_list_to_filelist(ct->selection); |
9 | 423 } |
424 | |
425 static GList *collection_table_get_list(CollectTable *ct) | |
426 { | |
138 | 427 return collection_list_to_filelist(ct->cd->list); |
9 | 428 } |
429 | |
430 /* | |
431 *------------------------------------------------------------------- | |
432 * tooltip type window | |
433 *------------------------------------------------------------------- | |
434 */ | |
435 | |
436 static void tip_show(CollectTable *ct) | |
437 { | |
438 GtkWidget *label; | |
439 gint x, y; | |
440 | |
441 if (ct->tip_window) return; | |
442 | |
443 gdk_window_get_pointer(ct->listview->window, &x, &y, NULL); | |
444 | |
445 ct->tip_info = collection_table_find_data_by_coord(ct, x, y, NULL); | |
446 if (!ct->tip_info) return; | |
447 | |
448 ct->tip_window = gtk_window_new(GTK_WINDOW_POPUP); | |
449 gtk_window_set_resizable(GTK_WINDOW(ct->tip_window), FALSE); | |
450 gtk_container_set_border_width(GTK_CONTAINER(ct->tip_window), 2); | |
451 | |
274
2710d14f6a28
Fix the "continuous display" of tooltips in the collection view
zas_
parents:
196
diff
changeset
|
452 label = gtk_label_new(ct->show_text ? ct->tip_info->fd->path : ct->tip_info->fd->name); |
9 | 453 |
454 g_object_set_data(G_OBJECT(ct->tip_window), "tip_label", label); | |
455 gtk_container_add(GTK_CONTAINER(ct->tip_window), label); | |
456 gtk_widget_show(label); | |
457 | |
458 gdk_window_get_pointer(NULL, &x, &y, NULL); | |
459 | |
460 if (!GTK_WIDGET_REALIZED(ct->tip_window)) gtk_widget_realize(ct->tip_window); | |
461 gtk_window_move(GTK_WINDOW(ct->tip_window), x + 16, y + 16); | |
462 gtk_widget_show(ct->tip_window); | |
463 } | |
464 | |
465 static void tip_hide(CollectTable *ct) | |
466 { | |
467 if (ct->tip_window) gtk_widget_destroy(ct->tip_window); | |
468 ct->tip_window = NULL; | |
469 } | |
470 | |
471 static gint tip_schedule_cb(gpointer data) | |
472 { | |
473 CollectTable *ct = data; | |
474 | |
475 if (ct->tip_delay_id == -1) return FALSE; | |
476 | |
477 tip_show(ct); | |
478 | |
479 ct->tip_delay_id = -1; | |
480 return FALSE; | |
481 } | |
482 | |
483 static void tip_schedule(CollectTable *ct) | |
484 { | |
485 tip_hide(ct); | |
486 | |
487 if (ct->tip_delay_id != -1) | |
488 { | |
489 g_source_remove(ct->tip_delay_id); | |
490 ct->tip_delay_id = -1; | |
491 } | |
492 | |
274
2710d14f6a28
Fix the "continuous display" of tooltips in the collection view
zas_
parents:
196
diff
changeset
|
493 ct->tip_delay_id = g_timeout_add(ct->show_text ? COLLECT_TABLE_TIP_DELAY_PATH : COLLECT_TABLE_TIP_DELAY, tip_schedule_cb, ct); |
9 | 494 } |
495 | |
496 static void tip_unschedule(CollectTable *ct) | |
497 { | |
498 tip_hide(ct); | |
499 | |
500 if (ct->tip_delay_id != -1) g_source_remove(ct->tip_delay_id); | |
501 ct->tip_delay_id = -1; | |
502 } | |
503 | |
504 static void tip_update(CollectTable *ct, CollectInfo *info) | |
505 { | |
274
2710d14f6a28
Fix the "continuous display" of tooltips in the collection view
zas_
parents:
196
diff
changeset
|
506 tip_schedule(ct); |
2710d14f6a28
Fix the "continuous display" of tooltips in the collection view
zas_
parents:
196
diff
changeset
|
507 |
9 | 508 if (ct->tip_window) |
509 { | |
510 gint x, y; | |
511 | |
512 gdk_window_get_pointer(NULL, &x, &y, NULL); | |
513 gtk_window_move(GTK_WINDOW(ct->tip_window), x + 16, y + 16); | |
514 | |
515 if (info != ct->tip_info) | |
516 { | |
517 GtkWidget *label; | |
518 | |
519 ct->tip_info = info; | |
520 | |
521 if (!ct->tip_info) | |
522 { | |
523 return; | |
524 } | |
525 | |
526 label = g_object_get_data(G_OBJECT(ct->tip_window), "tip_label"); | |
274
2710d14f6a28
Fix the "continuous display" of tooltips in the collection view
zas_
parents:
196
diff
changeset
|
527 gtk_label_set_text(GTK_LABEL(label), ct->show_text ? ct->tip_info->fd->path : ct->tip_info->fd->name); |
9 | 528 } |
529 } | |
530 } | |
531 | |
532 /* | |
533 *------------------------------------------------------------------- | |
534 * popup menus | |
535 *------------------------------------------------------------------- | |
536 */ | |
537 | |
538 static void collection_table_popup_save_as_cb(GtkWidget *widget, gpointer data) | |
539 { | |
540 CollectTable *ct = data; | |
541 | |
542 collection_dialog_save_as(NULL, ct->cd); | |
543 } | |
544 | |
545 static void collection_table_popup_save_cb(GtkWidget *widget, gpointer data) | |
546 { | |
547 CollectTable *ct = data; | |
548 | |
549 if (!ct->cd->path) | |
550 { | |
551 collection_table_popup_save_as_cb(widget, data); | |
552 return; | |
553 } | |
554 | |
555 if (!collection_save(ct->cd, ct->cd->path)) | |
556 { | |
557 printf("failed saving to collection path: %s\n", ct->cd->path); | |
558 } | |
559 } | |
560 | |
561 static GList *collection_table_popup_file_list(CollectTable *ct) | |
562 { | |
563 if (!ct->click_info) return NULL; | |
564 | |
565 if (INFO_SELECTED(ct->click_info)) | |
566 { | |
567 return collection_table_selection_get_list(ct); | |
568 } | |
569 | |
138 | 570 return g_list_append(NULL, g_strdup(ct->click_info->fd->path)); |
9 | 571 } |
572 | |
573 static void collection_table_popup_edit_cb(GtkWidget *widget, gpointer data) | |
574 { | |
575 CollectTable *ct; | |
576 gint n; | |
577 GList *list; | |
578 | |
579 ct = submenu_item_get_data(widget); | |
580 | |
581 if (!ct) return; | |
582 n = GPOINTER_TO_INT(data); | |
583 | |
584 list = collection_table_popup_file_list(ct); | |
585 if (list) | |
586 { | |
138 | 587 start_editor_from_filelist(n, list); |
588 filelist_free(list); | |
9 | 589 } |
590 } | |
591 | |
592 static void collection_table_popup_info_cb(GtkWidget *widget, gpointer data) | |
593 { | |
594 CollectTable *ct = data; | |
595 | |
596 info_window_new(NULL, collection_table_popup_file_list(ct)); | |
597 } | |
598 | |
599 static void collection_table_popup_copy_cb(GtkWidget *widget, gpointer data) | |
600 { | |
601 CollectTable *ct = data; | |
602 | |
603 file_util_copy(NULL, collection_table_popup_file_list(ct), NULL, ct->listview); | |
604 } | |
605 | |
606 static void collection_table_popup_move_cb(GtkWidget *widget, gpointer data) | |
607 { | |
608 CollectTable *ct = data; | |
609 | |
610 file_util_move(NULL, collection_table_popup_file_list(ct), NULL, ct->listview); | |
611 } | |
612 | |
613 static void collection_table_popup_rename_cb(GtkWidget *widget, gpointer data) | |
614 { | |
615 CollectTable *ct = data; | |
616 | |
617 file_util_rename(NULL, collection_table_popup_file_list(ct), ct->listview); | |
618 } | |
619 | |
620 static void collection_table_popup_delete_cb(GtkWidget *widget, gpointer data) | |
621 { | |
622 CollectTable *ct = data; | |
623 | |
624 file_util_delete(NULL, collection_table_popup_file_list(ct), ct->listview); | |
625 } | |
626 | |
627 static void collection_table_popup_sort_cb(GtkWidget *widget, gpointer data) | |
628 { | |
629 CollectTable *ct; | |
630 SortType type; | |
631 | |
632 ct = submenu_item_get_data(widget); | |
633 | |
634 if (!ct) return; | |
635 | |
636 type = (SortType)GPOINTER_TO_INT(data); | |
637 | |
638 collection_set_sort_method(ct->cd, type); | |
639 } | |
640 | |
641 static void collection_table_popup_view_new_cb(GtkWidget *widget, gpointer data) | |
642 { | |
643 CollectTable *ct = data; | |
644 | |
645 if (ct->click_info && g_list_find(ct->cd->list, ct->click_info)) | |
646 { | |
647 view_window_new_from_collection(ct->cd, ct->click_info); | |
648 } | |
649 } | |
650 | |
651 static void collection_table_popup_view_cb(GtkWidget *widget, gpointer data) | |
652 { | |
653 CollectTable *ct = data; | |
654 | |
655 if (ct->click_info && g_list_find(ct->cd->list, ct->click_info)) | |
656 { | |
657 layout_image_set_collection(NULL, ct->cd, ct->click_info); | |
658 } | |
659 } | |
660 | |
661 static void collection_table_popup_selectall_cb(GtkWidget *widget, gpointer data) | |
662 { | |
663 CollectTable *ct = data; | |
664 | |
665 collection_table_select_all(ct); | |
666 ct->prev_selection= ct->click_info; | |
667 } | |
668 | |
669 static void collection_table_popup_unselectall_cb(GtkWidget *widget, gpointer data) | |
670 { | |
671 CollectTable *ct = data; | |
672 | |
673 collection_table_unselect_all(ct); | |
674 ct->prev_selection= ct->click_info; | |
675 } | |
676 | |
677 static void collection_table_popup_remove_cb(GtkWidget *widget, gpointer data) | |
678 { | |
679 CollectTable *ct = data; | |
680 GList *list; | |
681 | |
682 if (!ct->click_info) return; | |
683 | |
684 if (INFO_SELECTED(ct->click_info)) | |
685 { | |
686 list = g_list_copy(ct->selection); | |
687 } | |
688 else | |
689 { | |
690 list = g_list_append(NULL, ct->click_info); | |
691 } | |
692 | |
693 collection_remove_by_info_list(ct->cd, list); | |
694 g_list_free(list); | |
695 } | |
696 | |
697 static void collection_table_popup_add_filelist_cb(GtkWidget *widget, gpointer data) | |
698 { | |
699 CollectTable *ct = data; | |
700 GList *list; | |
701 | |
702 list = layout_list(NULL); | |
703 | |
704 if (list) | |
705 { | |
138 | 706 collection_table_add_filelist(ct, list); |
707 filelist_free(list); | |
9 | 708 } |
709 } | |
710 | |
711 static void collection_table_popup_add_collection_cb(GtkWidget *widget, gpointer data) | |
712 { | |
713 CollectTable *ct = data; | |
714 | |
715 collection_dialog_append(NULL, ct->cd); | |
716 } | |
717 | |
718 static void collection_table_popup_find_dupes_cb(GtkWidget *widget, gpointer data) | |
719 { | |
720 CollectTable *ct = data; | |
721 DupeWindow *dw; | |
722 | |
723 dw = dupe_window_new(DUPE_MATCH_NAME); | |
724 dupe_window_add_collection(dw, ct->cd); | |
725 } | |
726 | |
727 static void collection_table_popup_print_cb(GtkWidget *widget, gpointer data) | |
728 { | |
729 CollectTable *ct = data; | |
138 | 730 FileData *fd; |
731 | |
732 fd = (ct->click_info) ? ct->click_info->fd : NULL; | |
733 | |
734 print_window_new(fd, collection_table_selection_get_list(ct), collection_table_get_list(ct), ct->listview); | |
9 | 735 } |
736 | |
737 static void collection_table_popup_show_names_cb(GtkWidget *widget, gpointer data) | |
738 { | |
739 CollectTable *ct = data; | |
740 | |
741 collection_table_toggle_filenames(ct); | |
742 } | |
743 | |
744 static void collection_table_popup_destroy_cb(GtkWidget *widget, gpointer data) | |
745 { | |
746 CollectTable *ct = data; | |
747 | |
748 collection_table_selection_remove(ct, ct->click_info, SELECTION_PRELIGHT, NULL); | |
749 ct->click_info = NULL; | |
750 ct->popup = NULL; | |
751 | |
752 path_list_free(ct->drop_list); | |
753 ct->drop_list = NULL; | |
754 ct->drop_info = NULL; | |
755 } | |
756 | |
757 static GtkWidget *collection_table_popup_menu(CollectTable *ct, gint over_icon) | |
758 { | |
759 GtkWidget *menu; | |
760 GtkWidget *item; | |
761 | |
762 menu = popup_menu_short_lived(); | |
763 | |
764 g_signal_connect(G_OBJECT(menu), "destroy", | |
765 G_CALLBACK(collection_table_popup_destroy_cb), ct); | |
766 | |
767 menu_item_add_sensitive(menu, _("_View"), over_icon, | |
768 G_CALLBACK(collection_table_popup_view_cb), ct); | |
769 menu_item_add_stock_sensitive(menu, _("View in _new window"), GTK_STOCK_NEW, over_icon, | |
770 G_CALLBACK(collection_table_popup_view_new_cb), ct); | |
771 menu_item_add_divider(menu); | |
772 menu_item_add_stock_sensitive(menu, _("Rem_ove"), GTK_STOCK_REMOVE, over_icon, | |
773 G_CALLBACK(collection_table_popup_remove_cb), ct); | |
774 | |
775 menu_item_add_stock(menu, _("Append from file list"), GTK_STOCK_ADD, | |
776 G_CALLBACK(collection_table_popup_add_filelist_cb), ct); | |
777 menu_item_add_stock(menu, _("Append from collection..."), GTK_STOCK_OPEN, | |
778 G_CALLBACK(collection_table_popup_add_collection_cb), ct); | |
779 menu_item_add_divider(menu); | |
780 menu_item_add(menu, _("Select all"), | |
781 G_CALLBACK(collection_table_popup_selectall_cb), ct); | |
782 menu_item_add(menu, _("Select none"), | |
783 G_CALLBACK(collection_table_popup_unselectall_cb), ct); | |
784 menu_item_add_divider(menu); | |
785 | |
786 submenu_add_edit(menu, &item, | |
787 G_CALLBACK(collection_table_popup_edit_cb), ct); | |
788 gtk_widget_set_sensitive(item, over_icon); | |
789 | |
790 menu_item_add_sensitive(menu, _("_Properties"), over_icon, | |
791 G_CALLBACK(collection_table_popup_info_cb), ct); | |
792 menu_item_add_divider(menu); | |
793 menu_item_add_stock_sensitive(menu, _("_Copy..."), GTK_STOCK_COPY, over_icon, | |
794 G_CALLBACK(collection_table_popup_copy_cb), ct); | |
795 menu_item_add_sensitive(menu, _("_Move..."), over_icon, | |
796 G_CALLBACK(collection_table_popup_move_cb), ct); | |
797 menu_item_add_sensitive(menu, _("_Rename..."), over_icon, | |
798 G_CALLBACK(collection_table_popup_rename_cb), ct); | |
799 menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, over_icon, | |
800 G_CALLBACK(collection_table_popup_delete_cb), ct); | |
801 menu_item_add_divider(menu); | |
802 | |
803 submenu_add_sort(menu, G_CALLBACK(collection_table_popup_sort_cb), ct, FALSE, TRUE, FALSE, 0); | |
804 menu_item_add_check(menu, _("Show filename _text"), ct->show_text, | |
805 G_CALLBACK(collection_table_popup_show_names_cb), ct); | |
806 menu_item_add_divider(menu); | |
807 menu_item_add_stock(menu, _("_Save collection"), GTK_STOCK_SAVE, | |
808 G_CALLBACK(collection_table_popup_save_cb), ct); | |
809 menu_item_add_stock(menu, _("Save collection _as..."), GTK_STOCK_SAVE_AS, | |
810 G_CALLBACK(collection_table_popup_save_as_cb), ct); | |
811 menu_item_add_divider(menu); | |
812 menu_item_add_stock(menu, _("_Find duplicates..."), GTK_STOCK_FIND, | |
813 G_CALLBACK(collection_table_popup_find_dupes_cb), ct); | |
814 menu_item_add_stock_sensitive(menu, _("Print..."), GTK_STOCK_PRINT, over_icon, | |
815 G_CALLBACK(collection_table_popup_print_cb), ct); | |
816 | |
817 return menu; | |
818 } | |
819 /* | |
820 *------------------------------------------------------------------- | |
821 * keyboard callbacks | |
822 *------------------------------------------------------------------- | |
823 */ | |
824 | |
825 static void collection_table_set_focus(CollectTable *ct, CollectInfo *info) | |
826 { | |
827 GtkTreeIter iter; | |
828 gint row, col; | |
829 | |
830 if (g_list_find(ct->cd->list, ct->focus_info)) | |
831 { | |
832 if (info == ct->focus_info) | |
833 { | |
834 /* ensure focus row col are correct */ | |
835 collection_table_find_position(ct, ct->focus_info, | |
836 &ct->focus_row, &ct->focus_column); | |
837 return; | |
838 } | |
839 collection_table_selection_remove(ct, ct->focus_info, SELECTION_FOCUS, NULL); | |
840 } | |
841 | |
842 if (!collection_table_find_position(ct, info, &row, &col)) | |
843 { | |
844 ct->focus_info = NULL; | |
845 ct->focus_row = -1; | |
846 ct->focus_column = -1; | |
847 return; | |
848 } | |
849 | |
850 ct->focus_info = info; | |
851 ct->focus_row = row; | |
852 ct->focus_column = col; | |
853 collection_table_selection_add(ct, ct->focus_info, SELECTION_FOCUS, NULL); | |
854 | |
855 if (collection_table_find_iter(ct, ct->focus_info, &iter, NULL)) | |
856 { | |
857 GtkTreePath *tpath; | |
858 GtkTreeViewColumn *column; | |
859 GtkTreeModel *store; | |
860 | |
861 tree_view_row_make_visible(GTK_TREE_VIEW(ct->listview), &iter, FALSE); | |
862 | |
863 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
864 tpath = gtk_tree_model_get_path(store, &iter); | |
865 /* focus is set to an extra column with 0 width to hide focus, we draw it ourself */ | |
866 column = gtk_tree_view_get_column(GTK_TREE_VIEW(ct->listview), COLLECT_TABLE_MAX_COLUMNS); | |
867 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ct->listview), tpath, column, FALSE); | |
868 gtk_tree_path_free(tpath); | |
869 } | |
870 } | |
871 | |
872 static void collection_table_move_focus(CollectTable *ct, gint row, gint col, gint relative) | |
873 { | |
874 gint new_row; | |
875 gint new_col; | |
876 | |
877 if (relative) | |
878 { | |
879 new_row = ct->focus_row; | |
880 new_col = ct->focus_column; | |
881 | |
882 new_row += row; | |
883 if (new_row < 0) new_row = 0; | |
884 if (new_row >= ct->rows) new_row = ct->rows - 1; | |
885 | |
886 while(col != 0) | |
887 { | |
888 if (col < 0) | |
889 { | |
890 new_col--; | |
891 col++; | |
892 } | |
893 else | |
894 { | |
895 new_col++; | |
896 col--; | |
897 } | |
898 | |
899 if (new_col < 0) | |
900 { | |
901 if (new_row > 0) | |
902 { | |
903 new_row--; | |
904 new_col = ct->columns - 1; | |
905 } | |
906 else | |
907 { | |
908 new_col = 0; | |
909 } | |
910 } | |
911 if (new_col >= ct->columns) | |
912 { | |
913 if (new_row < ct->rows - 1) | |
914 { | |
915 new_row++; | |
916 new_col = 0; | |
917 } | |
918 else | |
919 { | |
920 new_col = ct->columns - 1; | |
921 } | |
922 } | |
923 } | |
924 } | |
925 else | |
926 { | |
927 new_row = row; | |
928 new_col = col; | |
929 | |
930 if (new_row >= ct->rows) | |
931 { | |
932 if (ct->rows > 0) | |
933 new_row = ct->rows - 1; | |
934 else | |
935 new_row = 0; | |
936 new_col = ct->columns - 1; | |
937 } | |
938 if (new_col >= ct->columns) new_col = ct->columns - 1; | |
939 } | |
940 | |
941 if (new_row == ct->rows - 1) | |
942 { | |
943 gint l; | |
944 | |
945 /* if we moved beyond the last image, go to the last image */ | |
946 | |
947 l = g_list_length(ct->cd->list); | |
948 if (ct->rows > 1) l -= (ct->rows - 1) * ct->columns; | |
949 if (new_col >= l) new_col = l - 1; | |
950 } | |
951 | |
952 if (new_row == -1 || new_col == -1) | |
953 { | |
954 if (!ct->cd->list) return; | |
955 new_row = new_col = 0; | |
956 } | |
957 | |
958 collection_table_set_focus(ct, collection_table_find_data(ct, new_row, new_col, NULL)); | |
959 } | |
960 | |
961 static void collection_table_update_focus(CollectTable *ct) | |
962 { | |
963 gint new_row = 0; | |
964 gint new_col = 0; | |
965 | |
966 if (ct->focus_info && collection_table_find_position(ct, ct->focus_info, &new_row, &new_col)) | |
967 { | |
968 /* first find the old focus, if it exists and is valid */ | |
969 } | |
970 else | |
971 { | |
972 /* (try to) stay where we were */ | |
973 new_row = ct->focus_row; | |
974 new_col = ct->focus_column; | |
975 } | |
976 | |
977 collection_table_move_focus(ct, new_row, new_col, FALSE); | |
978 } | |
979 | |
980 /* used to figure the page up/down distances */ | |
981 static gint page_height(CollectTable *ct) | |
982 { | |
983 GtkAdjustment *adj; | |
984 gint page_size; | |
985 gint row_height; | |
986 gint ret; | |
987 | |
988 adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(ct->listview)); | |
989 page_size = (gint)adj->page_increment; | |
990 | |
991 row_height = thumb_max_height + THUMB_BORDER_PADDING * 2; | |
992 if (ct->show_text) row_height += thumb_max_height / 3; | |
993 | |
994 ret = page_size / row_height; | |
995 if (ret < 1) ret = 1; | |
996 | |
997 return ret; | |
998 } | |
999 | |
1000 static void collection_table_menu_pos_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data) | |
1001 { | |
1002 CollectTable *ct = data; | |
1003 GtkTreeModel *store; | |
1004 GtkTreeIter iter; | |
1005 gint column; | |
1006 GtkTreePath *tpath; | |
1007 gint cw, ch; | |
1008 | |
1009 if (!collection_table_find_iter(ct, ct->click_info, &iter, &column)) return; | |
1010 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
1011 tpath = gtk_tree_model_get_path(store, &iter); | |
1012 tree_view_get_cell_clamped(GTK_TREE_VIEW(ct->listview), tpath, column, FALSE, x, y, &cw, &ch); | |
1013 gtk_tree_path_free(tpath); | |
1014 *y += ch; | |
1015 popup_menu_position_clamp(menu, x, y, 0); | |
1016 } | |
1017 | |
1018 static gint collection_table_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
1019 { | |
1020 CollectTable *ct = data; | |
1021 gint focus_row = 0; | |
1022 gint focus_col = 0; | |
1023 CollectInfo *info; | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1024 gint stop_signal; |
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1025 |
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1026 stop_signal = TRUE; |
9 | 1027 switch (event->keyval) |
1028 { | |
1029 case GDK_Left: case GDK_KP_Left: | |
1030 focus_col = -1; | |
1031 break; | |
1032 case GDK_Right: case GDK_KP_Right: | |
1033 focus_col = 1; | |
1034 break; | |
1035 case GDK_Up: case GDK_KP_Up: | |
1036 focus_row = -1; | |
1037 break; | |
1038 case GDK_Down: case GDK_KP_Down: | |
1039 focus_row = 1; | |
1040 break; | |
1041 case GDK_Page_Up: case GDK_KP_Page_Up: | |
1042 focus_row = -page_height(ct); | |
1043 break; | |
1044 case GDK_Page_Down: case GDK_KP_Page_Down: | |
1045 focus_row = page_height(ct); | |
1046 break; | |
1047 case GDK_Home: case GDK_KP_Home: | |
1048 focus_row = -ct->focus_row; | |
1049 focus_col = -ct->focus_column; | |
1050 break; | |
1051 case GDK_End: case GDK_KP_End: | |
1052 focus_row = ct->rows - 1 - ct->focus_row; | |
1053 focus_col = ct->columns - 1 - ct->focus_column; | |
1054 break; | |
1055 case GDK_space: | |
1056 info = collection_table_find_data(ct, ct->focus_row, ct->focus_column, NULL); | |
1057 if (info) | |
1058 { | |
1059 ct->click_info = info; | |
1060 if (event->state & GDK_CONTROL_MASK) | |
1061 { | |
1062 collection_table_select_util(ct, info, !INFO_SELECTED(info)); | |
1063 } | |
1064 else | |
1065 { | |
1066 collection_table_unselect_all(ct); | |
1067 collection_table_select(ct, info); | |
1068 } | |
1069 } | |
1070 break; | |
1071 case 'T': case 't': | |
1072 if (event->state & GDK_CONTROL_MASK) collection_table_toggle_filenames(ct); | |
1073 break; | |
1074 case GDK_Menu: | |
1075 case GDK_F10: | |
1076 info = collection_table_find_data(ct, ct->focus_row, ct->focus_column, NULL); | |
1077 ct->click_info = info; | |
1078 | |
1079 collection_table_selection_add(ct, ct->click_info, SELECTION_PRELIGHT, NULL); | |
1080 tip_unschedule(ct); | |
1081 | |
1082 ct->popup = collection_table_popup_menu(ct, (info != NULL)); | |
1083 gtk_menu_popup(GTK_MENU(ct->popup), NULL, NULL, collection_table_menu_pos_cb, ct, 0, GDK_CURRENT_TIME); | |
1084 break; | |
1085 default: | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1086 stop_signal = FALSE; |
9 | 1087 break; |
1088 } | |
1089 | |
1090 if (focus_row != 0 || focus_col != 0) | |
1091 { | |
1092 CollectInfo *new_info; | |
1093 CollectInfo *old_info; | |
1094 | |
1095 old_info = collection_table_find_data(ct, ct->focus_row, ct->focus_column, NULL); | |
1096 collection_table_move_focus(ct, focus_row, focus_col, TRUE); | |
1097 new_info = collection_table_find_data(ct, ct->focus_row, ct->focus_column, NULL); | |
1098 | |
1099 if (new_info != old_info) | |
1100 { | |
1101 if (event->state & GDK_SHIFT_MASK) | |
1102 { | |
1103 if (!collection_rectangular_selection) | |
1104 { | |
1105 collection_table_select_region_util(ct, old_info, new_info, FALSE); | |
1106 } | |
1107 else | |
1108 { | |
1109 collection_table_select_region_util(ct, ct->click_info, old_info, FALSE); | |
1110 } | |
1111 collection_table_select_region_util(ct, ct->click_info, new_info, TRUE); | |
1112 } | |
1113 else if (event->state & GDK_CONTROL_MASK) | |
1114 { | |
1115 ct->click_info = new_info; | |
1116 } | |
1117 else | |
1118 { | |
1119 ct->click_info = new_info; | |
1120 collection_table_unselect_all(ct); | |
1121 collection_table_select(ct, new_info); | |
1122 } | |
1123 } | |
1124 } | |
1125 | |
1126 if (stop_signal) | |
1127 { | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1128 #if 0 |
9 | 1129 g_signal_stop_emission_by_name(GTK_OBJECT(widget), "key_press_event"); |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
1130 #endif |
9 | 1131 tip_unschedule(ct); |
1132 } | |
1133 | |
1134 return stop_signal; | |
1135 } | |
1136 | |
1137 /* | |
1138 *------------------------------------------------------------------- | |
1139 * insert marker | |
1140 *------------------------------------------------------------------- | |
1141 */ | |
1142 | |
1143 static CollectInfo *collection_table_insert_find(CollectTable *ct, CollectInfo *source, gint *after, GdkRectangle *cell, | |
1144 gint use_coord, gint x, gint y) | |
1145 { | |
1146 CollectInfo *info = NULL; | |
1147 GtkTreeModel *store; | |
1148 GtkTreeIter iter; | |
1149 GtkTreePath *tpath; | |
1150 GtkTreeViewColumn *column; | |
1151 | |
1152 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
1153 | |
1154 if (!use_coord) gdk_window_get_pointer(ct->listview->window, &x, &y, NULL); | |
1155 | |
1156 if (source) | |
1157 { | |
1158 gint col; | |
1159 if (collection_table_find_iter(ct, source, &iter, &col)) | |
1160 { | |
1161 tpath = gtk_tree_model_get_path(store, &iter); | |
1162 column = gtk_tree_view_get_column(GTK_TREE_VIEW(ct->listview), col); | |
1163 gtk_tree_view_get_background_area(GTK_TREE_VIEW(ct->listview), tpath, column, cell); | |
1164 gtk_tree_path_free(tpath); | |
1165 | |
1166 info = source; | |
1167 *after = (x > cell->x + (cell->width / 2)); | |
1168 } | |
1169 return info; | |
1170 } | |
1171 | |
1172 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(ct->listview), x, y, | |
1173 &tpath, &column, NULL, NULL)) | |
1174 { | |
1175 GList *list; | |
1176 gint n; | |
1177 | |
1178 gtk_tree_model_get_iter(store, &iter, tpath); | |
1179 gtk_tree_model_get(store, &iter, CTABLE_COLUMN_POINTER, &list, -1); | |
1180 | |
1181 n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_number")); | |
1182 info = g_list_nth_data(list, n); | |
1183 | |
1184 if (info) | |
1185 { | |
1186 gtk_tree_view_get_background_area(GTK_TREE_VIEW(ct->listview), tpath, column, cell); | |
1187 *after = (x > cell->x + (cell->width / 2)); | |
1188 } | |
1189 | |
1190 gtk_tree_path_free(tpath); | |
1191 } | |
1192 | |
1193 if (info == NULL) | |
1194 { | |
1195 GList *work; | |
1196 | |
1197 work = g_list_last(ct->cd->list); | |
1198 if (work) | |
1199 { | |
1200 gint col; | |
1201 | |
1202 info = work->data; | |
1203 *after = TRUE; | |
1204 | |
1205 if (collection_table_find_iter(ct, info, &iter, &col)) | |
1206 { | |
1207 tpath = gtk_tree_model_get_path(store, &iter); | |
1208 column = gtk_tree_view_get_column(GTK_TREE_VIEW(ct->listview), col); | |
1209 gtk_tree_view_get_background_area(GTK_TREE_VIEW(ct->listview), tpath, column, cell); | |
1210 gtk_tree_path_free(tpath); | |
1211 } | |
1212 } | |
1213 } | |
1214 | |
1215 return info; | |
1216 } | |
1217 | |
1218 static CollectInfo *collection_table_insert_point(CollectTable *ct, gint x, gint y) | |
1219 { | |
1220 CollectInfo *info; | |
1221 GdkRectangle cell; | |
1222 gint after = FALSE; | |
1223 | |
1224 info = collection_table_insert_find(ct, NULL, &after, &cell, TRUE, x, y); | |
1225 | |
1226 if (info && after) | |
1227 { | |
1228 GList *work; | |
1229 | |
1230 work = g_list_find(ct->cd->list, info); | |
1231 if (work && work->next) | |
1232 { | |
1233 info = work->next->data; | |
1234 } | |
1235 else | |
1236 { | |
1237 info = NULL; | |
1238 } | |
1239 } | |
1240 | |
1241 return info; | |
1242 } | |
1243 | |
1244 static void collection_table_insert_marker(CollectTable *ct, CollectInfo *info, gint enable) | |
1245 { | |
1246 gint row, col; | |
1247 gint after = FALSE; | |
1248 GdkRectangle cell; | |
1249 | |
1250 if (!enable) | |
1251 { | |
1252 if (ct->marker_window) gdk_window_destroy(ct->marker_window); | |
1253 ct->marker_window = NULL; | |
1254 | |
1255 return; | |
1256 } | |
1257 | |
1258 info = collection_table_insert_find(ct, info, &after, &cell, FALSE, 0, 0); | |
1259 | |
1260 /* this setting does not take into account (after), but since it is not really used... */ | |
1261 ct->marker_info = info; | |
1262 | |
1263 row = -1; | |
1264 col = -1; | |
1265 | |
1266 if (!ct->marker_window) | |
1267 { | |
1268 GdkWindow *parent; | |
1269 GdkWindowAttr attributes; | |
1270 gint attributes_mask; | |
1271 GdkPixmap *pixmap; | |
1272 GdkBitmap *mask; | |
1273 GdkPixbuf *pb; | |
1274 gint w, h; | |
1275 | |
1276 parent = gtk_tree_view_get_bin_window(GTK_TREE_VIEW(ct->listview)); | |
1277 | |
1278 pb = gdk_pixbuf_new_from_xpm_data((const char **)marker_xpm); | |
1279 gdk_pixbuf_render_pixmap_and_mask(pb, &pixmap, &mask, 128); | |
1280 gdk_pixbuf_unref(pb); | |
1281 | |
1282 gdk_drawable_get_size(pixmap, &w, &h); | |
1283 | |
1284 attributes.window_type = GDK_WINDOW_CHILD; | |
1285 attributes.wclass = GDK_INPUT_OUTPUT; | |
1286 attributes.width = w; | |
1287 attributes.height = h; | |
1288 attributes.event_mask = gtk_widget_get_events(ct->listview); | |
1289 attributes_mask = 0; | |
1290 | |
1291 ct->marker_window = gdk_window_new(parent, &attributes, attributes_mask); | |
1292 gdk_window_set_back_pixmap(ct->marker_window, pixmap, FALSE); | |
1293 gdk_window_shape_combine_mask(ct->marker_window, mask, 0, 0); | |
1294 | |
1295 g_object_unref(pixmap); | |
1296 if (mask) g_object_unref(mask); | |
1297 } | |
1298 | |
1299 if (info) | |
1300 { | |
1301 gint x, y; | |
1302 gint w, h; | |
1303 | |
1304 gdk_drawable_get_size(ct->marker_window, &w, &h); | |
1305 | |
1306 if (!after) | |
1307 { | |
1308 x = cell.x; | |
1309 } | |
1310 else | |
1311 { | |
1312 x = cell.x + cell.width; | |
1313 } | |
1314 x -= (w / 2); | |
1315 y = cell.y + (cell.height / 2) - (h / 2); | |
1316 | |
1317 gdk_window_move(ct->marker_window, x, y); | |
1318 gdk_window_clear(ct->marker_window); | |
1319 if (!gdk_window_is_visible(ct->marker_window)) gdk_window_show(ct->marker_window); | |
1320 } | |
1321 else | |
1322 { | |
1323 if (gdk_window_is_visible(ct->marker_window)) gdk_window_hide(ct->marker_window); | |
1324 } | |
1325 } | |
1326 | |
1327 /* | |
1328 *------------------------------------------------------------------- | |
1329 * mouse drag auto-scroll | |
1330 *------------------------------------------------------------------- | |
1331 */ | |
1332 | |
1333 static void collection_table_motion_update(CollectTable *ct, gint x, gint y, gint drop_event) | |
1334 { | |
1335 CollectInfo *info; | |
1336 | |
1337 info = collection_table_find_data_by_coord(ct, x, y, NULL); | |
1338 | |
1339 if (drop_event) | |
1340 { | |
1341 tip_unschedule(ct); | |
1342 collection_table_insert_marker(ct, info, TRUE); | |
1343 } | |
1344 else | |
1345 { | |
1346 tip_update(ct, info); | |
1347 } | |
1348 } | |
1349 | |
1350 static gint collection_table_auto_scroll_idle_cb(gpointer data) | |
1351 { | |
1352 CollectTable *ct = data; | |
1353 GdkWindow *window; | |
1354 gint x, y; | |
1355 gint w, h; | |
1356 | |
1357 if (ct->drop_idle_id == -1) return FALSE; | |
1358 | |
1359 window = ct->listview->window; | |
1360 gdk_window_get_pointer(window, &x, &y, NULL); | |
1361 gdk_drawable_get_size(window, &w, &h); | |
1362 if (x >= 0 && x < w && y >= 0 && y < h) | |
1363 { | |
1364 collection_table_motion_update(ct, x, y, TRUE); | |
1365 } | |
1366 | |
1367 ct->drop_idle_id = -1; | |
1368 return FALSE; | |
1369 } | |
1370 | |
1371 static gint collection_table_auto_scroll_notify_cb(GtkWidget *widget, gint x, gint y, gpointer data) | |
1372 { | |
1373 CollectTable *ct = data; | |
1374 | |
1375 if (ct->drop_idle_id == -1) ct->drop_idle_id = g_idle_add(collection_table_auto_scroll_idle_cb, ct); | |
1376 | |
1377 return TRUE; | |
1378 } | |
1379 | |
1380 static void collection_table_scroll(CollectTable *ct, gint scroll) | |
1381 { | |
1382 if (!scroll) | |
1383 { | |
1384 if (ct->drop_idle_id != -1) | |
1385 { | |
1386 g_source_remove(ct->drop_idle_id); | |
1387 ct->drop_idle_id = -1; | |
1388 } | |
1389 widget_auto_scroll_stop(ct->listview); | |
1390 collection_table_insert_marker(ct, NULL, FALSE); | |
1391 } | |
1392 else | |
1393 { | |
1394 GtkAdjustment *adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(ct->listview)); | |
1395 widget_auto_scroll_start(ct->listview, adj, -1, thumb_max_height / 2, | |
1396 collection_table_auto_scroll_notify_cb, ct); | |
1397 } | |
1398 } | |
1399 | |
1400 /* | |
1401 *------------------------------------------------------------------- | |
1402 * mouse callbacks | |
1403 *------------------------------------------------------------------- | |
1404 */ | |
1405 | |
1406 static gint collection_table_motion_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
1407 { | |
1408 CollectTable *ct = data; | |
1409 | |
1410 collection_table_motion_update(ct, (gint)bevent->x, (gint)bevent->y, FALSE); | |
1411 | |
1412 return FALSE; | |
1413 } | |
1414 | |
1415 static gint collection_table_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
1416 { | |
1417 CollectTable *ct = data; | |
1418 GtkTreeIter iter; | |
1419 CollectInfo *info; | |
1420 | |
1421 tip_unschedule(ct); | |
1422 | |
1423 info = collection_table_find_data_by_coord(ct, (gint)bevent->x, (gint)bevent->y, &iter); | |
1424 | |
1425 ct->click_info = info; | |
1426 collection_table_selection_add(ct, ct->click_info, SELECTION_PRELIGHT, &iter); | |
1427 | |
1428 switch (bevent->button) | |
1429 { | |
1430 case 1: | |
1431 if (bevent->type == GDK_2BUTTON_PRESS) | |
1432 { | |
1433 if (info) | |
1434 { | |
1435 layout_image_set_collection(NULL, ct->cd, info); | |
1436 } | |
1437 } | |
1438 else if (!GTK_WIDGET_HAS_FOCUS(ct->listview)) | |
1439 { | |
1440 gtk_widget_grab_focus(ct->listview); | |
1441 } | |
1442 break; | |
1443 case 3: | |
1444 ct->popup = collection_table_popup_menu(ct, (info != NULL)); | |
1445 gtk_menu_popup(GTK_MENU(ct->popup), NULL, NULL, NULL, NULL, bevent->button, bevent->time); | |
1446 break; | |
1447 default: | |
1448 break; | |
1449 } | |
1450 | |
1451 return TRUE; | |
1452 } | |
1453 | |
1454 static gint collection_table_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
1455 { | |
1456 CollectTable *ct = data; | |
1457 GtkTreeIter iter; | |
1458 CollectInfo *info = NULL; | |
1459 | |
1460 tip_schedule(ct); | |
1461 | |
1462 if ((gint)bevent->x != 0 || (gint) bevent->y != 0) | |
1463 { | |
1464 info = collection_table_find_data_by_coord(ct, (gint)bevent->x, (gint)bevent->y, &iter); | |
1465 } | |
1466 | |
1467 if (ct->click_info) | |
1468 { | |
1469 collection_table_selection_remove(ct, ct->click_info, SELECTION_PRELIGHT, NULL); | |
1470 } | |
1471 | |
1472 if (bevent->button == 1 && | |
1473 info && ct->click_info == info) | |
1474 { | |
1475 collection_table_set_focus(ct, info); | |
1476 | |
1477 if (bevent->state & GDK_CONTROL_MASK) | |
1478 { | |
1479 gint select; | |
1480 | |
1481 select = !INFO_SELECTED(info); | |
1482 if ((bevent->state & GDK_SHIFT_MASK) && ct->prev_selection) | |
1483 { | |
1484 collection_table_select_region_util(ct, ct->prev_selection, info, select); | |
1485 } | |
1486 else | |
1487 { | |
1488 collection_table_select_util(ct, info, select); | |
1489 } | |
1490 } | |
1491 else | |
1492 { | |
1493 collection_table_unselect_all(ct); | |
1494 | |
1495 if ((bevent->state & GDK_SHIFT_MASK) && | |
1496 ct->prev_selection) | |
1497 { | |
1498 collection_table_select_region_util(ct, ct->prev_selection, info, TRUE); | |
1499 } | |
1500 else | |
1501 { | |
1502 collection_table_select_util(ct, info, TRUE); | |
1503 } | |
1504 } | |
1505 } | |
1506 else if (bevent->button == 2 && | |
1507 info && ct->click_info == info) | |
1508 { | |
1509 collection_table_select_util(ct, info, !INFO_SELECTED(info)); | |
1510 } | |
1511 | |
1512 return TRUE; | |
1513 } | |
1514 | |
1515 static gint collection_table_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data) | |
1516 { | |
1517 CollectTable *ct = data; | |
1518 | |
1519 tip_unschedule(ct); | |
1520 return FALSE; | |
1521 } | |
1522 | |
1523 /* | |
1524 *------------------------------------------------------------------- | |
1525 * populate, add, insert, etc. | |
1526 *------------------------------------------------------------------- | |
1527 */ | |
1528 | |
1529 static gboolean collection_table_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GtkTreeIter *iter, gpointer data) | |
1530 { | |
1531 GList *list; | |
1532 | |
1533 gtk_tree_model_get(store, iter, CTABLE_COLUMN_POINTER, &list, -1); | |
1534 g_list_free(list); | |
1535 | |
1536 return FALSE; | |
1537 } | |
1538 | |
1539 static void collection_table_clear_store(CollectTable *ct) | |
1540 { | |
1541 GtkTreeModel *store; | |
1542 | |
1543 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
1544 gtk_tree_model_foreach(store, collection_table_destroy_node_cb, NULL); | |
1545 | |
1546 gtk_list_store_clear(GTK_LIST_STORE(store)); | |
1547 } | |
1548 | |
1549 static GList *collection_table_add_row(CollectTable *ct, GtkTreeIter *iter) | |
1550 { | |
1551 GtkListStore *store; | |
1552 GList *list = NULL; | |
1553 gint i; | |
1554 | |
1555 for (i = 0; i < ct->columns; i++) list = g_list_prepend(list, NULL); | |
1556 | |
1557 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview))); | |
1558 gtk_list_store_append(store, iter); | |
1559 gtk_list_store_set(store, iter, CTABLE_COLUMN_POINTER, list, -1); | |
1560 | |
1561 return list; | |
1562 } | |
1563 | |
1564 static void collection_table_populate(CollectTable *ct, gint resize) | |
1565 { | |
1566 gint row; | |
1567 GList *work; | |
1568 | |
1569 collection_table_verify_selections(ct); | |
1570 | |
1571 collection_table_clear_store(ct); | |
1572 | |
1573 if (resize) | |
1574 { | |
1575 gint i; | |
1576 gint thumb_width; | |
1577 | |
1578 thumb_width = collection_table_get_icon_width(ct); | |
1579 | |
1580 for (i = 0; i < COLLECT_TABLE_MAX_COLUMNS; i++) | |
1581 { | |
1582 GtkTreeViewColumn *column; | |
1583 GtkCellRenderer *cell; | |
1584 GList *list; | |
1585 | |
1586 column = gtk_tree_view_get_column(GTK_TREE_VIEW(ct->listview), i); | |
1587 gtk_tree_view_column_set_visible(column, (i < ct->columns)); | |
1588 gtk_tree_view_column_set_fixed_width(column, thumb_width + (THUMB_BORDER_PADDING * 6)); | |
1589 | |
1590 list = gtk_tree_view_column_get_cell_renderers(column); | |
1591 cell = (list) ? list->data : NULL; | |
1592 g_list_free(list); | |
1593 | |
1594 if (cell && GQV_IS_CELL_RENDERER_ICON(cell)) | |
1595 { | |
1596 g_object_set(G_OBJECT(cell), "fixed_width", thumb_width, | |
1597 "fixed_height", thumb_max_height, | |
1598 "show_text", ct->show_text, NULL); | |
1599 } | |
1600 } | |
1601 if (GTK_WIDGET_REALIZED(ct->listview)) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(ct->listview)); | |
1602 } | |
1603 | |
1604 row = -1; | |
1605 work = ct->cd->list; | |
1606 while (work) | |
1607 { | |
1608 GList *list; | |
1609 GtkTreeIter iter; | |
1610 | |
1611 row++; | |
1612 | |
1613 list = collection_table_add_row(ct, &iter); | |
1614 while (work && list) | |
1615 { | |
1616 list->data = work->data; | |
1617 list = list->next; | |
1618 work = work->next; | |
1619 } | |
1620 } | |
1621 | |
1622 ct->rows = row + 1; | |
1623 | |
1624 collection_table_update_focus(ct); | |
1625 collection_table_update_status(ct); | |
1626 } | |
1627 | |
1628 static void collection_table_populate_at_new_size(CollectTable *ct, gint w, gint h, gint force) | |
1629 { | |
1630 gint new_cols; | |
1631 gint thumb_width; | |
1632 | |
1633 thumb_width = collection_table_get_icon_width(ct); | |
1634 | |
1635 new_cols = w / (thumb_width + (THUMB_BORDER_PADDING * 6)); | |
1636 if (new_cols < 1) new_cols = 1; | |
1637 | |
1638 if (!force && new_cols == ct->columns) return; | |
1639 | |
1640 ct->columns = new_cols; | |
1641 | |
1642 collection_table_populate(ct, TRUE); | |
1643 | |
1644 if (debug) printf("col tab pop cols=%d rows=%d\n", ct->columns, ct->rows); | |
1645 } | |
1646 | |
1647 static void collection_table_sync(CollectTable *ct) | |
1648 { | |
1649 GtkTreeModel *store; | |
1650 GtkTreeIter iter; | |
1651 GList *work; | |
1652 gint r, c; | |
1653 | |
1654 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
1655 | |
1656 r = -1; | |
1657 c = 0; | |
1658 | |
1659 work = ct->cd->list; | |
1660 while (work) | |
1661 { | |
1662 GList *list; | |
1663 r++; | |
1664 c = 0; | |
1665 if (gtk_tree_model_iter_nth_child(store, &iter, NULL, r)) | |
1666 { | |
1667 gtk_tree_model_get(store, &iter, CTABLE_COLUMN_POINTER, &list, -1); | |
1668 gtk_list_store_set(GTK_LIST_STORE(store), &iter, CTABLE_COLUMN_POINTER, list, -1); | |
1669 } | |
1670 else | |
1671 { | |
1672 list = collection_table_add_row(ct, &iter); | |
1673 } | |
1674 | |
1675 while (list) | |
1676 { | |
1677 CollectInfo *info; | |
1678 if (work) | |
1679 { | |
1680 info = work->data; | |
1681 work = work->next; | |
1682 c++; | |
1683 } | |
1684 else | |
1685 { | |
1686 info = NULL; | |
1687 } | |
1688 if (list) | |
1689 { | |
1690 list->data = info; | |
1691 list = list->next; | |
1692 } | |
1693 } | |
1694 } | |
1695 | |
1696 r++; | |
1697 while (gtk_tree_model_iter_nth_child(store, &iter, NULL, r)) | |
1698 { | |
1699 GList *list; | |
1700 | |
1701 gtk_tree_model_get(store, &iter, CTABLE_COLUMN_POINTER, &list, -1); | |
1702 gtk_list_store_remove(GTK_LIST_STORE(store), &iter); | |
1703 g_list_free(list); | |
1704 } | |
1705 | |
1706 ct->rows = r; | |
1707 | |
1708 collection_table_update_focus(ct); | |
1709 collection_table_update_status(ct); | |
1710 } | |
1711 | |
1712 static gint collection_table_sync_idle_cb(gpointer data) | |
1713 { | |
1714 CollectTable *ct = data; | |
1715 | |
1716 if (ct->sync_idle_id == -1) return FALSE; | |
1717 ct->sync_idle_id = -1; | |
1718 | |
1719 collection_table_sync(ct); | |
1720 return FALSE; | |
1721 } | |
1722 | |
1723 static void collection_table_sync_idle(CollectTable *ct) | |
1724 { | |
1725 if (ct->sync_idle_id == -1) | |
1726 { | |
1727 /* high priority, the view needs to be resynced before a redraw | |
1728 * may contain invalid pointers at this time | |
1729 */ | |
1730 ct->sync_idle_id = g_idle_add_full(G_PRIORITY_HIGH, collection_table_sync_idle_cb, ct, NULL); | |
1731 } | |
1732 } | |
1733 | |
138 | 1734 void collection_table_add_filelist(CollectTable *ct, GList *list) |
9 | 1735 { |
1736 GList *work; | |
1737 | |
1738 if (!list) return; | |
1739 | |
1740 work = list; | |
1741 while (work) | |
1742 { | |
138 | 1743 collection_add(ct->cd, (FileData *)work->data, FALSE); |
9 | 1744 work = work->next; |
1745 } | |
1746 } | |
1747 | |
138 | 1748 static void collection_table_insert_filelist(CollectTable *ct, GList *list, CollectInfo *insert_info) |
9 | 1749 { |
1750 GList *work; | |
1751 | |
1752 if (!list) return; | |
1753 | |
1754 work = list; | |
1755 while (work) | |
1756 { | |
138 | 1757 collection_insert(ct->cd, (FileData *)work->data, insert_info, FALSE); |
9 | 1758 work = work->next; |
1759 } | |
1760 | |
1761 collection_table_sync_idle(ct); | |
1762 } | |
1763 | |
1764 static void collection_table_move_by_info_list(CollectTable *ct, GList *info_list, gint row, gint col) | |
1765 { | |
1766 GList *work; | |
1767 GList *insert_pos = NULL; | |
1768 GList *temp; | |
1769 CollectInfo *info; | |
1770 | |
1771 if (!info_list) return; | |
1772 | |
1773 info = collection_table_find_data(ct, row, col, NULL); | |
1774 | |
1775 if (!info_list->next && info_list->data == info) return; | |
1776 | |
1777 if (info) insert_pos = g_list_find(ct->cd->list, info); | |
1778 | |
1779 /* FIXME: this may get slow for large lists */ | |
1780 work = info_list; | |
1781 while (insert_pos && work) | |
1782 { | |
1783 if (insert_pos->data == work->data) | |
1784 { | |
1785 insert_pos = insert_pos->next; | |
1786 work = info_list; | |
1787 } | |
1788 else | |
1789 { | |
1790 work = work->next; | |
1791 } | |
1792 } | |
1793 | |
1794 work = info_list; | |
1795 while (work) | |
1796 { | |
1797 ct->cd->list = g_list_remove(ct->cd->list, work->data); | |
1798 work = work->next; | |
1799 } | |
1800 | |
1801 /* place them back in */ | |
1802 temp = g_list_copy(info_list); | |
1803 | |
1804 if (insert_pos) | |
1805 { | |
1806 ct->cd->list = uig_list_insert_list(ct->cd->list, insert_pos, temp); | |
1807 } | |
1808 else if (info) | |
1809 { | |
1810 ct->cd->list = g_list_concat(temp, ct->cd->list); | |
1811 } | |
1812 else | |
1813 { | |
1814 ct->cd->list = g_list_concat(ct->cd->list, temp); | |
1815 } | |
1816 | |
1817 ct->cd->changed = TRUE; | |
1818 | |
1819 collection_table_sync_idle(ct); | |
1820 } | |
1821 | |
1822 | |
1823 /* | |
1824 *------------------------------------------------------------------- | |
1825 * updating | |
1826 *------------------------------------------------------------------- | |
1827 */ | |
1828 | |
1829 void collection_table_file_update(CollectTable *ct, CollectInfo *info) | |
1830 { | |
1831 GtkTreeIter iter; | |
1832 gint row, col; | |
1833 gdouble value; | |
1834 | |
1835 if (!info) | |
1836 { | |
1837 collection_table_update_extras(ct, FALSE, 0.0); | |
1838 return; | |
1839 } | |
1840 | |
1841 if (!collection_table_find_position(ct, info, &row, &col)) return; | |
1842 | |
1843 if (ct->columns != 0 && ct->rows != 0) | |
1844 { | |
1845 value = (gdouble)(row * ct->columns + col) / (ct->columns * ct->rows); | |
1846 } | |
1847 else | |
1848 { | |
1849 value = 0.0; | |
1850 } | |
1851 | |
1852 collection_table_update_extras(ct, TRUE, value); | |
1853 | |
1854 if (collection_table_find_iter(ct, info, &iter, NULL)) | |
1855 { | |
1856 GtkTreeModel *store; | |
1857 GList *list; | |
1858 | |
1859 store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); | |
1860 gtk_tree_model_get(store, &iter, CTABLE_COLUMN_POINTER, &list, -1); | |
1861 gtk_list_store_set(GTK_LIST_STORE(store), &iter, CTABLE_COLUMN_POINTER, list, -1); | |
1862 } | |
1863 } | |
1864 | |
1865 void collection_table_file_add(CollectTable *ct, CollectInfo *info) | |
1866 { | |
1867 collection_table_sync_idle(ct); | |
1868 } | |
1869 | |
1870 void collection_table_file_insert(CollectTable *ct, CollectInfo *ci) | |
1871 { | |
1872 collection_table_sync_idle(ct); | |
1873 } | |
1874 | |
1875 void collection_table_file_remove(CollectTable *ct, CollectInfo *ci) | |
1876 { | |
1877 if (ci && INFO_SELECTED(ci)) | |
1878 { | |
1879 ct->selection = g_list_remove(ct->selection, ci); | |
1880 } | |
1881 | |
1882 collection_table_sync_idle(ct); | |
1883 } | |
1884 | |
1885 void collection_table_refresh(CollectTable *ct) | |
1886 { | |
1887 collection_table_populate(ct, FALSE); | |
1888 } | |
1889 | |
1890 /* | |
1891 *------------------------------------------------------------------- | |
1892 * dnd | |
1893 *------------------------------------------------------------------- | |
1894 */ | |
1895 | |
1896 static void collection_table_add_dir_recursive(CollectTable *ct, gchar *path, gint recursive) | |
1897 { | |
1898 GList *d = NULL; | |
1899 GList *f = NULL; | |
1900 | |
138 | 1901 if (filelist_read(path, &f, recursive ? &d : NULL)) |
9 | 1902 { |
1903 GList *work; | |
1904 | |
138 | 1905 f = filelist_filter(f, FALSE); |
1906 d = filelist_filter(d, TRUE); | |
1907 | |
1908 f = filelist_sort_path(f); | |
1909 d = filelist_sort_path(d); | |
1910 | |
1911 collection_table_insert_filelist(ct, f, ct->marker_info); | |
9 | 1912 |
1913 work = g_list_last(d); | |
1914 while (work) | |
1915 { | |
138 | 1916 collection_table_add_dir_recursive(ct, ((FileData *)work->data)->path, TRUE); |
9 | 1917 work = work->prev; |
1918 } | |
138 | 1919 filelist_free(f); |
1920 filelist_free(d); | |
9 | 1921 } |
1922 } | |
1923 | |
1924 static void confirm_dir_list_do(CollectTable *ct, GList *list, gint recursive) | |
1925 { | |
1926 GList *work = list; | |
1927 while (work) | |
1928 { | |
138 | 1929 FileData *fd = work->data; |
9 | 1930 work = work->next; |
138 | 1931 if (isdir(fd->path)) collection_table_add_dir_recursive(ct, fd->path, recursive); |
9 | 1932 } |
138 | 1933 collection_table_insert_filelist(ct, list, ct->marker_info); |
9 | 1934 } |
1935 | |
1936 | |
1937 static void confirm_dir_list_add(GtkWidget *widget, gpointer data) | |
1938 { | |
1939 CollectTable *ct = data; | |
1940 | |
1941 confirm_dir_list_do(ct, ct->drop_list, FALSE); | |
1942 } | |
1943 | |
1944 static void confirm_dir_list_recurse(GtkWidget *widget, gpointer data) | |
1945 { | |
1946 CollectTable *ct = data; | |
1947 | |
1948 confirm_dir_list_do(ct, ct->drop_list, TRUE); | |
1949 } | |
1950 | |
1951 static void confirm_dir_list_skip(GtkWidget *widget, gpointer data) | |
1952 { | |
1953 CollectTable *ct = data; | |
1954 | |
138 | 1955 collection_table_insert_filelist(ct, ct->drop_list, ct->marker_info); |
9 | 1956 } |
1957 | |
1958 static GtkWidget *collection_table_drop_menu(CollectTable *ct) | |
1959 { | |
1960 GtkWidget *menu; | |
1961 | |
1962 menu = popup_menu_short_lived(); | |
1963 g_signal_connect(G_OBJECT(menu), "destroy", | |
1964 G_CALLBACK(collection_table_popup_destroy_cb), ct); | |
1965 | |
1966 menu_item_add_stock(menu, _("Dropped list includes folders."), GTK_STOCK_DND_MULTIPLE, NULL, NULL); | |
1967 menu_item_add_divider(menu); | |
1968 menu_item_add_stock(menu, _("_Add contents"), GTK_STOCK_OK, | |
1969 G_CALLBACK(confirm_dir_list_add), ct); | |
1970 menu_item_add_stock(menu, _("Add contents _recursive"), GTK_STOCK_ADD, | |
1971 G_CALLBACK(confirm_dir_list_recurse), ct); | |
1972 menu_item_add_stock(menu, _("_Skip folders"), GTK_STOCK_REMOVE, | |
1973 G_CALLBACK(confirm_dir_list_skip), ct); | |
1974 menu_item_add_divider(menu); | |
1975 menu_item_add_stock(menu, _("Cancel"), GTK_STOCK_CANCEL, NULL, ct); | |
1976 | |
1977 return menu; | |
1978 } | |
1979 | |
1980 /* | |
1981 *------------------------------------------------------------------- | |
1982 * dnd | |
1983 *------------------------------------------------------------------- | |
1984 */ | |
1985 | |
1986 static GtkTargetEntry collection_drag_types[] = { | |
1987 { "application/x-gqview-collection-member", 0, TARGET_APP_COLLECTION_MEMBER }, | |
1988 { "text/uri-list", 0, TARGET_URI_LIST }, | |
1989 { "text/plain", 0, TARGET_TEXT_PLAIN } | |
1990 }; | |
1991 static gint n_collection_drag_types = 3; | |
1992 | |
1993 static GtkTargetEntry collection_drop_types[] = { | |
1994 { "application/x-gqview-collection-member", 0, TARGET_APP_COLLECTION_MEMBER }, | |
1995 { "text/uri-list", 0, TARGET_URI_LIST } | |
1996 }; | |
1997 static gint n_collection_drop_types = 2; | |
1998 | |
1999 | |
2000 static void collection_table_dnd_get(GtkWidget *widget, GdkDragContext *context, | |
2001 GtkSelectionData *selection_data, guint info, | |
2002 guint time, gpointer data) | |
2003 { | |
2004 CollectTable *ct = data; | |
2005 gint selected; | |
2006 GList *list = NULL; | |
2007 gchar *uri_text = NULL; | |
2008 gint total; | |
2009 | |
2010 if (!ct->click_info) return; | |
2011 | |
2012 selected = INFO_SELECTED(ct->click_info); | |
2013 | |
2014 switch (info) | |
2015 { | |
2016 case TARGET_APP_COLLECTION_MEMBER: | |
2017 if (selected) | |
2018 { | |
2019 uri_text = collection_info_list_to_dnd_data(ct->cd, ct->selection, &total); | |
2020 } | |
2021 else | |
2022 { | |
2023 list = g_list_append(NULL, ct->click_info); | |
2024 uri_text = collection_info_list_to_dnd_data(ct->cd, list, &total); | |
2025 g_list_free(list); | |
2026 } | |
2027 break; | |
2028 case TARGET_URI_LIST: | |
2029 case TARGET_TEXT_PLAIN: | |
2030 default: | |
2031 if (selected) | |
2032 { | |
2033 list = collection_table_selection_get_list(ct); | |
2034 } | |
2035 else | |
2036 { | |
138 | 2037 list = g_list_append(NULL, file_data_ref(ct->click_info->fd)); |
9 | 2038 } |
2039 if (!list) return; | |
2040 | |
138 | 2041 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN)); |
2042 filelist_free(list); | |
9 | 2043 break; |
2044 } | |
2045 | |
2046 gtk_selection_data_set(selection_data, selection_data->target, | |
64
04ff0df3ad2f
Mon Aug 15 17:13:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
2047 8, (guchar *)uri_text, total); |
9 | 2048 g_free(uri_text); |
2049 } | |
2050 | |
2051 | |
2052 static void collection_table_dnd_receive(GtkWidget *widget, GdkDragContext *context, | |
2053 gint x, gint y, | |
2054 GtkSelectionData *selection_data, guint info, | |
2055 guint time, gpointer data) | |
2056 { | |
2057 CollectTable *ct = data; | |
2058 GList *list = NULL; | |
2059 GList *info_list = NULL; | |
2060 CollectionData *source; | |
2061 CollectInfo *drop_info; | |
2062 GList *work; | |
2063 | |
64
04ff0df3ad2f
Mon Aug 15 17:13:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
2064 if (debug) printf("%s\n", selection_data->data); |
9 | 2065 |
2066 collection_table_scroll(ct, FALSE); | |
2067 collection_table_insert_marker(ct, NULL, FALSE); | |
2068 | |
2069 drop_info = collection_table_insert_point(ct, x, y); | |
2070 | |
2071 switch (info) | |
2072 { | |
2073 case TARGET_APP_COLLECTION_MEMBER: | |
2074 source = collection_from_dnd_data((gchar *)selection_data->data, &list, &info_list); | |
2075 if (source) | |
2076 { | |
2077 if (source == ct->cd) | |
2078 { | |
2079 gint row = -1; | |
2080 gint col = -1; | |
2081 | |
2082 /* it is a move within a collection */ | |
138 | 2083 filelist_free(list); |
9 | 2084 list = NULL; |
2085 | |
2086 if (!drop_info) | |
2087 { | |
2088 collection_table_move_by_info_list(ct, info_list, -1, -1); | |
2089 } | |
2090 else if (collection_table_find_position(ct, drop_info, &row, &col)) | |
2091 { | |
2092 collection_table_move_by_info_list(ct, info_list, row, col); | |
2093 } | |
2094 } | |
2095 else | |
2096 { | |
2097 /* it is a move/copy across collections */ | |
2098 if (context->action == GDK_ACTION_MOVE) | |
2099 { | |
2100 collection_remove_by_info_list(source, info_list); | |
2101 } | |
2102 } | |
2103 g_list_free(info_list); | |
2104 } | |
2105 break; | |
2106 case TARGET_URI_LIST: | |
138 | 2107 list = uri_filelist_from_text((gchar *)selection_data->data, TRUE); |
9 | 2108 work = list; |
2109 while (work) | |
2110 { | |
138 | 2111 FileData *fd = work->data; |
2112 if (isdir(fd->path)) | |
9 | 2113 { |
2114 GtkWidget *menu; | |
2115 | |
2116 ct->drop_list = list; | |
2117 ct->drop_info = drop_info; | |
2118 menu = collection_table_drop_menu(ct); | |
2119 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, time); | |
2120 return; | |
2121 } | |
2122 work = work->next; | |
2123 } | |
2124 break; | |
2125 default: | |
2126 list = NULL; | |
2127 break; | |
2128 } | |
2129 | |
2130 if (list) | |
2131 { | |
138 | 2132 collection_table_insert_filelist(ct, list, drop_info); |
2133 filelist_free(list); | |
9 | 2134 } |
2135 } | |
2136 | |
2137 static void collection_table_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data) | |
2138 { | |
2139 CollectTable *ct = data; | |
2140 | |
2141 if (ct->click_info && ct->click_info->pixbuf) | |
2142 { | |
2143 gint items; | |
2144 | |
2145 if (INFO_SELECTED(ct->click_info)) | |
2146 items = g_list_length(ct->selection); | |
2147 else | |
2148 items = 1; | |
2149 dnd_set_drag_icon(widget, context, ct->click_info->pixbuf, items); | |
2150 } | |
2151 } | |
2152 | |
2153 static void collection_table_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data) | |
2154 { | |
2155 CollectTable *ct = data; | |
2156 | |
2157 /* apparently a leave event is not generated on a drop */ | |
2158 tip_unschedule(ct); | |
2159 | |
2160 collection_table_scroll(ct, FALSE); | |
2161 } | |
2162 | |
2163 static gint collection_table_dnd_motion(GtkWidget *widget, GdkDragContext *context, | |
2164 gint x, gint y, guint time, gpointer data) | |
2165 { | |
2166 CollectTable *ct = data; | |
2167 | |
2168 collection_table_motion_update(ct, x, y, TRUE); | |
2169 collection_table_scroll(ct, TRUE); | |
2170 | |
2171 return FALSE; | |
2172 } | |
2173 | |
2174 static void collection_table_dnd_leave(GtkWidget *widget, GdkDragContext *context, guint time, gpointer data) | |
2175 { | |
2176 CollectTable *ct = data; | |
2177 | |
2178 collection_table_scroll(ct, FALSE); | |
2179 } | |
2180 | |
2181 static void collection_table_dnd_init(CollectTable *ct) | |
2182 { | |
2183 gtk_drag_source_set(ct->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, | |
2184 collection_drag_types, n_collection_drag_types, | |
2185 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); | |
2186 g_signal_connect(G_OBJECT(ct->listview), "drag_data_get", | |
2187 G_CALLBACK(collection_table_dnd_get), ct); | |
2188 g_signal_connect(G_OBJECT(ct->listview), "drag_begin", | |
2189 G_CALLBACK(collection_table_dnd_begin), ct); | |
2190 g_signal_connect(G_OBJECT(ct->listview), "drag_end", | |
2191 G_CALLBACK(collection_table_dnd_end), ct); | |
2192 | |
2193 gtk_drag_dest_set(ct->listview, | |
2194 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, | |
2195 collection_drop_types, n_collection_drop_types, | |
2196 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK); | |
2197 g_signal_connect(G_OBJECT(ct->listview), "drag_motion", | |
2198 G_CALLBACK(collection_table_dnd_motion), ct); | |
2199 g_signal_connect(G_OBJECT(ct->listview), "drag_leave", | |
2200 G_CALLBACK(collection_table_dnd_leave), ct); | |
2201 g_signal_connect(G_OBJECT(ct->listview), "drag_data_received", | |
2202 G_CALLBACK(collection_table_dnd_receive), ct); | |
2203 } | |
2204 | |
2205 /* | |
2206 *----------------------------------------------------------------------------- | |
2207 * draw, etc. | |
2208 *----------------------------------------------------------------------------- | |
2209 */ | |
2210 | |
2211 typedef struct _ColumnData ColumnData; | |
2212 struct _ColumnData | |
2213 { | |
2214 CollectTable *ct; | |
2215 gint number; | |
2216 }; | |
2217 | |
2218 static void collection_table_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, | |
2219 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) | |
2220 { | |
2221 ColumnData *cd = data; | |
2222 CollectTable *ct; | |
2223 GtkStyle *style; | |
2224 GList *list; | |
2225 CollectInfo *info; | |
2226 GdkColor color_fg; | |
2227 GdkColor color_bg; | |
2228 | |
2229 ct = cd->ct; | |
2230 | |
2231 gtk_tree_model_get(tree_model, iter, CTABLE_COLUMN_POINTER, &list, -1); | |
2232 info = g_list_nth_data(list, cd->number); | |
2233 | |
2234 style = gtk_widget_get_style(ct->listview); | |
2235 if (info && (info->flag_mask & SELECTION_SELECTED) ) | |
2236 { | |
2237 memcpy(&color_fg, &style->text[GTK_STATE_SELECTED], sizeof(color_fg)); | |
2238 memcpy(&color_bg, &style->base[GTK_STATE_SELECTED], sizeof(color_bg)); | |
2239 } | |
2240 else | |
2241 { | |
2242 memcpy(&color_fg, &style->text[GTK_STATE_NORMAL], sizeof(color_fg)); | |
2243 memcpy(&color_bg, &style->base[GTK_STATE_NORMAL], sizeof(color_bg)); | |
2244 } | |
2245 | |
2246 if (info && (info->flag_mask & SELECTION_PRELIGHT)) | |
2247 { | |
2248 #if 0 | |
2249 shift_color(&color_fg, -1, 0); | |
2250 #endif | |
2251 shift_color(&color_bg, -1, 0); | |
2252 } | |
2253 | |
2254 if (GQV_IS_CELL_RENDERER_ICON(cell)) | |
2255 { | |
2256 if (info) | |
2257 { | |
2258 g_object_set(cell, "pixbuf", info->pixbuf, | |
138 | 2259 "text", info->fd->name, |
9 | 2260 "cell-background-gdk", &color_bg, |
2261 "cell-background-set", TRUE, | |
2262 "foreground-gdk", &color_fg, | |
2263 "foreground-set", TRUE, | |
2264 "has-focus", (ct->focus_info == info), NULL); | |
2265 } | |
2266 else | |
2267 { | |
2268 g_object_set(cell, "pixbuf", NULL, | |
2269 "text", NULL, | |
2270 "cell-background-set", FALSE, | |
2271 "foreground-set", FALSE, | |
2272 "has-focus", FALSE, NULL); | |
2273 } | |
2274 } | |
2275 } | |
2276 | |
2277 static void collection_table_append_column(CollectTable *ct, gint n) | |
2278 { | |
2279 ColumnData *cd; | |
2280 GtkTreeViewColumn *column; | |
2281 GtkCellRenderer *renderer; | |
2282 | |
2283 column = gtk_tree_view_column_new(); | |
2284 gtk_tree_view_column_set_min_width(column, 0); | |
2285 | |
2286 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); | |
2287 gtk_tree_view_column_set_alignment(column, 0.5); | |
2288 | |
2289 renderer = gqv_cell_renderer_icon_new(); | |
2290 gtk_tree_view_column_pack_start(column, renderer, FALSE); | |
2291 g_object_set(G_OBJECT(renderer), "xpad", THUMB_BORDER_PADDING * 2, | |
2292 "ypad", THUMB_BORDER_PADDING, | |
2293 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); | |
2294 | |
2295 g_object_set_data(G_OBJECT(column), "column_number", GINT_TO_POINTER(n)); | |
2296 | |
2297 cd = g_new0(ColumnData, 1); | |
2298 cd->ct = ct; | |
2299 cd->number = n; | |
2300 gtk_tree_view_column_set_cell_data_func(column, renderer, collection_table_cell_data_cb, cd, g_free); | |
2301 | |
2302 gtk_tree_view_append_column(GTK_TREE_VIEW(ct->listview), column); | |
2303 } | |
2304 | |
2305 /* | |
2306 *------------------------------------------------------------------- | |
2307 * init, destruction | |
2308 *------------------------------------------------------------------- | |
2309 */ | |
2310 | |
2311 static void collection_table_destroy(GtkWidget *widget, gpointer data) | |
2312 { | |
2313 CollectTable *ct = data; | |
2314 | |
2315 if (ct->popup) | |
2316 { | |
2317 g_signal_handlers_disconnect_matched(GTK_OBJECT(ct->popup), G_SIGNAL_MATCH_DATA, | |
2318 0, 0, 0, NULL, ct); | |
2319 gtk_widget_destroy(ct->popup); | |
2320 } | |
2321 | |
2322 if (ct->sync_idle_id != -1) g_source_remove(ct->sync_idle_id); | |
2323 | |
2324 tip_unschedule(ct); | |
2325 collection_table_scroll(ct, FALSE); | |
2326 | |
2327 g_free(ct); | |
2328 } | |
2329 | |
2330 static void collection_table_sized(GtkWidget *widget, GtkAllocation *allocation, gpointer data) | |
2331 { | |
2332 CollectTable *ct = data; | |
2333 | |
2334 collection_table_populate_at_new_size(ct, allocation->width, allocation->height, FALSE); | |
2335 } | |
2336 | |
2337 CollectTable *collection_table_new(CollectionData *cd) | |
2338 { | |
2339 CollectTable *ct; | |
2340 GtkListStore *store; | |
2341 GtkTreeSelection *selection; | |
2342 gint i; | |
2343 | |
2344 ct = g_new0(CollectTable, 1); | |
2345 ct->cd = cd; | |
2346 ct->columns = 0; | |
2347 ct->rows = 0; | |
2348 | |
2349 ct->selection = NULL; | |
2350 ct->prev_selection = NULL; | |
2351 | |
2352 ct->tip_window = NULL; | |
2353 ct->tip_delay_id = -1; | |
2354 | |
2355 ct->marker_window = NULL; | |
2356 ct->marker_info = NULL; | |
2357 | |
2358 ct->status_label = NULL; | |
2359 ct->extra_label = NULL; | |
2360 | |
2361 ct->focus_row = 0; | |
2362 ct->focus_column = 0; | |
2363 ct->focus_info = NULL; | |
2364 | |
2365 ct->show_text = show_icon_names; | |
2366 | |
2367 ct->sync_idle_id = -1; | |
2368 ct->drop_idle_id = -1; | |
2369 | |
2370 ct->popup = NULL; | |
2371 ct->drop_info = NULL; | |
2372 ct->drop_list = NULL; | |
2373 | |
2374 ct->scrolled = gtk_scrolled_window_new(NULL, NULL); | |
2375 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct->scrolled), GTK_SHADOW_IN); | |
2376 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ct->scrolled), | |
2377 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
2378 | |
2379 store = gtk_list_store_new(1, G_TYPE_POINTER); | |
2380 ct->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); | |
2381 g_object_unref(store); | |
2382 | |
2383 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ct->listview)); | |
2384 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_NONE); | |
2385 | |
2386 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ct->listview), FALSE); | |
2387 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ct->listview), FALSE); | |
2388 | |
2389 for (i = 0; i < COLLECT_TABLE_MAX_COLUMNS; i++) | |
2390 { | |
2391 collection_table_append_column(ct, i); | |
2392 } | |
2393 | |
2394 /* zero width column to hide tree view focus, we draw it ourselves */ | |
2395 collection_table_append_column(ct, i); | |
2396 /* end column to fill white space */ | |
2397 collection_table_append_column(ct, i); | |
2398 | |
2399 g_signal_connect(G_OBJECT(ct->listview), "destroy", | |
2400 G_CALLBACK(collection_table_destroy), ct); | |
2401 g_signal_connect(G_OBJECT(ct->listview), "size_allocate", | |
2402 G_CALLBACK(collection_table_sized), ct); | |
2403 g_signal_connect(G_OBJECT(ct->listview), "key_press_event", | |
2404 G_CALLBACK(collection_table_press_key_cb), ct); | |
2405 | |
2406 gtk_container_add(GTK_CONTAINER(ct->scrolled), ct->listview); | |
2407 gtk_widget_show(ct->listview); | |
2408 | |
2409 collection_table_dnd_init(ct); | |
2410 | |
2411 gtk_widget_set_events(ct->listview, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | | |
2412 GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK); | |
2413 g_signal_connect(G_OBJECT(ct->listview),"button_press_event", | |
2414 G_CALLBACK(collection_table_press_cb), ct); | |
2415 g_signal_connect(G_OBJECT(ct->listview),"button_release_event", | |
2416 G_CALLBACK(collection_table_release_cb), ct); | |
2417 g_signal_connect(G_OBJECT(ct->listview),"motion_notify_event", | |
2418 G_CALLBACK(collection_table_motion_cb), ct); | |
2419 g_signal_connect(G_OBJECT(ct->listview), "leave_notify_event", | |
2420 G_CALLBACK(collection_table_leave_cb), ct); | |
2421 | |
2422 return ct; | |
2423 } | |
2424 | |
2425 void collection_table_set_labels(CollectTable *ct, GtkWidget *status, GtkWidget *extra) | |
2426 { | |
2427 ct->status_label = status; | |
2428 ct->extra_label = extra; | |
2429 collection_table_update_status(ct); | |
2430 collection_table_update_extras(ct, FALSE, 0.0); | |
2431 } | |
2432 | |
2433 CollectInfo *collection_table_get_focus_info(CollectTable *ct) | |
2434 { | |
2435 return collection_table_find_data(ct, ct->focus_row, ct->focus_column, NULL); | |
2436 } | |
2437 |