Commit | Line | Data |
---|---|---|
6a7eb118 RK |
1 | /* |
2 | * This file is part of DisOrder | |
3 | * Copyright (C) 2009 Richard Kettlewell | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | /** @file disobedience/multidrag.c | |
19 | * @brief Drag multiple rows of a GtkTreeView | |
20 | */ | |
21 | #include "disobedience.h" | |
22 | ||
23 | static gboolean multidrag_selection_block(GtkTreeSelection attribute((unused)) *selection, | |
24 | GtkTreeModel attribute((unused)) *model, | |
25 | GtkTreePath attribute((unused)) *path, | |
26 | gboolean attribute((unused)) path_currently_selected, | |
27 | gpointer data) { | |
28 | return *(gboolean *)data; | |
29 | } | |
30 | ||
31 | static void block_selection(GtkWidget *w, gboolean block, | |
32 | int x, int y) { | |
33 | static gboolean which[] = { FALSE, TRUE }; | |
34 | GtkTreeSelection *s = gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); | |
35 | gtk_tree_selection_set_select_function(s, | |
36 | multidrag_selection_block, | |
37 | &which[!!block], | |
38 | NULL); | |
39 | // Remember the pointer location | |
40 | int *where = g_object_get_data(G_OBJECT(w), "multidrag-where"); | |
41 | if(!where) { | |
42 | where = g_malloc(2 * sizeof (int)); | |
43 | g_object_set_data(G_OBJECT(w), "multidrag-where", where); | |
44 | } | |
45 | where[0] = x; | |
46 | where[1] = y; | |
47 | } | |
48 | ||
49 | static gboolean multidrag_button_press_event(GtkWidget *w, | |
50 | GdkEventButton *event, | |
51 | gpointer attribute((unused)) user_data) { | |
52 | /* By default we assume that anything this button press does should | |
53 | * act as normal */ | |
54 | block_selection(w, TRUE, -1, -1); | |
55 | /* We are only interested in left-button behavior */ | |
56 | if(event->button != 1) | |
57 | return FALSE; | |
58 | /* We are only interested in unmodified clicks (not SHIFT etc) */ | |
59 | if(event->state & GDK_MODIFIER_MASK) | |
60 | return FALSE; | |
61 | /* We are only interested if a well-defined path is clicked */ | |
62 | GtkTreePath *path; | |
63 | if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), | |
64 | event->x, event->y, | |
65 | &path, | |
66 | NULL, | |
67 | NULL, NULL)) | |
68 | return FALSE; | |
69 | //gtk_widget_grab_focus(w); // TODO why?? | |
70 | /* We are only interested if a selected row is clicked */ | |
71 | GtkTreeSelection *s = gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); | |
72 | if(!gtk_tree_selection_path_is_selected(s, path)) | |
73 | return FALSE; | |
74 | /* We block subsequent selection changes and remember where the | |
75 | * click was */ | |
76 | block_selection(w, FALSE, event->x, event->y); | |
77 | return FALSE; /* propagate */ | |
78 | } | |
79 | ||
80 | static gboolean multidrag_button_release_event(GtkWidget *w, | |
81 | GdkEventButton *event, | |
82 | gpointer attribute((unused)) user_data) { | |
83 | int *where = g_object_get_data(G_OBJECT(w), "multidrag-where"); | |
84 | ||
85 | if(where && where[0] != -1) { | |
86 | // Remember where the down-click was | |
87 | const int x = where[0], y = where[1]; | |
88 | // Re-allow selections | |
89 | block_selection(w, TRUE, -1, -1); | |
90 | if(x == event->x && y == event->y) { | |
91 | // If the up-click is at the same location as the down-click, | |
92 | // it's not a drag. | |
93 | GtkTreePath *path; | |
94 | GtkTreeViewColumn *col; | |
95 | if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), | |
96 | event->x, event->y, | |
97 | &path, | |
98 | &col, | |
99 | NULL, NULL)) { | |
100 | gtk_tree_view_set_cursor(GTK_TREE_VIEW(w), path, col, FALSE); | |
101 | } | |
102 | } | |
103 | } | |
104 | return FALSE; /* propagate */ | |
105 | } | |
106 | ||
107 | void make_treeview_multidrag(GtkWidget *w) { | |
108 | g_signal_connect(w, "button-press-event", | |
109 | G_CALLBACK(multidrag_button_press_event), NULL); | |
110 | g_signal_connect(w, "button-release-event", | |
111 | G_CALLBACK(multidrag_button_release_event), NULL); | |
112 | } | |
113 | ||
114 | /* | |
115 | Local Variables: | |
116 | c-basic-offset:2 | |
117 | comment-column:40 | |
118 | fill-column:79 | |
119 | indent-tabs-mode:nil | |
120 | End: | |
121 | */ |