From 3e353f8d1a41585b4715eaf0dfeed057b8a23b15 Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Sun, 4 Apr 2010 13:32:15 +0200 Subject: implemented dragndrop between different playlists --- deadbeef.h | 5 ++ playlist.c | 71 ++++++++++++++++++++++++++ playlist.h | 9 ++++ plugins.c | 5 ++ plugins/gtkui/ddblistview.c | 18 ++++--- plugins/gtkui/ddblistview.h | 3 +- plugins/gtkui/ddbtabstrip.c | 115 +++++++++++++++++++++++++++---------------- plugins/gtkui/mainplaylist.c | 12 ++++- 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"); @@ -2548,6 +2581,44 @@ pl_move_items (int iter, playItem_t *drop_before, uint32_t *indexes, int count) GLOBAL_UNLOCK; } +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; 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); @@ -265,6 +271,9 @@ pl_set_cursor (int iter, int cursor); 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); 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 #include #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) { -- cgit v1.2.3