chiark / gitweb /
Use a cards image for 'random' icon
[disorder] / disobedience / choose.c
index 8d8ac08601c4dd5fc52ffc76ab156783b4311b8b..a1d50c1a62c18f584af0f74435f9bd533f435be8 100644 (file)
@@ -2,20 +2,18 @@
  * This file is part of DisOrder
  * Copyright (C) 2008 Richard Kettlewell
  *
- * This program is free software; you can redistribute it and/or modify
+ * 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 2 of the License, or
+ * 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.
- *
+ * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 /** @file disobedience/choose.c
  * @brief Hierarchical track selection and search
 
 #include "disobedience.h"
 #include "choose.h"
+#include "multidrag.h"
+#include "queue-generic.h"
 #include <gdk/gdkkeysyms.h>
 
+/** @brief Drag types */
+const GtkTargetEntry choose_targets[] = {
+  {
+    PLAYABLE_TRACKS,                             /* drag type */
+    GTK_TARGET_SAME_APP|GTK_TARGET_OTHER_WIDGET, /* copying between widgets */
+    PLAYABLE_TRACKS_ID                           /* ID value */
+  },
+  {
+    .target = NULL
+  }
+};
+
 /** @brief The current selection tree */
 GtkTreeStore *choose_store;
 
@@ -105,7 +117,7 @@ int choose_can_autocollapse(GtkTreeIter *iter) {
 }
 
 /** @brief Remove node @p it and all its children
- * @param Iterator, updated to point to next
+ * @param it Iterator, updated to point to next
  * @return True if iterator remains valid
  *
  * TODO is this necessary?  gtk_tree_store_remove() does not document what
@@ -165,12 +177,12 @@ static void choose_set_state(const char attribute((unused)) *event,
  * @param parent_ref Node to populate or NULL to fill root
  * @param nvec Number of children to add
  * @param vec Children
- * @param files 1 if children are files, 0 if directories
+ * @param isfile 1 if children are files, 0 if directories
  *
  * Adjusts the set of files (or directories) below @p parent_ref to match those
  * listed in @p nvec and @p vec.
  *
- * @parent_ref will be destroyed.
+ * @p parent_ref will be destroyed.
  */
 static void choose_populate(GtkTreeRowReference *parent_ref,
                             int nvec, char **vec,
@@ -505,7 +517,7 @@ static void choose_refill(const char attribute((unused)) *event,
  */
 static gboolean choose_key_event(GtkWidget attribute((unused)) *widget,
                                  GdkEventKey *event,
-                                 gpointer attribute((unused)) user_data) {
+                                 gpointer user_data) {
   /*fprintf(stderr, "choose_key_event type=%d state=%#x keyval=%#x\n",
           event->type, event->state, event->keyval);*/
   switch(event->keyval) {
@@ -535,10 +547,65 @@ static gboolean choose_key_event(GtkWidget attribute((unused)) *widget,
     }
     break;
   }
+  /* Anything not handled we redirected to the search entry field */
   gtk_widget_event(user_data, (GdkEvent *)event);
   return TRUE;                          /* Handled it */
 }
 
+static gboolean choose_multidrag_predicate(GtkTreePath attribute((unused)) *path,
+                                           GtkTreeIter *iter) {
+  return choose_is_file(iter);
+}
+
+
+/** @brief Callback to add selected tracks to the selection data
+ *
+ * Called from choose_drag_data_get().
+ */
+static void choose_drag_data_get_collect(GtkTreeModel attribute((unused)) *model,
+                                         GtkTreePath attribute((unused)) *path,
+                                         GtkTreeIter *iter,
+                                         gpointer data) {
+  struct dynstr *const result = data;
+
+  if(choose_is_file(iter)) {            /* no diretories */
+    dynstr_append_string(result, "");   /* no ID */
+    dynstr_append(result, '\n');
+    dynstr_append_string(result, choose_get_track(iter));
+    dynstr_append(result, '\n');
+  }
+}
+
+/** @brief Called to extract the dragged data from the choose view
+ * @param w Source widget (the tree view)
+ * @param dc Drag context
+ * @param data Where to put the answer
+ * @param info_ Target @c info parameter
+ * @param time_ Time data requested (for some reason not a @c time_t)
+ * @param user_data The queuelike
+ *
+ * Closely analogous to ql_drag_data_get(), and uses the same data format.
+ * IDs are sent as empty strings.
+ */
+static void choose_drag_data_get(GtkWidget *w,
+                                 GdkDragContext attribute((unused)) *dc,
+                                 GtkSelectionData *data,
+                                 guint attribute((unused)) info_,
+                                 guint attribute((unused)) time_,
+                                 gpointer attribute((unused)) user_data) {
+  struct dynstr result[1];
+  GtkTreeSelection *sel;
+
+  sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(w));
+  dynstr_init(result);
+  gtk_tree_selection_selected_foreach(sel,
+                                      choose_drag_data_get_collect,
+                                      result);
+  gtk_selection_data_set(data,
+                         GDK_TARGET_STRING,
+                         8, (guchar *)result->vec, result->nvec);
+}
+
 /** @brief Create the choose tab */
 GtkWidget *choose_widget(void) {
   /* Create the tree store. */
@@ -620,6 +687,7 @@ GtkWidget *choose_widget(void) {
   event_register("playing-track-changed", choose_set_state, 0);
   event_register("search-results-changed", choose_set_state, 0);
   event_register("lookups-completed", choose_set_state, 0);
+  event_register("choose-more-tracks", choose_menu_moretracks, 0);
 
   /* After a rescan we update the choose tree.  We get a rescan-complete
    * automatically at startup and upon connection too. */
@@ -643,6 +711,17 @@ GtkWidget *choose_widget(void) {
   g_signal_connect(choose_view, "key-release-event",
                    G_CALLBACK(choose_key_event), choose_search_entry);
 
+  /* Enable dragging of tracks out */
+  gtk_drag_source_set(choose_view,
+                      GDK_BUTTON1_MASK,
+                      choose_targets,
+                      1,
+                      GDK_ACTION_COPY);
+  g_signal_connect(choose_view, "drag-data-get",
+                   G_CALLBACK(choose_drag_data_get), NULL);
+  make_treeview_multidrag(choose_view,
+                          choose_multidrag_predicate);
+
   return vbox;
 }