summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--callbacks.c47
-rw-r--r--conf.c51
-rw-r--r--conf.h7
-rw-r--r--deadbeef.h11
-rw-r--r--gtkplaylist.c338
-rw-r--r--gtkplaylist.h45
-rw-r--r--main.c2
-rw-r--r--playlist.c73
-rw-r--r--playlist.h6
-rw-r--r--session.c93
10 files changed, 564 insertions, 109 deletions
diff --git a/callbacks.c b/callbacks.c
index abf970fc..23bf56d0 100644
--- a/callbacks.c
+++ b/callbacks.c
@@ -56,6 +56,7 @@ void
main_playlist_init (GtkWidget *widget) {
// init playlist control structure, and put it into widget user-data
memset (&main_playlist, 0, sizeof (main_playlist));
+ main_playlist.title = "playlist";
main_playlist.playlist = widget;
main_playlist.header = lookup_widget (mainwin, "header");
main_playlist.scrollbar = lookup_widget (mainwin, "playscroll");
@@ -69,10 +70,26 @@ main_playlist_init (GtkWidget *widget) {
main_playlist.row = -1;
main_playlist.clicktime = -1;
main_playlist.nvisiblerows = 0;
- //main_playlist.fmtcache = NULL;
-// int colwidths[pl_ncolumns] = { 50, 150, 50, 150, 50 };
-// memcpy (main_playlist.colwidths, colwidths, sizeof (colwidths));
- main_playlist.colwidths = session_get_main_colwidths_ptr ();
+
+// FIXME: on 1st run, copy colwidths to new columns
+// main_playlist.colwidths = session_get_main_colwidths_ptr ();
+
+ DB_conf_item_t *col = conf_find ("playlist.column.", NULL);
+ if (!col) {
+ // create default set of columns
+ gtkpl_column_append (&main_playlist, gtkpl_column_alloc ("Playing", 50, DB_COLUMN_PLAYING, NULL, 0));
+ gtkpl_column_append (&main_playlist, gtkpl_column_alloc ("Artist / Album", 150, DB_COLUMN_ARTIST_ALBUM, NULL, 0));
+ gtkpl_column_append (&main_playlist, gtkpl_column_alloc ("Track №", 50, DB_COLUMN_TRACK, NULL, 1));
+ gtkpl_column_append (&main_playlist, gtkpl_column_alloc ("Title / Track Artist", 150, DB_COLUMN_TITLE, NULL, 0));
+ gtkpl_column_append (&main_playlist, gtkpl_column_alloc ("Duration", 50, DB_COLUMN_DURATION, NULL, 0));
+ }
+ else {
+ while (col) {
+ gtkpl_append_column_from_textdef (&main_playlist, col->value);
+ col = conf_find ("playlist.column.", col);
+ }
+ }
+
gtk_object_set_data (GTK_OBJECT (main_playlist.playlist), "ps", &main_playlist);
gtk_object_set_data (GTK_OBJECT (main_playlist.header), "ps", &main_playlist);
gtk_object_set_data (GTK_OBJECT (main_playlist.scrollbar), "ps", &main_playlist);
@@ -84,6 +101,7 @@ search_playlist_init (GtkWidget *widget) {
extern GtkWidget *searchwin;
// init playlist control structure, and put it into widget user-data
memset (&search_playlist, 0, sizeof (search_playlist));
+ search_playlist.title = "search";
search_playlist.playlist = widget;
search_playlist.header = lookup_widget (searchwin, "searchheader");
search_playlist.scrollbar = lookup_widget (searchwin, "searchscroll");
@@ -99,10 +117,23 @@ search_playlist_init (GtkWidget *widget) {
search_playlist.row = -1;
search_playlist.clicktime = -1;
search_playlist.nvisiblerows = 0;
- //search_playlist.fmtcache = NULL;
-// int colwidths[pl_ncolumns] = { 0, 150, 50, 150, 50 };
-// memcpy (search_playlist.colwidths, colwidths, sizeof (colwidths));
- search_playlist.colwidths = session_get_search_colwidths_ptr ();
+
+// FIXME: port to new columns
+// search_playlist.colwidths = session_get_search_colwidths_ptr ();
+ // create default set of columns
+ DB_conf_item_t *col = conf_find ("search.column.", NULL);
+ if (!col) {
+ gtkpl_column_append (&search_playlist, gtkpl_column_alloc ("Artist / Album", 150, DB_COLUMN_ARTIST_ALBUM, NULL, 0));
+ gtkpl_column_append (&search_playlist, gtkpl_column_alloc ("Track №", 50, DB_COLUMN_TRACK, NULL, 1));
+ gtkpl_column_append (&search_playlist, gtkpl_column_alloc ("Title / Track Artist", 150, DB_COLUMN_TITLE, NULL, 0));
+ gtkpl_column_append (&search_playlist, gtkpl_column_alloc ("Duration", 50, DB_COLUMN_DURATION, NULL, 0));
+ }
+ else {
+ while (col) {
+ gtkpl_append_column_from_textdef (&search_playlist, col->value);
+ col = conf_find ("search.column.", col);
+ }
+ }
gtk_object_set_data (GTK_OBJECT (search_playlist.playlist), "ps", &search_playlist);
gtk_object_set_data (GTK_OBJECT (search_playlist.header), "ps", &search_playlist);
gtk_object_set_data (GTK_OBJECT (search_playlist.scrollbar), "ps", &search_playlist);
diff --git a/conf.c b/conf.c
index f45eabd5..912db783 100644
--- a/conf.c
+++ b/conf.c
@@ -66,6 +66,8 @@ conf_load (void) {
}
*p = 0;
// new items are appended, to preserve order
+ conf_set_str (str, value);
+#if 0
DB_conf_item_t *it = malloc (sizeof (DB_conf_item_t));
memset (it, 0, sizeof (DB_conf_item_t));
it->key = strdup (str);
@@ -77,6 +79,7 @@ conf_load (void) {
tail->next = it;
}
tail = it;
+#endif
}
fclose (fp);
changed = 0;
@@ -105,8 +108,19 @@ conf_free (void) {
DB_conf_item_t *next = NULL;
for (DB_conf_item_t *it = conf_items; it; it = next) {
next = it->next;
- free (it->key);
- free (it->value);
+ conf_item_free (it);
+ }
+}
+
+void
+conf_item_free (DB_conf_item_t *it) {
+ if (it) {
+ if (it->key) {
+ free (it->key);
+ }
+ if (it->value) {
+ free (it->value);
+ }
free (it);
}
}
@@ -147,19 +161,32 @@ conf_find (const char *group, DB_conf_item_t *prev) {
void
conf_set_str (const char *key, const char *val) {
changed = 1;
+ DB_conf_item_t *prev = NULL;
for (DB_conf_item_t *it = conf_items; it; it = it->next) {
- if (!strcasecmp (key, it->key)) {
+ int cmp = strcasecmp (key, it->key);
+ if (!cmp) {
free (it->value);
it->value = strdup (val);
return;
}
+ else if (cmp < 0) {
+ break;
+ }
+ prev = it;
}
DB_conf_item_t *it = malloc (sizeof (DB_conf_item_t));
memset (it, 0, sizeof (DB_conf_item_t));
- it->next = conf_items;
it->key = strdup (key);
it->value = strdup (val);
- conf_items = it;
+ if (prev) {
+ DB_conf_item_t *next = prev->next;
+ prev->next = it;
+ it->next = next;
+ }
+ else {
+ it->next = conf_items;
+ conf_items = it;
+ }
}
void
@@ -185,3 +212,17 @@ void
conf_setchanged (int c) {
changed = c;
}
+
+void
+conf_remove_items (const char *key) {
+ int l = strlen (key);
+ DB_conf_item_t *it = conf_find (key, NULL);
+ while (it) {
+ DB_conf_item_t *next = it->next;
+ conf_item_free (it);
+ it = next;
+ if (strncasecmp (key, it->key, l)) {
+ break;
+ }
+ }
+}
diff --git a/conf.h b/conf.h
index bce7572c..0a76aaa2 100644
--- a/conf.h
+++ b/conf.h
@@ -56,4 +56,11 @@ conf_set_float (const char *key, float val);
DB_conf_item_t *
conf_find (const char *group, DB_conf_item_t *prev);
+// remove all items starting with key
+void
+conf_remove_items (const char *key);
+
+void
+conf_item_free (DB_conf_item_t *it);
+
#endif // __CONF_H
diff --git a/deadbeef.h b/deadbeef.h
index bc1a7d6e..e10029d5 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -118,6 +118,17 @@ enum {
DB_EV_MAX
};
+// preset columns, working using IDs
+enum {
+ DB_COLUMN_PLAYING = 1,
+ DB_COLUMN_ARTIST_ALBUM = 2,
+ DB_COLUMN_ARTIST = 3,
+ DB_COLUMN_ALBUM = 4,
+ DB_COLUMN_TITLE = 5,
+ DB_COLUMN_DURATION = 6,
+ DB_COLUMN_TRACK = 7
+};
+
// message ids for communicating with player
enum {
M_SONGFINISHED,
diff --git a/gtkplaylist.c b/gtkplaylist.c
index 4564e5b4..5d640c87 100644
--- a/gtkplaylist.c
+++ b/gtkplaylist.c
@@ -28,6 +28,7 @@
#include <assert.h>
#include <unistd.h>
#include <ctype.h>
+#include <assert.h>
#include "gtkplaylist.h"
#include "callbacks.h"
#include "interface.h"
@@ -43,6 +44,7 @@
#include "drawing.h"
#include "session.h"
#include "deadbeef.h"
+#include "conf.h"
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -84,6 +86,7 @@ float colo_current[COLO_COUNT][3];
// playlist row height
int rowheight = -1;
+#if 0
const char *colnames[pl_ncolumns] = {
"Playing",
"Artist / Album",
@@ -91,6 +94,7 @@ const char *colnames[pl_ncolumns] = {
"Title / Track Artist",
"Duration"
};
+#endif
static uintptr_t play16_pixbuf;
static uintptr_t pause16_pixbuf;
@@ -107,6 +111,15 @@ gtkpl_init (void) {
}
void
+gtkpl_free (gtkplaylist_t *pl) {
+ while (pl->columns) {
+ gtkpl_column_t *next = pl->columns->next;
+ gtkpl_column_free (pl->columns);
+ pl->columns = next;
+ }
+}
+
+void
theme_set_cairo_source_rgb (cairo_t *cr, int col) {
cairo_set_source_rgb (cr, colo_current[col][0], colo_current[col][1], colo_current[col][2]);
}
@@ -154,8 +167,9 @@ gtkpl_setup_hscrollbar (gtkplaylist_t *ps) {
int w = playlist->allocation.width;
int size = 0;
int i;
- for (i = 0; i < pl_ncolumns; i++) {
- size += ps->colwidths[i];
+ gtkpl_column_t *c;
+ for (c = ps->columns; c; c = c->next) {
+ size += c->width;
}
if (w >= size) {
size = 0;
@@ -240,10 +254,10 @@ gtkpl_draw_pl_row (gtkplaylist_t *ps, int row, playItem_t *it) {
}
int width, height;
draw_get_canvas_size ((uintptr_t)ps->backbuf, &width, &height);
- if (it == playlist_current_ptr && ps->colwidths[0] > 0 && !p_isstopped ()) {
- uintptr_t pixbuf = p_ispaused () ? pause16_pixbuf : play16_pixbuf;
- draw_pixbuf ((uintptr_t)ps->backbuf, pixbuf, ps->colwidths[0]/2-8-ps->hscrollpos, (row - ps->scrollpos) * rowheight + rowheight/2 - 8, 0, 0, 16, 16);
- }
+// if (it == playlist_current_ptr && ps->colwidths[0] > 0 && !p_isstopped ()) {
+// uintptr_t pixbuf = p_ispaused () ? pause16_pixbuf : play16_pixbuf;
+// draw_pixbuf ((uintptr_t)ps->backbuf, pixbuf, ps->colwidths[0]/2-8-ps->hscrollpos, (row - ps->scrollpos) * rowheight + rowheight/2 - 8, 0, 0, 16, 16);
+// }
if (it && ((it->selected && ps->multisel) || (row == ps->row && !ps->multisel))) {
if (row % 2) {
theme_set_bg_color (COLO_PLAYLIST_SEL_EVEN);
@@ -263,16 +277,9 @@ gtkpl_draw_pl_row (gtkplaylist_t *ps, int row, playItem_t *it) {
theme_set_fg_color (COLO_PLAYLIST_TEXT);
}
// draw as columns
- char dur[10] = "-:--";
- if (it) {
- if (it->_duration >= 0) {
- int min = (int)it->_duration/60;
- int sec = (int)(it->_duration-min*60);
- snprintf (dur, 10, "%d:%02d", min, sec);
- }
- }
+ char dur[50];
+ pl_format_title (it, dur, sizeof (dur), "%l");
- char artistalbum[1024];
const char *artist = pl_find_meta (it, "artist");
if (!artist) {
artist = "?";
@@ -289,7 +296,9 @@ gtkpl_draw_pl_row (gtkplaylist_t *ps, int row, playItem_t *it) {
if (!title) {
title = "?";
}
- snprintf (artistalbum, 1024, "%s - %s", artist, album);
+ char artistalbum[1024];
+ pl_format_title (it, artistalbum, sizeof (artistalbum), "%a - %b");
+#if 0
const char *columns[pl_ncolumns] = {
"",
artistalbum,
@@ -297,20 +306,53 @@ gtkpl_draw_pl_row (gtkplaylist_t *ps, int row, playItem_t *it) {
title,
dur
};
+#endif
int x = -ps->hscrollpos;
- for (int i = 0; i < pl_ncolumns; i++) {
- if (i > 0) {
-
- int dotpos;
- int cidx = ((row-ps->scrollpos) * pl_ncolumns + i) * 3;
- if (i == 2) {
- draw_text_with_colors (x+5, row * rowheight - ps->scrollpos * rowheight + rowheight/2 - draw_get_font_size ()/2 - 2, ps->colwidths[i]-10, 1, columns[i]);
+ gtkpl_column_t *c;
+ for (c = ps->columns; c; c = c->next) {
+ if (it == playlist_current_ptr && c->id == DB_COLUMN_PLAYING && !p_isstopped ()) {
+ uintptr_t pixbuf = p_ispaused () ? pause16_pixbuf : play16_pixbuf;
+ 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 {
- draw_text_with_colors (x + 5, row * rowheight - ps->scrollpos * rowheight + rowheight/2 - draw_get_font_size ()/2 - 2, ps->colwidths[i]-10, 0, columns[i]);
+ else if (c->format) {
+ pl_format_title (it, fmt_text, sizeof (fmt_text), c->format);
+ text = fmt_text;
+ }
+ 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);
+ }
+ else {
+ draw_text_with_colors (x + 5, row * rowheight - ps->scrollpos * rowheight + rowheight/2 - draw_get_font_size ()/2 - 2, c->width-10, 0, text);
+ }
}
}
- x += ps->colwidths[i];
+ x += c->width;
}
}
@@ -1129,11 +1171,12 @@ gtkpl_header_draw (gtkplaylist_t *ps) {
// fill background
gdk_draw_rectangle (ps->backbuf_header, widget->style->bg_gc[0], TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
- for (int i = 0; i < pl_ncolumns; i++) {
+ gtkpl_column_t *c;
+ for (c = ps->columns; c; c = c->next) {
if (x >= widget->allocation.width) {
break;
}
- w = ps->colwidths[i];
+ w = c->width;
if (w > 0) {
gtk_paint_box (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, NULL, detail, x, 0, w - 2, h);
gtk_paint_vline (widget->style, ps->backbuf_header, GTK_STATE_NORMAL, NULL, NULL, NULL, 0, h, x+w - 2);
@@ -1145,16 +1188,16 @@ gtkpl_header_draw (gtkplaylist_t *ps) {
}
draw_begin ((uintptr_t)ps->backbuf_header);
x = -ps->hscrollpos;
- for (int i = 0; i < pl_ncolumns; i++) {
+ for (c = ps->columns; c; c = c->next) {
if (x >= widget->allocation.width) {
break;
}
- w = ps->colwidths[i];
+ w = c->width;
if (w > 0) {
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 (x + 5, h/2-draw_get_font_size()/2, ps->colwidths[i]-10, 0, colnames[i]);
+ draw_text (x + 5, h/2-draw_get_font_size()/2, c->width-10, 0, c->title);
}
x += w;
}
@@ -1229,22 +1272,26 @@ on_header_motion_notify_event (GtkWidget *widget,
gdk_window_set_cursor (widget->window, cursor_sz);
// get column start pos
int x = -ps->hscrollpos;
- for (int i = 0; i < header_sizing; i++) {
- int w = ps->colwidths[i];
- x += w;
+ int i = 0;
+ gtkpl_column_t *c;
+ for (c = ps->columns; c && i < header_sizing; c = c->next, i++) {
+ x += c->width;
}
+
int newx = event->x > x + 40 ? event->x : x + 40;
- ps->colwidths[header_sizing] = newx - x;
+ c->width = newx - x;
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_update_config (ps, c, i);
}
else {
int x = -ps->hscrollpos;
- for (int i = 0; i < pl_ncolumns; i++) {
- int w = ps->colwidths[i];
+ gtkpl_column_t *c;
+ for (c = ps->columns; c; c = c->next) {
+ int w = c->width;
if (w > 0) { // ignore collapsed columns (hack for search window)
if (event->x >= x + w - 2 && event->x <= x + w) {
gdk_window_set_cursor (widget->window, cursor_sz);
@@ -1276,8 +1323,10 @@ on_header_button_press_event (GtkWidget *widget,
header_dragpt[0] = event->x;
header_dragpt[1] = event->y;
int x = -ps->hscrollpos;
- for (int i = 0; i < pl_ncolumns; i++) {
- int w = ps->colwidths[i];
+ int i = 0;
+ gtkpl_column_t *c;
+ for (c = ps->columns; c; c = c->next, i++) {
+ int w = c->width;
if (event->x >= x + w - 2 && event->x <= x + w) {
header_sizing = i;
header_dragging = -1;
@@ -1303,8 +1352,9 @@ on_header_button_release_event (GtkWidget *widget,
header_dragging = -1;
header_sizing = -1;
int x = 0;
- for (int i = 0; i < pl_ncolumns; i++) {
- int w = ps->colwidths[i];
+ 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;
@@ -1418,3 +1468,209 @@ playlist_refresh (void) {
gtkpl_expose (ps, 0, 0, widget->allocation.width, widget->allocation.height);
search_refresh ();
}
+
+gtkpl_column_t *
+gtkpl_column_alloc (const char *title, int width, int id, const char *format, int align_right) {
+ gtkpl_column_t *c = malloc (sizeof (gtkpl_column_t));
+ memset (c, 0, sizeof (gtkpl_column_t));
+ c->title = strdup (title);
+ c->id = id;
+ c->format = format ? strdup (format) : NULL;
+ c->width = width;
+ c->align_right = align_right;
+ return c;
+}
+
+void
+gtkpl_column_append (gtkplaylist_t *pl, gtkpl_column_t *c) {
+ int idx = 0;
+ if (pl->columns) {
+ idx++;
+ gtkpl_column_t *tail = pl->columns;
+ while (tail->next) {
+ tail = tail->next;
+ idx++;
+ }
+ tail->next = c;
+ }
+ else {
+ pl->columns = c;
+ }
+ gtkpl_column_update_config (pl, c, idx);
+}
+
+void
+gtkpl_column_free (gtkpl_column_t *c) {
+ if (c->title) {
+ free (c->title);
+ }
+ if (c->format) {
+ free (c->format);
+ }
+ free (c);
+}
+
+void
+gtkpl_column_remove (gtkplaylist_t *pl, gtkpl_column_t *c) {
+ if (pl->columns == c) {
+ pl->columns = pl->columns->next;
+ gtkpl_column_free (c);
+ return;
+ }
+ gtkpl_column_t *cc = pl->columns;
+ while (cc) {
+ if (cc->next == c) {
+ cc->next = cc->next->next;
+ gtkpl_column_free (c);
+ return;
+ }
+ cc = cc->next;
+ }
+ assert (cc && "gtkpl: attempted to remove column that is not in list");
+}
+
+void
+gtkpl_append_column_from_textdef (gtkplaylist_t *pl, const uint8_t *def) {
+ // syntax: "title" "format" id width alignright
+ char title[128];
+ char format[128];
+ int id;
+ int width;
+ int align_right;
+ // title
+ if (*def != '"') {
+ return;
+ }
+ def++;
+ if (*def == 0) {
+ return;
+ }
+ const uint8_t *e = def;
+ e++;
+ while (*e && *e != '"') {
+ e++;
+ }
+ if (*e == 0) {
+ return;
+ }
+ memcpy (title, def, e-def);
+ title[e-def] = 0;
+ // skip whitespace
+ def = e;
+ def++;
+ while (*def && *def <= ' ') {
+ def++;
+ }
+ if (*def == 0) {
+ return;
+ }
+ // format
+ if (*def != '"') {
+ return;
+ }
+ def++;
+ if (*def == 0) {
+ return;
+ }
+ e = def;
+ while (*e && *e != '"') {
+ e++;
+ }
+ if (*e == 0) {
+ return;
+ }
+ memcpy (format, def, e-def);
+ format[e-def] = 0;
+ // skip whitespace
+ def = e;
+ def++;
+ while (*def && *def <= ' ') {
+ def++;
+ }
+ if (*def == 0) {
+ return;
+ }
+ // id
+ e = def;
+ while (*e && isdigit (*e)) {
+ e++;
+ }
+ if (*e == 0) {
+ return;
+ }
+ {
+ char s[e-def+1];
+ memcpy (s, def, e-def);
+ s[e-def] = 0;
+ id = atoi (s);
+ }
+ // skip whitespace
+ def = e;
+ def++;
+ while (*def && *def <= ' ') {
+ def++;
+ }
+ if (*def == 0) {
+ return;
+ }
+ // width
+ e = def;
+ while (*e && isdigit (*e)) {
+ e++;
+ }
+ if (*e == 0) {
+ return;
+ }
+ {
+ char s[e-def+1];
+ memcpy (s, def, e-def);
+ s[e-def] = 0;
+ width = atoi (s);
+ }
+ // skip whitespace
+ def = e;
+ def++;
+ while (*def && *def <= ' ') {
+ def++;
+ }
+ if (*def == 0) {
+ return;
+ }
+ // align_right
+ e = def;
+ while (*e && isdigit (*e)) {
+ e++;
+ }
+ {
+ char s[e-def+1];
+ memcpy (s, def, e-def);
+ s[e-def] = 0;
+ align_right = atoi (s);
+ }
+ gtkpl_column_append (pl, gtkpl_column_alloc (title, width, id, format[0] ? format : NULL, align_right));
+}
+
+void
+gtkpl_column_update_config (gtkplaylist_t *pl, gtkpl_column_t *c, int idx) {
+ char key[128];
+ char value[128];
+ snprintf (key, sizeof (key), "%s.column.%d", pl->title, idx);
+ snprintf (value, sizeof (value), "\"%s\" \"%s\" %d %d %d", c->title, c->format ? c->format : "", c->id, c->width, c->align_right);
+ conf_set_str (key, value);
+}
+
+void
+gtkpl_column_rewrite_config (gtkplaylist_t *pl) {
+ char key[128];
+ char value[128];
+ snprintf (key, sizeof (key), "%s.column.", pl->title);
+ conf_remove_items (key);
+
+ gtkpl_column_t *c;
+ int i = 0;
+ for (c = pl->columns; c; c = c->next, i++) {
+ snprintf (key, sizeof (key), "%s.column.%d", pl->title, i);
+ snprintf (value, sizeof (value), "\"%s\" \"%s\" %d %d %d", c->title, c->format ? c->format : "", c->id, c->width, c->align_right);
+ conf_set_str (key, value);
+ }
+}
diff --git a/gtkplaylist.h b/gtkplaylist.h
index 9504df1d..22e83000 100644
--- a/gtkplaylist.h
+++ b/gtkplaylist.h
@@ -46,8 +46,19 @@ enum {
COLO_COUNT
};
-#define pl_ncolumns 5
-#define pl_colname_max 100
+//#define pl_ncolumns 5
+//#define pl_colname_max 100
+
+typedef struct gtkpl_column_s {
+ char *title;
+ int id; // id is faster than format, set to -1 to use format
+ char *format;
+ int width;
+ int movepos; // valid only while `moving' is 1
+ struct gtkpl_column_s *next;
+ unsigned align_right : 1;
+ unsigned moving : 1;
+} gtkpl_column_t;
// structure of this kind must be set as user data for playlist, header and scrollbar widgets
// pointer to this structure must be passed too all functions that
@@ -60,6 +71,7 @@ typedef struct {
GtkWidget *hscrollbar;
GdkPixmap *backbuf;
GdkPixmap *backbuf_header;
+ const char *title; // unique id, used for config writing, etc
// parameters
playItem_t **pcurr; // pointer to current item
int *pcount; // pointer to count of items in list
@@ -73,7 +85,9 @@ typedef struct {
double clicktime; // for doubleclick detection
int nvisiblerows;
int nvisiblefullrows;
- int *colwidths;//[pl_ncolumns]; // current column widths
+// int *colwidths;//[pl_ncolumns]; // current column widths
+// int ncolumns;
+ gtkpl_column_t *columns;
} gtkplaylist_t;
#define GTKPL_PROLOGUE \
@@ -84,6 +98,9 @@ void
gtkpl_init (void);
void
+gtkpl_free (gtkplaylist_t *pl);
+
+void
gtkpl_redraw_pl_row (gtkplaylist_t *ps, int row, playItem_t *it);
void
@@ -205,4 +222,26 @@ theme_set_cairo_source_rgb (cairo_t *cr, int col);
void
playlist_refresh (void);
+// column utilities
+gtkpl_column_t *
+gtkpl_column_alloc (const char *title, int width, int id, const char *format, int align_right);
+
+void
+gtkpl_column_append (gtkplaylist_t *pl, gtkpl_column_t *c);
+
+void
+gtkpl_column_remove (gtkplaylist_t *pl, gtkpl_column_t *c);
+
+void
+gtkpl_column_free (gtkpl_column_t *c);
+
+void
+gtkpl_append_column_from_textdef (gtkplaylist_t *pl, const uint8_t *def);
+
+void
+gtkpl_column_update_config (gtkplaylist_t *pl, gtkpl_column_t *c, int idx);
+
+void
+gtkpl_column_rewrite_config (gtkplaylist_t *pl);
+
#endif // __GTKPLAYLIST_H
diff --git a/main.c b/main.c
index 1406cc75..20b2fad8 100644
--- a/main.c
+++ b/main.c
@@ -750,6 +750,8 @@ main (int argc, char *argv[]) {
gtk_widget_show (mainwin);
gtk_main ();
+ gtkpl_free (&main_playlist);
+ gtkpl_free (&search_playlist);
server_close ();
gdk_threads_leave ();
messagepump_free ();
diff --git a/playlist.c b/playlist.c
index 0da4820e..8f1910f6 100644
--- a/playlist.c
+++ b/playlist.c
@@ -1375,3 +1375,76 @@ float
pl_get_item_duration (playItem_t *it) {
return it->_duration;
}
+
+int
+pl_format_title (playItem_t *it, char *s, int size, const char *fmt) {
+ int n = size-1;
+ while (*fmt && n) {
+ if (*fmt != '%') {
+ *s++ = *fmt;
+ n--;
+ }
+ else {
+ fmt++;
+ const char *meta = NULL;
+ if (*fmt == 0) {
+ break;
+ }
+ else if (*fmt == 'a') {
+ meta = "artist";
+ }
+ else if (*fmt == 't') {
+ meta = "title";
+ }
+ else if (*fmt == 'b') {
+ meta = "album";
+ }
+ else if (*fmt == 'n') {
+ meta = "track";
+ }
+ else if (*fmt == '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 - 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 *value = dur;
+ while (n > 0 && *value) {
+ *s++ = *value++;
+ n--;
+ }
+ }
+ else {
+ *s++ = *fmt;
+ n--;
+ }
+
+ if (meta) {
+ const char *value = pl_find_meta (it, meta);
+ if (!value) {
+ value = "?";
+ }
+ while (n > 0 && *value) {
+ *s++ = *value++;
+ n--;
+ }
+ }
+ }
+ fmt++;
+ }
+ *s = 0;
+
+ return size - n - 1;
+}
+
diff --git a/playlist.h b/playlist.h
index 6f297e41..21c4752e 100644
--- a/playlist.h
+++ b/playlist.h
@@ -169,4 +169,10 @@ pl_set_item_duration (playItem_t *it, float duration);
float
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);
+
#endif // __PLAYLIST_H
diff --git a/session.c b/session.c
index 01f4a6f1..6822fdba 100644
--- a/session.c
+++ b/session.c
@@ -21,9 +21,12 @@
#include <stdint.h>
#include "session.h"
#include "common.h"
+#include "deadbeef.h"
+#include "conf.h"
-#define SESS_CURRENT_VER 3
+#define SESS_CURRENT_VER 4
// changelog:
+// version 4 column settings moved to common config
// version 3 adds column widths
// NOTE: dont forget to update session_reset when changing that
@@ -33,11 +36,6 @@ int8_t session_playlist_order;
int8_t session_playlist_looping;
int8_t session_scroll_follows_playback = 1;
int session_win_attrs[5] = { 40, 40, 500, 300, 0 };
-#define PL_MAX_COLUMNS 5
-static int session_main_colwidths[PL_MAX_COLUMNS] = { 50, 150, 50, 150, 50 };
-static int session_main_numcols = 5;
-static int session_search_colwidths[PL_MAX_COLUMNS] = { 0, 150, 50, 150, 50 };;
-static int session_search_numcols = 5;
static uint8_t sessfile_magic[] = { 0xdb, 0xef, 0x5e, 0x55 }; // dbefsess in hexspeak
@@ -53,16 +51,6 @@ session_reset (void) {
session_win_attrs[2] = 500;
session_win_attrs[3] = 300;
session_win_attrs[4] = 0;
- {
- session_main_numcols = 5;
- int colwidths[] = { 50, 150, 50, 150, 50 };
- memcpy (session_main_colwidths, colwidths, sizeof (colwidths));
- }
- {
- session_search_numcols = 5;
- int colwidths[] = { 0, 150, 50, 150, 50 };
- memcpy (session_search_colwidths, colwidths, sizeof (colwidths));
- }
}
static int
@@ -180,32 +168,6 @@ session_save (const char *fname) {
goto session_save_fail;
}
}
- {
- // main column widths
- uint8_t cl = session_main_numcols;
- if (fwrite (&cl, 1, 1, fp) != 1) {
- goto session_save_fail;
- }
- for (int i = 0; i < cl; i++) {
- int16_t w = session_main_colwidths[i];
- if (fwrite (&w, 1, sizeof (w), fp) != sizeof (w)) {
- goto session_save_fail;
- }
- }
- }
- {
- // search column widths
- uint8_t cl = session_search_numcols;
- if (fwrite (&cl, 1, 1, fp) != 1) {
- goto session_save_fail;
- }
- for (int i = 0; i < cl; i++) {
- int16_t w = session_search_colwidths[i];
- if (fwrite (&w, 1, sizeof (w), fp) != sizeof (w)) {
- goto session_save_fail;
- }
- }
- }
fclose (fp);
return 0;
session_save_fail:
@@ -269,7 +231,13 @@ session_load (const char *fname) {
goto session_load_fail;
}
}
- if (version >= 3) {
+ if (version == 3) {
+ // import playlist and search columns to new common config
+#define PL_MAX_COLUMNS 5
+ int session_main_colwidths[PL_MAX_COLUMNS] = { 50, 150, 50, 150, 50 };
+ int session_main_numcols = 5;
+ int session_search_colwidths[PL_MAX_COLUMNS] = { 0, 150, 50, 150, 50 };;
+ int session_search_numcols = 5;
{
// main column widths
uint8_t l;
@@ -306,6 +274,36 @@ session_load (const char *fname) {
session_search_colwidths[i] = w;
}
}
+ // convert to common config
+ const char *colnames[] = {
+ "Playing",
+ "Artist / Album",
+ "Track №",
+ "Title / Track Artist",
+ "Duration"
+ };
+ int colids[] = {
+ DB_COLUMN_PLAYING,
+ DB_COLUMN_ARTIST_ALBUM,
+ DB_COLUMN_TRACK,
+ DB_COLUMN_TITLE,
+ DB_COLUMN_DURATION
+ };
+ int i;
+ for (i = 0; i < 5; i++) {
+ char key[128];
+ char value[128];
+ snprintf (key, sizeof (key), "playlist.column.%d", i);
+ snprintf (value, sizeof (value), "\"%s\" \"%s\" %d %d %d", colnames[i], "", colids[i], session_main_colwidths[i], i == 2 ? 1 : 0);
+ conf_set_str (key, value);
+ }
+ for (i = 1; i < 5; i++) {
+ char key[128];
+ char value[128];
+ snprintf (key, sizeof (key), "search.column.%d", i-1);
+ snprintf (value, sizeof (value), "\"%s\" \"%s\" %d %d %d", colnames[i], "", colids[i], session_main_colwidths[i], i == 2 ? 1 : 0);
+ conf_set_str (key, value);
+ }
}
// printf ("dir: %s\n", session_dir);
// printf ("volume: %f\n", session_volume);
@@ -369,12 +367,3 @@ session_get_scroll_follows_playback (void) {
return session_scroll_follows_playback;
}
-int *
-session_get_main_colwidths_ptr (void) {
- return session_main_colwidths;
-}
-
-int *
-session_get_search_colwidths_ptr (void) {
- return session_search_colwidths;
-}