From 6a7eb11801ac98ea701dc52d38d8705eea1047a7 Mon Sep 17 00:00:00 2001 Message-Id: <6a7eb11801ac98ea701dc52d38d8705eea1047a7.1715292758.git.mdw@distorted.org.uk> From: Mark Wooding Date: Fri, 13 Nov 2009 19:45:53 +0000 Subject: [PATCH] Multiple-track drag+drop queue rearrangement. Organization: Straylight/Edgeware From: Richard Kettlewell --- CHANGES.html | 9 +++ disobedience/Makefile.am | 2 +- disobedience/disobedience.h | 2 + disobedience/multidrag.c | 121 +++++++++++++++++++++++++++++++++++ disobedience/queue-generic.c | 1 + 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 disobedience/multidrag.c diff --git a/CHANGES.html b/CHANGES.html index 8b0b28f..38f14e9 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -82,6 +82,15 @@ span.command { +

Disobedience

+ +
+ +

Multiple tracks can now be dragged in the queue in a single + operation.

+ +
+

Web Interface

diff --git a/disobedience/Makefile.am b/disobedience/Makefile.am index f8bdb14..353b145 100644 --- a/disobedience/Makefile.am +++ b/disobedience/Makefile.am @@ -28,7 +28,7 @@ disobedience_SOURCES=disobedience.h disobedience.c client.c queue.c \ choose.c choose-menu.c choose-search.c popup.c misc.c \ control.c properties.c menu.c log.c progress.c login.c rtp.c \ help.c ../lib/memgc.c settings.c users.c lookup.c choose.h \ - popup.h playlists.c + popup.h playlists.c multidrag.c disobedience_LDADD=../lib/libdisorder.a $(LIBPCRE) $(LIBGC) $(LIBGCRYPT) \ $(LIBASOUND) $(COREAUDIO) $(LIBDB) $(LIBICONV) disobedience_LDFLAGS=$(GTK_LIBS) diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index f4678c7..404358a 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -266,6 +266,8 @@ extern GtkWidget *playlists_menu; extern GtkWidget *editplaylists_widget; #endif +void make_treeview_multidrag(GtkWidget *w); + #endif /* DISOBEDIENCE_H */ /* diff --git a/disobedience/multidrag.c b/disobedience/multidrag.c new file mode 100644 index 0000000..95a133a --- /dev/null +++ b/disobedience/multidrag.c @@ -0,0 +1,121 @@ +/* + * This file is part of DisOrder + * Copyright (C) 2009 Richard Kettlewell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/** @file disobedience/multidrag.c + * @brief Drag multiple rows of a GtkTreeView + */ +#include "disobedience.h" + +static gboolean multidrag_selection_block(GtkTreeSelection attribute((unused)) *selection, + GtkTreeModel attribute((unused)) *model, + GtkTreePath attribute((unused)) *path, + gboolean attribute((unused)) path_currently_selected, + gpointer data) { + return *(gboolean *)data; +} + +static void block_selection(GtkWidget *w, gboolean block, + int x, int y) { + static gboolean which[] = { FALSE, TRUE }; + GtkTreeSelection *s = gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); + gtk_tree_selection_set_select_function(s, + multidrag_selection_block, + &which[!!block], + NULL); + // Remember the pointer location + int *where = g_object_get_data(G_OBJECT(w), "multidrag-where"); + if(!where) { + where = g_malloc(2 * sizeof (int)); + g_object_set_data(G_OBJECT(w), "multidrag-where", where); + } + where[0] = x; + where[1] = y; +} + +static gboolean multidrag_button_press_event(GtkWidget *w, + GdkEventButton *event, + gpointer attribute((unused)) user_data) { + /* By default we assume that anything this button press does should + * act as normal */ + block_selection(w, TRUE, -1, -1); + /* We are only interested in left-button behavior */ + if(event->button != 1) + return FALSE; + /* We are only interested in unmodified clicks (not SHIFT etc) */ + if(event->state & GDK_MODIFIER_MASK) + return FALSE; + /* We are only interested if a well-defined path is clicked */ + GtkTreePath *path; + if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), + event->x, event->y, + &path, + NULL, + NULL, NULL)) + return FALSE; + //gtk_widget_grab_focus(w); // TODO why?? + /* We are only interested if a selected row is clicked */ + GtkTreeSelection *s = gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); + if(!gtk_tree_selection_path_is_selected(s, path)) + return FALSE; + /* We block subsequent selection changes and remember where the + * click was */ + block_selection(w, FALSE, event->x, event->y); + return FALSE; /* propagate */ +} + +static gboolean multidrag_button_release_event(GtkWidget *w, + GdkEventButton *event, + gpointer attribute((unused)) user_data) { + int *where = g_object_get_data(G_OBJECT(w), "multidrag-where"); + + if(where && where[0] != -1) { + // Remember where the down-click was + const int x = where[0], y = where[1]; + // Re-allow selections + block_selection(w, TRUE, -1, -1); + if(x == event->x && y == event->y) { + // If the up-click is at the same location as the down-click, + // it's not a drag. + GtkTreePath *path; + GtkTreeViewColumn *col; + if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), + event->x, event->y, + &path, + &col, + NULL, NULL)) { + gtk_tree_view_set_cursor(GTK_TREE_VIEW(w), path, col, FALSE); + } + } + } + return FALSE; /* propagate */ +} + +void make_treeview_multidrag(GtkWidget *w) { + g_signal_connect(w, "button-press-event", + G_CALLBACK(multidrag_button_press_event), NULL); + g_signal_connect(w, "button-release-event", + G_CALLBACK(multidrag_button_release_event), NULL); +} + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ diff --git a/disobedience/queue-generic.c b/disobedience/queue-generic.c index 913d9d3..2db2e1d 100644 --- a/disobedience/queue-generic.c +++ b/disobedience/queue-generic.c @@ -798,6 +798,7 @@ GtkWidget *init_queuelike(struct queuelike *ql) { G_CALLBACK(ql_drag_data_get), ql); g_signal_connect(ql->view, "drag-data-received", G_CALLBACK(ql_drag_data_received), ql); + make_treeview_multidrag(ql->view); } else { /* TODO: support copy-dragging out of non-rearrangeable queues. Will need * to support copy dropping into the rearrangeable ones. */ -- [mdw]