diff options
-rw-r--r-- | deadbeef.h | 3 | ||||
-rw-r--r-- | playlist.c | 148 | ||||
-rw-r--r-- | playlist.h | 5 | ||||
-rw-r--r-- | plugins.c | 3 | ||||
-rw-r--r-- | plugins/gtkui/gtkplaylist.c | 156 | ||||
-rw-r--r-- | plugins/gtkui/gtkplaylist.h | 2 |
6 files changed, 237 insertions, 80 deletions
@@ -268,7 +268,7 @@ typedef struct { DB_playItem_t *(*pl_get_last) (int iter); DB_playItem_t *(*pl_get_next) (DB_playItem_t *it, int iter); DB_playItem_t *(*pl_get_prev) (DB_playItem_t *it, int iter); - int (*pl_format_title) (DB_playItem_t *it, char *s, int size, const char *fmt); + int (*pl_format_title) (DB_playItem_t *it, char *s, int size, int id, const char *fmt); void (*pl_format_item_display_name) (DB_playItem_t *it, char *str, int len); // void (*pl_set_next) (DB_playItem_t *it, DB_playItem_t *next, int iter); // void (*pl_set_prev) (DB_playItem_t *it, DB_playItem_t *prev, int iter); @@ -284,6 +284,7 @@ typedef struct { void (*pl_delete_all_meta) (DB_playItem_t *it); void (*pl_set_item_duration) (DB_playItem_t *it, float duration); float (*pl_get_item_duration) (DB_playItem_t *it); + void (*pl_sort) (int id, const char *format, int ascending); // cuesheet support DB_playItem_t *(*pl_insert_cue_from_buffer) (DB_playItem_t *after, const char *fname, const uint8_t *buffer, int buffersize, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate); DB_playItem_t * (*pl_insert_cue) (DB_playItem_t *after, const char *filename, struct DB_decoder_s *decoder, const char *ftype, int numsamples, int samplerate); @@ -1577,7 +1577,75 @@ pl_get_item_duration (playItem_t *it) { } int -pl_format_title (playItem_t *it, char *s, int size, const char *fmt) { +pl_format_title (playItem_t *it, char *s, int size, int id, const char *fmt) { + if (id != -1) { + char dur[50]; + //pl_format_title (it, dur, sizeof (dur), "%l"); + //char dur[50]; + if (it->_duration >= 0) { + int hourdur = it->_duration / (60 * 60); + int mindur = (it->_duration - hourdur * 60 * 60) / 60; + int secdur = it->_duration - hourdur*60*60 - mindur * 60; + + if (hourdur) { + snprintf (dur, sizeof (dur), "%d:%02d:%02d", hourdur, mindur, secdur); + } + else { + snprintf (dur, sizeof (dur), "%d:%02d", mindur, secdur); + } + } + else { + strcpy (dur, "-:--"); + } + + const char *artist = pl_find_meta (it, "artist"); + if (!artist) { + artist = "?"; + } + const char *album = pl_find_meta (it, "album"); + if (!album) { + album = "?"; + } + const char *track = pl_find_meta (it, "track"); + if (!track) { + track = ""; + } + const char *title = pl_find_meta (it, "title"); + if (!title) { + title = "?"; + } + char artistalbum[1024]; + snprintf (artistalbum, sizeof (artistalbum), "%s - %s", artist, album); + const char *text = NULL; + switch (id) { + case DB_COLUMN_ARTIST_ALBUM: + text = artistalbum; + break; + case DB_COLUMN_ARTIST: + text = artist; + break; + case DB_COLUMN_ALBUM: + text = album; + break; + case DB_COLUMN_TITLE: + text = title; + break; + case DB_COLUMN_DURATION: + text = dur; + break; + case DB_COLUMN_TRACK: + text = track; + break; + } + if (text) { + strncpy (s, text, size); + return strlen (s); + } + else { + s[0] = 0; + } + return 0; + } int n = size-1; while (*fmt && n) { if (*fmt != '%') { @@ -1649,7 +1717,83 @@ pl_format_title (playItem_t *it, char *s, int size, const char *fmt) { } void -pl_sort (const char *meta) { +pl_sort (int id, const char *format, int ascending) { + int sorted = 0; + int iter = 0; + do { +// printf ("iter: %d\n", iter); + sorted = 1; + playItem_t *it; + playItem_t *next = NULL; + for (it = playlist_head[PL_MAIN]; it; it = it->next[PL_MAIN]) { + playItem_t *next = it->next[PL_MAIN]; + if (!next) { + break; + } + char title1[1024]; + char title2[1024]; + pl_format_title (it, title1, sizeof (title1), id, format); + pl_format_title (next, title2, sizeof (title2), id, format); +// const char *meta1 = pl_find_meta (it, meta); +// const char *meta2 = pl_find_meta (next, meta); + int cmp = ascending ? strcmp (title1, title2) < 0 : strcmp (title1, title2) > 0; + if (cmp) { +// printf ("%p %p swapping %s and %s\n", it, next, meta1, meta2); + sorted = 0; + // swap them + if (it->prev[PL_MAIN]) { + it->prev[PL_MAIN]->next[PL_MAIN] = next; +// printf ("it->prev->next = it->next\n"); + } + else { + playlist_head[PL_MAIN] = next; + next->prev[PL_MAIN] = NULL; +// printf ("head = it->next\n"); + } + if (next->next[PL_MAIN]) { + next->next[PL_MAIN]->prev[PL_MAIN] = it; +// printf ("it->next->next->prev = it\n"); + } + else { + playlist_tail[PL_MAIN] = it; + it->next[PL_MAIN] = NULL; +// printf ("tail = it\n"); + } + playItem_t *it_prev = it->prev[PL_MAIN]; + it->next[PL_MAIN] = next->next[PL_MAIN]; + it->prev[PL_MAIN] = next; + next->next[PL_MAIN] = it; + next->prev[PL_MAIN] = it_prev; + it = next; +// if (iter >= 10) { +// exit (0); +// } + } +#if 0 + else { + printf ("%p %p NOT swapping %s and %s\n", it, next, meta1, meta2); + } +#endif +#if 0 + // print list + int k = 0; + playItem_t *p = NULL; + for (playItem_t *i = playlist_head[PL_MAIN]; i; p = i, i = i->next[PL_MAIN], k++) { + printf ("%p ", i); + if (i->prev[PL_MAIN] != p) { + printf ("\n\033[0;33mbroken link, i=%p, i->prev=%p, prev=%p\033[37;0m\n", i, i->prev[PL_MAIN], p); + } + if (k > 20) { + printf ("\033[0;31mlist corrupted\033[37;0m\n"); + return; + } + } + printf ("\n"); +#endif + } + iter++; + } while (!sorted); +// printf ("sorted in %d iterations\n", iter); } void @@ -170,7 +170,7 @@ pl_get_item_duration (playItem_t *it); // returns number of characters printed, not including trailing 0 // [a]rtist, [t]itle, al[b]um, [l]ength, track[n]umber int -pl_format_title (playItem_t *it, char *s, int size, const char *fmt); +pl_format_title (playItem_t *it, char *s, int size, int id, const char *fmt); void pl_reset_cursor (void); @@ -211,4 +211,7 @@ pl_move_items (int iter, playItem_t *drop_before, uint32_t *indexes, int count); int pl_process_search (const char *text); +void +pl_sort (int id, const char *format, int ascending); + #endif // __PLAYLIST_H @@ -100,6 +100,7 @@ static DB_functions_t deadbeef_api = { .pl_get_for_idx_and_iter = (DB_playItem_t * (*) (int idx, int iter))pl_get_for_idx_and_iter, .pl_set_item_duration = (void (*) (DB_playItem_t *it, float duration))pl_set_item_duration, .pl_get_item_duration = (float (*) (DB_playItem_t *it))pl_get_item_duration, + .pl_sort = pl_sort, .pl_get_totaltime = pl_get_totaltime, .pl_getcount = pl_getcount, .pl_getcurrent = (DB_playItem_t *(*)(void))pl_getcurrent, @@ -118,7 +119,7 @@ static DB_functions_t deadbeef_api = { .pl_get_last = (DB_playItem_t *(*) (int))pl_get_last, .pl_get_next = (DB_playItem_t *(*) (DB_playItem_t *, int))pl_get_next, .pl_get_prev = (DB_playItem_t *(*) (DB_playItem_t *, int))pl_get_prev, - .pl_format_title = (int (*) (DB_playItem_t *it, char *s, int size, const char *fmt))pl_format_title, + .pl_format_title = (int (*) (DB_playItem_t *it, 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_process_search = pl_process_search, diff --git a/plugins/gtkui/gtkplaylist.c b/plugins/gtkui/gtkplaylist.c index 12f7496c..69a3d866 100644 --- a/plugins/gtkui/gtkplaylist.c +++ b/plugins/gtkui/gtkplaylist.c @@ -383,28 +383,6 @@ gtkpl_draw_pl_row (gtkplaylist_t *ps, int row, DB_playItem_t *it) { } theme_set_fg_color (COLO_PLAYLIST_TEXT); } - // draw as columns - char dur[50]; - deadbeef->pl_format_title (it, dur, sizeof (dur), "%l"); - - const char *artist = deadbeef->pl_find_meta (it, "artist"); - if (!artist) { - artist = "?"; - } - const char *album = deadbeef->pl_find_meta (it, "album"); - if (!album) { - album = "?"; - } - const char *track = deadbeef->pl_find_meta (it, "track"); - if (!track) { - track = ""; - } - const char *title = deadbeef->pl_find_meta (it, "title"); - if (!title) { - title = "?"; - } - char artistalbum[1024]; - deadbeef->pl_format_title (it, artistalbum, sizeof (artistalbum), "%a - %b"); int x = -ps->hscrollpos; gtkpl_column_t *c; for (c = ps->columns; c; c = c->next) { @@ -424,34 +402,9 @@ gtkpl_draw_pl_row (gtkplaylist_t *ps, int row, DB_playItem_t *it) { draw_pixbuf ((uintptr_t)ps->backbuf, pixbuf, x + c->width/2 - 8 - ps->hscrollpos, (row - ps->scrollpos) * rowheight + rowheight/2 - 8, 0, 0, 16, 16); } else { - char fmt_text[1024]; - const char *text = NULL; - if (c->id != -1) { - switch (c->id) { - case DB_COLUMN_ARTIST_ALBUM: - text = artistalbum; - break; - case DB_COLUMN_ARTIST: - text = artist; - break; - case DB_COLUMN_ALBUM: - text = album; - break; - case DB_COLUMN_TITLE: - text = title; - break; - case DB_COLUMN_DURATION: - text = dur; - break; - case DB_COLUMN_TRACK: - text = track; - break; - } - } - else if (c->format) { - deadbeef->pl_format_title (it, fmt_text, sizeof (fmt_text), c->format); - text = fmt_text; - } + char text[1024]; + deadbeef->pl_format_title (it, text, sizeof (text), c->id, c->format); + if (text) { if (c->align_right) { draw_text_with_colors (x+5, row * rowheight - ps->scrollpos * rowheight + rowheight/2 - draw_get_font_size ()/2 - 2, c->width-10, 1, text); @@ -1276,12 +1229,24 @@ gtkpl_header_draw (gtkplaylist_t *ps) { if (xx >= widget->allocation.width) { continue; } + int arrow_sz = 10; if (w > 0) { gtk_paint_vline (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, NULL, NULL, NULL, 2, h-4, xx+w - 2); GdkColor *gdkfg = &widget->style->fg[0]; float fg[3] = {(float)gdkfg->red/0xffff, (float)gdkfg->green/0xffff, (float)gdkfg->blue/0xffff}; draw_set_fg_color (fg); - draw_text (xx + 5, h/2-draw_get_font_size()/2, c->width-10, 0, c->title); + int w = c->width-10; + if (c->sort_order) { + w -= arrow_sz; + if (w < 0) { + w = 0; + } + } + draw_text (xx + 5, h/2-draw_get_font_size()/2, w, 0, c->title); + } + if (c->sort_order != 0) { + int dir = c->sort_order == 1 ? GTK_ARROW_DOWN : GTK_ARROW_UP; + gtk_paint_arrow (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, widget, NULL, dir, TRUE, xx + c->width-arrow_sz-5, widget->allocation.height/2-arrow_sz/2, arrow_sz, arrow_sz); } } else { @@ -1318,7 +1283,6 @@ gtkpl_header_draw (gtkplaylist_t *ps) { GdkColor *gdkfg = &widget->style->fg[GTK_STATE_SELECTED]; float fg[3] = {(float)gdkfg->red/0xffff, (float)gdkfg->green/0xffff, (float)gdkfg->blue/0xffff}; draw_set_fg_color (fg); - draw_text (x + 5, h/2-draw_get_font_size()/2, c->width-10, 0, c->title); } break; } @@ -1367,8 +1331,9 @@ on_header_realize (GtkWidget *widget, cursor_drag = gdk_cursor_new (GDK_FLEUR); } -float last_header_motion_ev = -1; -int prev_header_x = -1; +static float last_header_motion_ev = -1; +static int prev_header_x = -1; +static int header_prepare = 0; gboolean on_header_motion_notify_event (GtkWidget *widget, @@ -1376,7 +1341,12 @@ on_header_motion_notify_event (GtkWidget *widget, gpointer user_data) { GTKPL_PROLOGUE; - if (header_dragging >= 0) { + if ((event->state & GDK_BUTTON1_MASK) && header_prepare) { + if (gtk_drag_check_threshold (widget, event->x, prev_header_x, 0, 0)) { + header_prepare = 0; + } + } + if (!header_prepare && header_dragging >= 0) { gdk_window_set_cursor (widget->window, cursor_drag); gtkpl_column_t *c; int i; @@ -1512,9 +1482,12 @@ on_header_button_press_event (GtkWidget *widget, break; } else if (event->x > x + 2 && event->x < x + w - 2) { + // prepare to drag or sort header_dragpt[0] = event->x - x; + header_prepare = 1; header_dragging = i; header_sizing = -1; + prev_header_x = event->x; break; } x += w; @@ -1536,28 +1509,63 @@ on_header_button_release_event (GtkWidget *widget, { GTKPL_PROLOGUE; if (event->button == 1) { - header_sizing = -1; - int x = 0; - gtkpl_column_t *c; - for (c = ps->columns; c; c = c->next) { - int w = c->width; - if (event->x >= x + w - 2 && event->x <= x + w) { - gdk_window_set_cursor (widget->window, cursor_sz); - break; - } - else { - gdk_window_set_cursor (widget->window, NULL); - } - x += w; - } - if (header_dragging >= 0) { + if (header_prepare) { + header_sizing = -1; header_dragging = -1; - gtkpl_setup_hscrollbar (ps); + header_prepare = 0; + // sort + gtkpl_column_t *c; + int i = 0; + int x = -ps->hscrollpos; + int sorted = 0; + for (c = ps->columns; c; c = c->next, i++) { + int w = c->width; + if (event->x > x + 2 && event->x < x + w - 2) { + if (!c->sort_order) { + c->sort_order = 1; + } + else if (c->sort_order == 1) { + c->sort_order = 2; + } + else if (c->sort_order == 2) { + c->sort_order = 1; + } + deadbeef->pl_sort (c->id, c->format, c->sort_order-1); + sorted = 1; + } + else { + c->sort_order = 0; + } + x += w; + } + playlist_refresh (); gtkpl_header_draw (ps); gtkpl_expose_header (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height); - gtkpl_draw_playlist (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height); - gtkpl_expose (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height); - gtkpl_column_rewrite_config (ps); + } + else { + header_sizing = -1; + int x = 0; + gtkpl_column_t *c; + for (c = ps->columns; c; c = c->next) { + int w = c->width; + if (event->x >= x + w - 2 && event->x <= x + w) { + gdk_window_set_cursor (widget->window, cursor_sz); + break; + } + else { + gdk_window_set_cursor (widget->window, NULL); + } + x += w; + } + if (header_dragging >= 0) { + header_dragging = -1; + gtkpl_setup_hscrollbar (ps); + gtkpl_header_draw (ps); + gtkpl_expose_header (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height); + gtkpl_draw_playlist (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height); + gtkpl_expose (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height); + gtkpl_column_rewrite_config (ps); + } } } return FALSE; diff --git a/plugins/gtkui/gtkplaylist.h b/plugins/gtkui/gtkplaylist.h index 5d149c51..430f112a 100644 --- a/plugins/gtkui/gtkplaylist.h +++ b/plugins/gtkui/gtkplaylist.h @@ -57,7 +57,7 @@ typedef struct gtkpl_column_s { int movepos; // valid only while `moving' is 1 struct gtkpl_column_s *next; unsigned align_right : 1; -// unsigned moving : 1; + unsigned sort_order : 2; // 0=none, 1=asc, 2=desc } gtkpl_column_t; // structure of this kind must be set as user data for playlist, header and scrollbar widgets |