summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deadbeef.h3
-rw-r--r--playlist.c148
-rw-r--r--playlist.h5
-rw-r--r--plugins.c3
-rw-r--r--plugins/gtkui/gtkplaylist.c156
-rw-r--r--plugins/gtkui/gtkplaylist.h2
6 files changed, 237 insertions, 80 deletions
diff --git a/deadbeef.h b/deadbeef.h
index aca8992d..c87de95f 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -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);
diff --git a/playlist.c b/playlist.c
index 857bffff..68af5381 100644
--- a/playlist.c
+++ b/playlist.c
@@ -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
diff --git a/playlist.h b/playlist.h
index ec2b8ecd..5a4d5208 100644
--- a/playlist.h
+++ b/playlist.h
@@ -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
diff --git a/plugins.c b/plugins.c
index 5c3e6fb4..6f91d140 100644
--- a/plugins.c
+++ b/plugins.c
@@ -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