2 * This file is part of DisOrder
3 * Copyright (C) 2009 Richard Kettlewell
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.
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.
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/>.
18 /** @file disobedience/multidrag.c
19 * @brief Drag multiple rows of a GtkTreeView
21 #include "disobedience.h"
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
,
28 return *(gboolean
*)data
;
31 static void block_selection(GtkWidget
*w
, gboolean block
,
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
,
39 // Remember the pointer location
40 int *where
= g_object_get_data(G_OBJECT(w
), "multidrag-where");
42 where
= g_malloc(2 * sizeof (int));
43 g_object_set_data(G_OBJECT(w
), "multidrag-where", where
);
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
54 block_selection(w
, TRUE
, -1, -1);
55 /* We are only interested in left-button behavior */
56 if(event
->button
!= 1)
58 /* We are only interested in unmodified clicks (not SHIFT etc) */
59 if(event
->state
& GDK_MODIFIER_MASK
)
61 /* We are only interested if a well-defined path is clicked */
63 if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w
),
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
))
74 /* We block subsequent selection changes and remember where the
76 block_selection(w
, FALSE
, event
->x
, event
->y
);
77 return FALSE
; /* propagate */
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");
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,
94 GtkTreeViewColumn
*col
;
95 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w
),
100 gtk_tree_view_set_cursor(GTK_TREE_VIEW(w
), path
, col
, FALSE
);
104 return FALSE
; /* propagate */
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
);