summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-04-04 13:32:15 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-04-04 13:32:15 +0200
commit3e353f8d1a41585b4715eaf0dfeed057b8a23b15 (patch)
treec651c2443efaa6004c0ab19c56aefe2961c8d1b0
parent1af02622022d9100b302c7dd7e8bc08793bead38 (diff)
implemented dragndrop between different playlists
-rw-r--r--deadbeef.h5
-rw-r--r--playlist.c71
-rw-r--r--playlist.h9
-rw-r--r--plugins.c5
-rw-r--r--plugins/gtkui/ddblistview.c18
-rw-r--r--plugins/gtkui/ddblistview.h3
-rw-r--r--plugins/gtkui/ddbtabstrip.c115
-rw-r--r--plugins/gtkui/mainplaylist.c12
8 files changed, 186 insertions, 52 deletions
diff --git a/deadbeef.h b/deadbeef.h
index eaf9f076..a0053cdd 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -319,6 +319,8 @@ typedef struct {
int (*cond_broadcast) (uintptr_t cond);
// playlist management
int (*plt_get_count) (void);
+ DB_playItem_t * (*plt_get_head) (int plt);
+ int (*plt_get_sel_count) (int plt);
int (*plt_add) (int before, const char *title);
void (*plt_remove) (int plt);
void (*plt_free) (void);
@@ -330,6 +332,8 @@ typedef struct {
// playlist control
void (*pl_lock) (void);
void (*pl_unlock) (void);
+ void (*plt_lock) (void);
+ void (*plt_unlock) (void);
// playlist tracks access
DB_playItem_t * (*pl_item_alloc) (void);
void (*pl_item_ref) (DB_playItem_t *it);
@@ -389,6 +393,7 @@ typedef struct {
// DB_playItem_t* (*pl_get_head) (void);
// DB_playItem_t* (*pl_get_tail) (void);
void (*pl_move_items) (int iter, DB_playItem_t *drop_before, uint32_t *indexes, int count);
+ void (*pl_copy_items) (int iter, int plt_from, DB_playItem_t *before, uint32_t *indices, int cnt);
void (*pl_search_reset) (void);
void (*pl_search_process) (const char *text);
// metainfo
diff --git a/playlist.c b/playlist.c
index f556a3ef..09e656f0 100644
--- a/playlist.c
+++ b/playlist.c
@@ -198,6 +198,39 @@ plt_get_count (void) {
return playlists_count;
}
+playItem_t *
+plt_get_head (int plt) {
+ playlist_t *p = playlists_head;
+ for (int i = 0; p && i <= plt; i++, p = p->next) {
+ if (i == plt) {
+ if (p->head[PL_MAIN]) {
+ pl_item_ref (p->head[PL_MAIN]);
+ }
+ return p->head[PL_MAIN];
+ }
+ }
+ return NULL;
+}
+
+int
+plt_get_sel_count (int plt) {
+ playlist_t *p = playlists_head;
+ for (int i = 0; p && i <= plt; i++, p = p->next) {
+ if (i == plt) {
+ int cnt = 0;
+ LOCK;
+ for (playItem_t *it = p->head[PL_MAIN]; it; it = it->next[PL_MAIN]) {
+ if (it->selected) {
+ cnt++;
+ }
+ }
+ UNLOCK;
+ return cnt;
+ }
+ }
+ return 0;
+}
+
int
plt_add (int before, const char *title) {
trace ("plt_add\n");
@@ -2549,6 +2582,44 @@ pl_move_items (int iter, playItem_t *drop_before, uint32_t *indexes, int count)
}
void
+pl_copy_items (int iter, int plt_from, playItem_t *before, uint32_t *indices, int cnt) {
+ pl_lock ();
+ playlist_t *from = playlists_head;
+ playlist_t *to = plt_get_curr_ptr ();
+
+ int i;
+ for (i = 0; i < plt_from; i++) {
+ from = from->next;
+ }
+
+ if (!from || !to) {
+ pl_unlock ();
+ return;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ playItem_t *it = from->head[iter];
+ int idx = 0;
+ while (it && idx < indices[i]) {
+ it = it->next[iter];
+ idx++;
+ }
+ if (!it) {
+ trace ("pl_copy_items: warning: item %d not found in source playlist\n", indices[i]);
+ continue;
+ }
+ playItem_t *it_new = pl_item_alloc ();
+ pl_item_copy (it_new, it);
+
+ playItem_t *after = before ? before->prev[iter] : to->tail[iter];
+ pl_insert_item (after, it_new);
+ pl_item_unref (it_new);
+
+ }
+ pl_unlock ();
+}
+
+void
pl_search_reset (void) {
GLOBAL_LOCK;
while (playlist->head[PL_SEARCH]) {
diff --git a/playlist.h b/playlist.h
index 9651e148..b6c8403f 100644
--- a/playlist.h
+++ b/playlist.h
@@ -93,6 +93,12 @@ plt_get_curr_ptr (void);
int
plt_get_count (void);
+playItem_t *
+plt_get_head (int plt);
+
+int
+plt_get_sel_count (int plt);
+
int
plt_add (int before, const char *title);
@@ -266,6 +272,9 @@ void
pl_move_items (int iter, playItem_t *drop_before, uint32_t *indexes, int count);
void
+pl_copy_items (int iter, int plt_from, playItem_t *before, uint32_t *indices, int cnt);
+
+void
pl_search_reset (void);
void
diff --git a/plugins.c b/plugins.c
index 64845e0d..429fac61 100644
--- a/plugins.c
+++ b/plugins.c
@@ -106,6 +106,8 @@ static DB_functions_t deadbeef_api = {
.cond_broadcast = cond_broadcast,
// playlist management
.plt_get_count = plt_get_count,
+ .plt_get_head = (DB_playItem_t * (*) (int plt))plt_get_head,
+ .plt_get_sel_count = plt_get_sel_count,
.plt_add = plt_add,
.plt_remove = plt_remove,
.plt_free = plt_free,
@@ -117,6 +119,8 @@ static DB_functions_t deadbeef_api = {
// playlist access
.pl_lock = pl_lock,
.pl_unlock = pl_unlock,
+ .plt_lock = plt_lock,
+ .plt_unlock = plt_unlock,
.pl_item_alloc = (DB_playItem_t* (*)(void))pl_item_alloc,
.pl_item_ref = (void (*)(DB_playItem_t *))pl_item_ref,
.pl_item_unref = (void (*)(DB_playItem_t *))pl_item_unref,
@@ -153,6 +157,7 @@ static DB_functions_t deadbeef_api = {
.pl_format_title = (int (*) (DB_playItem_t *it, int idx, char *s, int size, int id, const char *fmt))pl_format_title,
.pl_format_item_display_name = (void (*) (DB_playItem_t *it, char *str, int len))pl_format_item_display_name,
.pl_move_items = (void (*) (int iter, DB_playItem_t *drop_before, uint32_t *indexes, int count))pl_move_items,
+ .pl_copy_items = (void (*) (int iter, int plt_from, DB_playItem_t *before, uint32_t *indices, int cnt))pl_copy_items,
.pl_search_reset = pl_search_reset,
.pl_search_process = pl_search_process,
// metainfo
diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c
index 9ac6e561..441e126b 100644
--- a/plugins/gtkui/ddblistview.c
+++ b/plugins/gtkui/ddblistview.c
@@ -828,14 +828,15 @@ ddb_listview_list_drag_data_get (GtkWidget *widget,
case TARGET_SAMEWIDGET:
{
// format as "STRING" consisting of array of pointers
- int nsel = ps->binding->sel_count ();
+ int nsel = deadbeef->plt_get_sel_count (ps->drag_source_playlist);
if (!nsel) {
break; // something wrong happened
}
- uint32_t *ptr = malloc (nsel * sizeof (uint32_t));
+ uint32_t *ptr = malloc ((nsel+1) * sizeof (uint32_t));
+ *ptr = ps->drag_source_playlist;
int idx = 0;
- int i = 0;
- DdbListviewIter it = ps->binding->head ();
+ int i = 1;
+ DdbListviewIter it = deadbeef->plt_get_head (ps->drag_source_playlist);
for (; it; idx++) {
if (ps->binding->is_selected (it)) {
ptr[i] = idx;
@@ -845,7 +846,7 @@ ddb_listview_list_drag_data_get (GtkWidget *widget,
ps->binding->unref (it);
it = next;
}
- gtk_selection_data_set (selection_data, selection_data->target, sizeof (uint32_t) * 8, (gchar *)ptr, nsel * sizeof (uint32_t));
+ gtk_selection_data_set (selection_data, selection_data->target, sizeof (uint32_t) * 8, (gchar *)ptr, (nsel+1) * sizeof (uint32_t));
free (ptr);
}
break;
@@ -894,7 +895,9 @@ ddb_listview_list_drag_data_received (GtkWidget *widget,
}
else if (target_type == 1) {
uint32_t *d= (uint32_t *)ptr;
- int length = data->length/4;
+ int plt = *d;
+ d++;
+ int length = (data->length/4)-1;
DdbListviewIter drop_before = it;
// find last selected
while (drop_before && ps->binding->is_selected (drop_before)) {
@@ -902,7 +905,7 @@ ddb_listview_list_drag_data_received (GtkWidget *widget,
UNREF (drop_before);
drop_before = next;
}
- ps->binding->drag_n_drop (drop_before, d, length);
+ ps->binding->drag_n_drop (drop_before, plt, d, length);
if (drop_before) {
UNREF (drop_before);
}
@@ -1561,6 +1564,7 @@ ddb_listview_list_mousemove (DdbListview *ps, GdkEventMotion *ev, int ex, int ey
GtkWidget *widget = ps->list;
if (gtk_drag_check_threshold (widget, ps->lastpos[0], ex, ps->lastpos[1], ey)) {
ps->dragwait = 0;
+ ps->drag_source_playlist = deadbeef->plt_get_curr ();
GtkTargetEntry entry = {
.target = "STRING",
.flags = GTK_TARGET_SAME_WIDGET,
diff --git a/plugins/gtkui/ddblistview.h b/plugins/gtkui/ddblistview.h
index eb103354..cdf7517f 100644
--- a/plugins/gtkui/ddblistview.h
+++ b/plugins/gtkui/ddblistview.h
@@ -68,7 +68,7 @@ typedef struct {
int (*get_group) (DdbListviewIter it, char *str, int size);
// drag-n-drop
- void (*drag_n_drop) (DdbListviewIter before, uint32_t *indices, int length);
+ void (*drag_n_drop) (DdbListviewIter before, int playlist, uint32_t *indices, int length);
void (*external_drag_n_drop) (DdbListviewIter before, char *mem, int length);
// callbacks
@@ -128,6 +128,7 @@ struct _DdbListview {
int areaselect; // boolean, whether area selection is active (1), or not (0)
int areaselect_y; // pixel-coordinate of anchor click relative to playlist origin
int dragwait;
+ int drag_source_playlist;
int shift_sel_anchor;
// header
diff --git a/plugins/gtkui/ddbtabstrip.c b/plugins/gtkui/ddbtabstrip.c
index de5a3231..8d9b6675 100644
--- a/plugins/gtkui/ddbtabstrip.c
+++ b/plugins/gtkui/ddbtabstrip.c
@@ -16,6 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <gtk/gtk.h>
#include <string.h>
#include "ddbtabstrip.h"
#include "drawing.h"
@@ -28,58 +29,65 @@ G_DEFINE_TYPE (DdbTabStrip, ddb_tabstrip, GTK_TYPE_WIDGET);
static void
ddb_tabstrip_send_configure (DdbTabStrip *darea)
{
- GtkWidget *widget;
- GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
-
- widget = GTK_WIDGET (darea);
-
- event->configure.window = g_object_ref (widget->window);
- event->configure.send_event = TRUE;
- event->configure.x = widget->allocation.x;
- event->configure.y = widget->allocation.y;
- event->configure.width = widget->allocation.width;
- event->configure.height = widget->allocation.height;
-
- gtk_widget_event (widget, event);
- gdk_event_free (event);
+ GtkWidget *widget;
+ GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
+
+ widget = GTK_WIDGET (darea);
+
+ event->configure.window = g_object_ref (widget->window);
+ event->configure.send_event = TRUE;
+ event->configure.x = widget->allocation.x;
+ event->configure.y = widget->allocation.y;
+ event->configure.width = widget->allocation.width;
+ event->configure.height = widget->allocation.height;
+
+ gtk_widget_event (widget, event);
+ gdk_event_free (event);
}
static void
ddb_tabstrip_realize (GtkWidget *widget) {
- DdbTabStrip *darea = DDB_TABSTRIP (widget);
- GdkWindowAttr attributes;
- gint attributes_mask;
+ DdbTabStrip *darea = DDB_TABSTRIP (widget);
+ GdkWindowAttr attributes;
+ gint attributes_mask;
- if (GTK_WIDGET_NO_WINDOW (widget))
+ if (GTK_WIDGET_NO_WINDOW (widget))
{
- GTK_WIDGET_CLASS (ddb_tabstrip_parent_class)->realize (widget);
+ GTK_WIDGET_CLASS (ddb_tabstrip_parent_class)->realize (widget);
}
- else
+ else
{
- GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.x = widget->allocation.x;
- attributes.y = widget->allocation.y;
- attributes.width = widget->allocation.width;
- attributes.height = widget->allocation.height;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.colormap = gtk_widget_get_colormap (widget);
- attributes.event_mask = gtk_widget_get_events (widget);
- attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
-
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-
- widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
- &attributes, attributes_mask);
- gdk_window_set_user_data (widget->window, darea);
-
- widget->style = gtk_style_attach (widget->style, widget->window);
- gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (widget->window, darea);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
}
- ddb_tabstrip_send_configure (DDB_TABSTRIP (widget));
+ ddb_tabstrip_send_configure (DDB_TABSTRIP (widget));
+ GtkTargetEntry entry = {
+ .target = "STRING",
+ .flags = GTK_TARGET_SAME_WIDGET | GTK_TARGET_OTHER_APP,
+ 0
+ };
+ gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY);
+ gtk_drag_dest_set_track_motion (widget, TRUE);
}
static void
@@ -122,6 +130,13 @@ gboolean
on_tabstrip_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event);
+gboolean
+on_tabstrip_drag_motion_event (GtkWidget *widget,
+ GdkDragContext *drag_context,
+ gint x,
+ gint y,
+ guint time);
+
static void
ddb_tabstrip_destroy(GtkObject *object)
{
@@ -156,6 +171,7 @@ ddb_tabstrip_class_init(DdbTabStripClass *class)
widget_class->button_release_event = on_tabstrip_button_release_event;
widget_class->configure_event = on_tabstrip_configure_event;
widget_class->motion_notify_event = on_tabstrip_motion_notify_event;
+ widget_class->drag_motion = on_tabstrip_drag_motion_event;
object_class->destroy = ddb_tabstrip_destroy;
}
@@ -553,6 +569,21 @@ on_tabstrip_motion_notify_event (GtkWidget *widget,
return FALSE;
}
+gboolean
+on_tabstrip_drag_motion_event (GtkWidget *widget,
+ GdkDragContext *drag_context,
+ gint x,
+ gint y,
+ guint time)
+{
+ int tab = get_tab_under_cursor (x);
+ if (tab != -1) {
+ deadbeef->plt_set_curr (tab);
+ deadbeef->conf_set_int ("playlist.current", tab);
+ }
+ return FALSE;
+}
+
void
on_rename_playlist1_activate (GtkMenuItem *menuitem,
gpointer user_data)
diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c
index 1815d0aa..4e8ddd93 100644
--- a/plugins/gtkui/mainplaylist.c
+++ b/plugins/gtkui/mainplaylist.c
@@ -98,8 +98,16 @@ int main_get_idx (DdbListviewIter it) {
return idx;
}
-void main_drag_n_drop (DdbListviewIter before, uint32_t *indices, int length) {
- deadbeef->pl_move_items (PL_MAIN, (DB_playItem_t *)before, indices, length);
+void main_drag_n_drop (DdbListviewIter before, int playlist, uint32_t *indices, int length) {
+ deadbeef->plt_lock ();
+ int curr = deadbeef->plt_get_curr ();
+ if (playlist == curr) {
+ deadbeef->pl_move_items (PL_MAIN, (DB_playItem_t *)before, indices, length);
+ }
+ else {
+ deadbeef->pl_copy_items (PL_MAIN, playlist, (DB_playItem_t *)before, indices, length);
+ }
+ deadbeef->plt_unlock ();
}
void main_external_drag_n_drop (DdbListviewIter before, char *mem, int length) {