From 0415b1ec23934e833b5d859aed0f12565c65b526 Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Sun, 18 Oct 2009 19:14:19 +0200 Subject: new custom columns WIP --- callbacks.c | 47 ++++++-- conf.c | 51 ++++++++- conf.h | 7 ++ deadbeef.h | 11 ++ gtkplaylist.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++++++------- gtkplaylist.h | 45 +++++++- main.c | 2 + playlist.c | 73 +++++++++++++ playlist.h | 6 ++ session.c | 93 +++++++--------- 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 #include #include +#include #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; @@ -106,6 +110,15 @@ gtkpl_init (void) { memcpy (colo_current, colo_white_blue, sizeof (colo_current)); } +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 \ @@ -83,6 +97,9 @@ typedef struct { void gtkpl_init (void); +void +gtkpl_free (gtkplaylist_t *pl); + void gtkpl_redraw_pl_row (gtkplaylist_t *ps, int row, playItem_t *it); @@ -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 #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; -} -- cgit v1.2.3