From 48e960ff2cbb08d7a442df93d2113af507ccfe92 Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Tue, 23 Feb 2010 22:23:44 +0100 Subject: moved column management into ddblistview --- plugins/gtkui/ddblistview.c | 327 ++++++++++++++++++++++++------- plugins/gtkui/ddblistview.h | 43 ++-- plugins/gtkui/mainplaylist.c | 452 ++++++++++++++----------------------------- 3 files changed, 427 insertions(+), 395 deletions(-) (limited to 'plugins') diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c index 34c4c94a..9965d21d 100644 --- a/plugins/gtkui/ddblistview.c +++ b/plugins/gtkui/ddblistview.c @@ -65,6 +65,16 @@ extern GtkWidget *theme_treeview; G_DEFINE_TYPE (DdbListview, ddb_listview, GTK_TYPE_TABLE); +struct _DdbListviewColumn { + char *title; + int width; + struct _DdbListviewColumn *next; + void *user_data; + unsigned align_right : 1; + unsigned sort_order : 2; // 0=none, 1=asc, 2=desc +}; +typedef struct _DdbListviewColumn DdbListviewColumn; + static void ddb_listview_class_init(DdbListviewClass *klass); static void ddb_listview_init(DdbListview *listview); static void ddb_listview_size_request(GtkWidget *widget, @@ -111,6 +121,12 @@ ddb_listview_header_render (DdbListview *ps); void ddb_listview_header_expose (DdbListview *ps, int x, int y, int w, int h); +////// column management functions //// +void +ddb_listview_column_move (DdbListview *listview, DdbListviewColumn *which, int inspos); +void +ddb_listview_column_free (DdbListviewColumn *c); + // signal handlers void @@ -370,7 +386,7 @@ ddb_listview_init(DdbListview *listview) G_CALLBACK (ddb_listview_vscroll_event), NULL); // g_signal_connect ((gpointer) listview->list, "drag_begin", -// G_CALLBACK (on_playlist_drag_begin), +// G_CALLBACK (on_list_drag_begin), // NULL); g_signal_connect ((gpointer) listview->list, "drag_motion", G_CALLBACK (ddb_listview_list_drag_motion), @@ -419,6 +435,12 @@ ddb_listview_destroy(GtkObject *object) g_return_if_fail(DDB_IS_LISTVIEW(object)); listview = DDB_LISTVIEW(object); + while (listview->columns) { + DdbListviewColumn *next = listview->columns->next; + listview->binding->col_deleted (0, listview->columns->user_data); + ddb_listview_column_free (listview->columns); + listview->columns = next; + } class = gtk_type_class(gtk_widget_get_type()); @@ -536,7 +558,6 @@ ddb_listview_list_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { - // draw visible area of playlist DdbListview *ps = DDB_LISTVIEW (gtk_object_get_data (GTK_OBJECT (widget), "owner")); ddb_listview_list_expose (ps, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; @@ -558,8 +579,8 @@ ddb_listview_vscroll_event (GtkWidget *widget, DdbListview *ps = DDB_LISTVIEW (gtk_object_get_data (GTK_OBJECT (widget), "owner")); GdkEventScroll *ev = (GdkEventScroll*)event; GtkWidget *range = ps->scrollbar;; - GtkWidget *playlist = ps->list; - int h = playlist->allocation.height / ps->rowheight; + GtkWidget *list = ps->list; + int h = list->allocation.height / ps->rowheight; int size = ps->binding->count (); if (h >= size) { size = 0; @@ -837,7 +858,7 @@ colhdr_anim_swap (DdbListview *pl, int c1, int c2, int x1, int x2) { // find c1 and c2 in column list and setup coords // note: columns are already swapped, so their coords must be reversed, // as if before swap - DdbListviewColIter c; + DdbListviewColumn *c; int idx = 0; int x = 0; for (c = pl->columns; c; c = c->next, idx++) { @@ -860,8 +881,8 @@ colhdr_anim_swap (DdbListview *pl, int c1, int c2, int x1, int x2) { void ddb_listview_list_setup_vscroll (DdbListview *ps) { - GtkWidget *playlist = ps->list; - int h = playlist->allocation.height / ps->rowheight; + GtkWidget *list = ps->list; + int h = list->allocation.height / ps->rowheight; int cnt = ps->binding->count (); int size = cnt; if (h >= size) { @@ -889,12 +910,12 @@ ddb_listview_list_setup_vscroll (DdbListview *ps) { void ddb_listview_list_setup_hscroll (DdbListview *ps) { - GtkWidget *playlist = ps->list; - int w = playlist->allocation.width; + GtkWidget *list = ps->list; + int w = list->allocation.width; int size = 0; - DdbListviewColIter c; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c)) { - size += ps->binding->col_get_width (c); + DdbListviewColumn *c; + for (c = ps->columns; c; c = c->next) { + size += c->width; } ps->totalwidth = size; if (ps->totalwidth < ps->list->allocation.width) { @@ -992,12 +1013,11 @@ ddb_listview_list_render_row_foreground (DdbListview *ps, int row, DdbListviewIt draw_set_fg_color (rgb); } int x = -ps->hscrollpos; - DdbListviewColIter c; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c)) { - int cw = ps->binding->col_get_width (c); - if (ps->binding->draw_column_data) { - ps->binding->draw_column_data (ps->backbuf, it, row, c, x - ps->hscrollpos, row * ps->rowheight - ps->scrollpos * ps->rowheight, cw, ps->rowheight); - } + DdbListviewColumn *c; + int cidx = 0; + for (c = ps->columns; c; c = c->next, cidx++) { + int cw = c->width; + ps->binding->draw_column_data (ps, ps->backbuf, it, row, cidx, x - ps->hscrollpos, row * ps->rowheight - ps->scrollpos * ps->rowheight, cw, ps->rowheight); x += cw; } } @@ -1216,7 +1236,6 @@ ddb_listview_list_dbg_draw_areasel (GtkWidget *widget, int x, int y) { if (!cr) { return; } - theme_set_fg_color (COLO_PLAYLIST_CURSOR); cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); cairo_set_line_width (cr, 1); int sx = min (areaselect_x, x); @@ -1472,7 +1491,6 @@ ddb_listview_list_track_dragdrop (DdbListview *ps, int y) { draw_begin ((uintptr_t)widget->window); ps->drag_motion_y = y / ps->rowheight; - //theme_set_fg_color (COLO_DRAGDROP_MARKER); GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (ps)); float clr[3] = { style->fg[GTK_STATE_NORMAL].red, style->fg[GTK_STATE_NORMAL].green, style->fg[GTK_STATE_NORMAL].blue }; draw_set_fg_color (clr); @@ -1533,11 +1551,11 @@ ddb_listview_header_render (DdbListview *ps) { gdk_draw_line (ps->backbuf_header, widget->style->mid_gc[GTK_STATE_NORMAL], 0, widget->allocation.height-1, widget->allocation.width, widget->allocation.height-1); draw_begin ((uintptr_t)ps->backbuf_header); x = -ps->hscrollpos; - DdbListviewColIter c; + DdbListviewColumn *c; int need_draw_moving = 0; int idx = 0; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c), idx++) { - w = ps->binding->col_get_width (c); + for (c = ps->columns; c; c = c->next, idx++) { + w = c->width; int xx = x; #if 0 if (colhdr_anim.anim_active) { @@ -1554,7 +1572,7 @@ ddb_listview_header_render (DdbListview *ps) { continue; } int arrow_sz = 10; - int sort = ps->binding->col_get_sort (c); + int sort = c->sort_order; 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]; @@ -1567,7 +1585,7 @@ ddb_listview_header_render (DdbListview *ps) { ww = 0; } } - draw_text (xx + 5, h/2-draw_get_font_size()/2, ww, 0, ps->binding->col_get_title (c)); + draw_text (xx + 5, h/2-draw_get_font_size()/2, ww, 0, c->title); } if (sort) { int dir = sort == 1 ? GTK_ARROW_DOWN : GTK_ARROW_UP; @@ -1582,8 +1600,8 @@ ddb_listview_header_render (DdbListview *ps) { if (need_draw_moving) { x = -ps->hscrollpos; idx = 0; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c), idx++) { - w = ps->binding->col_get_width (c); + for (c = ps->columns; c; c = c->next, idx++) { + w = c->width; if (idx == ps->header_dragging) { #if 0 if (colhdr_anim.anim_active) { @@ -1608,7 +1626,7 @@ ddb_listview_header_render (DdbListview *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, ps->binding->col_get_width (c)-10, 0, ps->binding->col_get_title (c)); + draw_text (x + 5, h/2-draw_get_font_size()/2, c->width-10, 0, c->title); } break; } @@ -1682,29 +1700,30 @@ ddb_listview_header_motion_notify_event (GtkWidget *widget, } if (!ps->header_prepare && ps->header_dragging >= 0) { gdk_window_set_cursor (widget->window, cursor_drag); - DdbListviewColIter c; + DdbListviewColumn *c; int i; - for (i = 0, c = ps->binding->col_first (); i < ps->header_dragging && c; c = ps->binding->col_next (c), i++); + for (i = 0, c = ps->columns; i < ps->header_dragging && c; c = c->next, i++); ps->col_movepos = ev_x - ps->header_dragpt[0]; // find closest column to the left int inspos = -1; - DdbListviewColIter cc; + DdbListviewColumn *cc; int x = 0; int idx = 0; int x1 = -1, x2 = -1; - for (cc = ps->binding->col_first (); cc; cc = ps->binding->col_next (cc), idx++) { - if (x < ps->col_movepos && x + ps->binding->col_get_width (c) > ps->col_movepos) { + for (cc = ps->columns; cc; cc = cc->next, idx++) { + if (x < ps->col_movepos && x + c->width > ps->col_movepos) { inspos = idx; x1 = x; } else if (idx == ps->header_dragging) { x2 = x; } - x += ps->binding->col_get_width (cc); + x += cc->width; } if (inspos >= 0 && inspos != ps->header_dragging) { - ps->binding->col_move (c, inspos); + ddb_listview_column_move (ps, c, inspos); +// ps->binding->col_move (c, inspos); ps->header_dragging = inspos; // colhdr_anim_swap (ps, c1, c2, x1, x2); // force redraw of everything @@ -1725,13 +1744,13 @@ ddb_listview_header_motion_notify_event (GtkWidget *widget, // get column start pos int x = -ps->hscrollpos; int i = 0; - DdbListviewColIter c; - for (c = ps->binding->col_first (); c && i < ps->header_sizing; c = ps->binding->col_next (c), i++) { - x += ps->binding->col_get_width (c); + DdbListviewColumn *c; + for (c = ps->columns; c && i < ps->header_sizing; c = c->next, i++) { + x += c->width; } int newx = ev_x > x + MIN_COLUMN_WIDTH ? ev_x : x + MIN_COLUMN_WIDTH; - ps->binding->col_set_width (c, newx-x); + c->width = newx-x; ddb_listview_list_setup_hscroll (ps); ddb_listview_header_render (ps); ddb_listview_header_expose (ps, 0, 0, ps->header->allocation.width, ps->header->allocation.height); @@ -1740,9 +1759,9 @@ ddb_listview_header_motion_notify_event (GtkWidget *widget, } else { int x = -ps->hscrollpos; - DdbListviewColIter c; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c)) { - int w = ps->binding->col_get_width (c); + DdbListviewColumn *c; + for (c = ps->columns; c; c = c->next) { + int w = c->width; if (w > 0) { // ignore collapsed columns (hack for search window) if (ev_x >= x + w - 2 && ev_x <= x + w) { gdk_window_set_cursor (widget->window, cursor_sz); @@ -1761,18 +1780,19 @@ ddb_listview_header_motion_notify_event (GtkWidget *widget, return FALSE; } -DdbListviewColIter -ddb_listview_header_get_column_for_coord (DdbListview *pl, int click_x) { +static int +ddb_listview_header_get_column_idx_for_coord (DdbListview *pl, int click_x) { int x = -pl->hscrollpos; - DdbListviewColIter c; - for (c = pl->binding->col_first (); c; c = pl->binding->col_next (c)) { - int w = pl->binding->col_get_width (c); + DdbListviewColumn *c; + int idx = 0; + for (c = pl->columns; c; c = c->next, idx++) { + int w = c->width; if (click_x >= x && click_x < x + w) { - return c; + return idx; } x += w; } - return NULL; + return -1; } gboolean @@ -1790,9 +1810,9 @@ ddb_listview_header_button_press_event (GtkWidget *widget, ps->header_dragpt[1] = event->y; int x = -ps->hscrollpos; int i = 0; - DdbListviewColIter c; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c), i++) { - int w = ps->binding->col_get_width (c); + DdbListviewColumn *c; + for (c = ps->columns; c; c = c->next, i++) { + int w = c->width; if (event->x >= x + w - 2 && event->x <= x + w) { ps->header_sizing = i; ps->header_dragging = -1; @@ -1811,7 +1831,8 @@ ddb_listview_header_button_press_event (GtkWidget *widget, } } else if (event->button == 3) { - ps->binding->header_context_menu (ps, ddb_listview_header_get_column_for_coord (ps, event->x)); + int idx = ddb_listview_header_get_column_idx_for_coord (ps, event->x); + ps->binding->header_context_menu (ps, idx); } ps->prev_header_x = -1; ps->last_header_motion_ev = -1; @@ -1830,28 +1851,28 @@ ddb_listview_header_button_release_event (GtkWidget *widget, ps->header_dragging = -1; ps->header_prepare = 0; // sort - DdbListviewColIter c; + DdbListviewColumn *c; int i = 0; int x = -ps->hscrollpos; int sorted = 0; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c), i++) { - int w = ps->binding->col_get_width (c); + for (c = ps->columns; c; c = c->next, i++) { + int w = c->width; if (event->x > x + 2 && event->x < x + w - 2) { - int sort_order = ps->binding->col_get_sort (c); + int sort_order = c->sort_order; if (!sort_order) { - ps->binding->col_set_sort (c, 1); + c->sort_order = 1; } else if (sort_order == 1) { - ps->binding->col_set_sort (c, 2); + c->sort_order = 2; } else if (sort_order == 2) { - ps->binding->col_set_sort (c, 1); + c->sort_order = 1; } - ps->binding->col_sort (c); + ps->binding->col_sort (i, c->sort_order, c->user_data); sorted = 1; } else { - ps->binding->col_set_sort (c, 0); + c->sort_order = 0; } x += w; } @@ -1860,9 +1881,9 @@ ddb_listview_header_button_release_event (GtkWidget *widget, else { ps->header_sizing = -1; int x = 0; - DdbListviewColIter c; - for (c = ps->binding->col_first (); c; c = ps->binding->col_next (c)) { - int w = ps->binding->col_get_width (c); + DdbListviewColumn *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; @@ -2040,3 +2061,179 @@ int ddb_listview_is_scrolling (DdbListview *listview) { return listview->dragwait; } + +// columns +void +ddb_listview_column_insert (DdbListview *listview, int before, const char *title, int width, int align_right, void *user_data); +void +ddb_listview_column_remove (DdbListview *listview, int idx); + +/////// column management code + +DdbListviewColumn * +ddb_listview_column_alloc (const char *title, int width, int align_right, void *user_data) { + DdbListviewColumn * c = malloc (sizeof (DdbListviewColumn)); + memset (c, 0, sizeof (DdbListviewColumn)); + c->title = strdup (title); + c->width = width; + c->align_right = align_right; + c->user_data = user_data; + return c; +} + +void +ddb_listview_column_append (DdbListview *listview, const char *title, int width, int align_right, void *user_data) { + DdbListviewColumn* c = ddb_listview_column_alloc (title, width, align_right, user_data); + int idx = 0; + DdbListviewColumn * columns = listview->columns; + if (columns) { + idx++; + DdbListviewColumn * tail = listview->columns; + while (tail->next) { + tail = tail->next; + idx++; + } + tail->next = c; + } + else { + listview->columns = c; + } +} + +void +ddb_listview_column_insert (DdbListview *listview, int before, const char *title, int width, int align_right, void *user_data) { + DdbListviewColumn *c = ddb_listview_column_alloc (title, width, align_right, user_data); + if (listview->columns) { + DdbListviewColumn * prev = NULL; + DdbListviewColumn * next = listview->columns; + int idx = 0; + while (next) { + if (idx == before) { + break; + } + prev = next; + next = next->next; + idx++; + } + c->next = next; + if (prev) { + prev->next = c; + } + else { + listview->columns = c; + } + } + else { + listview->columns = c; + } +} + +void +ddb_listview_column_free (DdbListviewColumn * c) { + if (c->title) { + free (c->title); + } + free (c); +} + +void +ddb_listview_column_remove (DdbListview *listview, int idx) { + DdbListviewColumn *c; + if (idx == 0) { + c = listview->columns; + assert (c); + listview->binding->col_deleted (0, c->user_data); + listview->columns = c->next; + ddb_listview_column_free (c); + return; + } + c = listview->columns; + int i = 0; + while (c) { + if (i+1 == idx) { + assert (c->next); + listview->binding->col_deleted (idx, c->next->user_data); + DdbListviewColumn *next = c->next->next; + ddb_listview_column_free (c->next); + c->next = next; + return; + } + c = c->next; + idx++; + } + + if (!c) { + trace ("ddblv: attempted to remove column that is not in list\n"); + } +} + +void +ddb_listview_column_move (DdbListview *listview, DdbListviewColumn *which, int inspos) { + // remove c from list + DdbListviewColumn *c = (DdbListviewColumn *)which; + if (c == listview->columns) { + listview->columns = c->next; + } + else { + DdbListviewColumn *cc; + for (cc = listview->columns; cc; cc = cc->next) { + if (cc->next == c) { + cc->next = c->next; + break; + } + } + } + c->next = NULL; + // reinsert c at position inspos update header_dragging to new idx + if (inspos == 0) { + c->next = listview->columns; + listview->columns = c; + } + else { + int idx = 0; + DdbListviewColumn *prev = NULL; + DdbListviewColumn *cc = NULL; + for (cc = listview->columns; cc; cc = cc->next, idx++, prev = cc) { + if (idx+1 == inspos) { + DdbListviewColumn *next = cc->next; + cc->next = c; + c->next = next; + break; + } + } + } +} + +int +ddb_listview_column_get_info (DdbListview *listview, int col, const char **title, int *width, int *align_right, void **user_data) { + DdbListviewColumn *c; + int idx = 0; + for (c = listview->columns; c; c = c->next, idx++) { + if (idx == col) { + *title = c->title; + *width = c->width; + *align_right = c->align_right; + *user_data = c->user_data; + return 0; + } + } + return -1; +} + +int +ddb_listview_column_set_info (DdbListview *listview, int col, const char *title, int width, int align_right, void *user_data) { + DdbListviewColumn *c; + int idx = 0; + for (c = listview->columns; c; c = c->next, idx++) { + if (idx == col) { + free (c->title); + c->title = strdup (title); + c->width = width; + c->align_right = align_right; + c->user_data = user_data; + return 0; + } + } + return -1; +} +/////// end of column management code diff --git a/plugins/gtkui/ddblistview.h b/plugins/gtkui/ddblistview.h index 0fa16ea4..a8146131 100644 --- a/plugins/gtkui/ddblistview.h +++ b/plugins/gtkui/ddblistview.h @@ -41,7 +41,7 @@ typedef struct _DdbListview DdbListview; typedef struct _DdbListviewClass DdbListviewClass; typedef void * DdbListviewIter; -typedef void * DdbListviewColIter; +//typedef void * DdbListviewColIter; typedef struct { // rows @@ -69,29 +69,20 @@ typedef struct { void (*drag_n_drop) (DdbListviewIter before, uint32_t *indices, int length); void (*external_drag_n_drop) (DdbListviewIter before, char *mem, int length); - // columns - int (*col_count) (void); - DdbListviewColIter (*col_first) (void); - DdbListviewColIter (*col_next) (DdbListviewColIter); - const char *(*col_get_title) (DdbListviewColIter); - int (*col_get_width) (DdbListviewColIter); - int (*col_get_justify) (DdbListviewColIter); - int (*col_get_sort) (DdbListviewColIter); - void (*col_move) (DdbListviewColIter which, int inspos); - void (*col_sort) (DdbListviewColIter); - - void (*col_set_width) (DdbListviewColIter c, int width); - void (*col_set_sort) (DdbListviewColIter c, int sort); - // callbacks - void (*draw_column_data) (GdkDrawable *drawable, DdbListviewIter iter, int idx, DdbListviewColIter column, int x, int y, int width, int height); + void (*draw_column_data) (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter iter, int idx, int column, int x, int y, int width, int height); void (*list_context_menu) (DdbListview *listview, DdbListviewIter iter, int idx); - void (*header_context_menu) (DdbListview *listview, DdbListviewColIter c); + void (*header_context_menu) (DdbListview *listview, int col); void (*handle_doubleclick) (DdbListview *listview, DdbListviewIter iter, int idx); void (*selection_changed) (DdbListviewIter it, int idx); void (*delete_selected) (void); + void (*col_changed) (int col, void *user_data); + void (*col_sort) (int col, int sort_order, void *user_data); + void (*col_deleted) (int col, void *user_data); } DdbListviewBinding; +struct _DdbListviewColumn; + struct _DdbListview { GtkTable parent; @@ -108,9 +99,6 @@ struct _DdbListview { GdkPixmap *backbuf; GdkPixmap *backbuf_header; const char *title; // unique id, used for config writing, etc -// // parameters -// int (*get_count)(void); // function pointer to get number of tracks -// int iterator; // index into next array of DB_playItem_t struct int lastpos[2]; // last mouse position (for list widget) // current state int scrollpos; @@ -149,8 +137,8 @@ struct _DdbListview { int prev_header_x; int header_prepare; -// gtkpl_column_t *columns; -// gtkpl_column_t *active_column; // required for column editing + struct _DdbListviewColumn *columns; + struct _DdbListviewColumn *active_column; }; struct _DdbListviewClass { @@ -158,6 +146,7 @@ struct _DdbListviewClass { }; GtkType ddb_listview_get_type(void); + GtkWidget * ddb_listview_new(); void @@ -178,6 +167,16 @@ void ddb_listview_scroll_to (DdbListview *listview, int pos); int ddb_listview_is_scrolling (DdbListview *listview); +void +ddb_listview_column_append (DdbListview *listview, const char *title, int width, int align_right, void *user_data); +void +ddb_listview_column_insert (DdbListview *listview, int before, const char *title, int width, int align_right, void *user_data); +void +ddb_listview_column_remove (DdbListview *listview, int idx); +int +ddb_listview_column_get_info (DdbListview *listview, int col, const char **title, int *width, int *align_right, void **user_data); +int +ddb_listview_column_set_info (DdbListview *listview, int col, const char *title, int width, int align_right, void *user_data); enum { DDB_REFRESH_COLUMNS = 1, diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c index 673d8c63..afc3daa8 100644 --- a/plugins/gtkui/mainplaylist.c +++ b/plugins/gtkui/mainplaylist.c @@ -27,6 +27,8 @@ #include "drawing.h" #include "trkproperties.h" +#pragma GCC optimize("O0") + //#define trace(...) { fprintf(stderr, __VA_ARGS__); } #define trace(fmt,...) @@ -34,183 +36,6 @@ static uintptr_t play16_pixbuf; static uintptr_t pause16_pixbuf; static uintptr_t buffering16_pixbuf; -/////// column management code - -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 sort_order : 2; // 0=none, 1=asc, 2=desc -} gtkpl_column_t; - -static gtkpl_column_t *main_columns = NULL; -static gtkpl_column_t *search_columns = NULL; - -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 (gtkpl_column_t **head, gtkpl_column_t * c) { - int idx = 0; - gtkpl_column_t * columns = *head; - if (columns) { - idx++; - gtkpl_column_t * tail = *head; - while (tail->next) { - tail = tail->next; - idx++; - } - tail->next = c; - } - else { - *head = c; - } -// gtkpl_column_update_config (pl, c, idx); -} - -void -gtkpl_column_insert_before (gtkpl_column_t **head, gtkpl_column_t * before, gtkpl_column_t * c) { - if (*head) { - gtkpl_column_t * prev = NULL; - gtkpl_column_t * next = *head; - while (next) { - if (next == before) { - break; - } - prev = next; - next = next->next; - } - c->next = next; - if (prev) { - prev->next = c; - } - else { - *head = c; - } -// gtkpl_column_rewrite_config (pl); - } - else { - *head = c; - // gtkpl_column_update_config (pl, c, 0); - } -} - -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 (gtkpl_column_t **head, gtkpl_column_t * c) { - if (*head == c) { - *head = (*head)->next; - gtkpl_column_free (c); - return; - } - gtkpl_column_t * cc = *head; - while (cc) { - if (cc->next == c) { - cc->next = cc->next->next; - gtkpl_column_free (c); - return; - } - cc = cc->next; - } - - if (!cc) { - trace ("gtkpl: attempted to remove column that is not in list\n"); - } -} - -void -gtkpl_append_column_from_textdef (gtkpl_column_t **head, const uint8_t *def) { - // syntax: "title" "format" id width alignright - char token[MAX_TOKEN]; - const char *p = def; - char title[MAX_TOKEN]; - int id; - char fmt[MAX_TOKEN]; - int width; - int align; - - parser_init (); - - p = gettoken_warn_eof (p, token); - if (!p) { - return; - } - strcpy (title, token); - - p = gettoken_warn_eof (p, token); - if (!p) { - return; - } - strcpy (fmt, token); - - p = gettoken_warn_eof (p, token); - if (!p) { - return; - } - id = atoi (token); - - p = gettoken_warn_eof (p, token); - if (!p) { - return; - } - width = atoi (token); - - p = gettoken_warn_eof (p, token); - if (!p) { - return; - } - align = atoi (token); - - gtkpl_column_append (head, gtkpl_column_alloc (title, width, id, fmt, align)); -} - -void -gtkpl_column_update_config (const char *title, gtkpl_column_t * c, int idx) { - char key[128]; - char value[128]; - snprintf (key, sizeof (key), "%s.column.%d", title, idx); - snprintf (value, sizeof (value), "\"%s\" \"%s\" %d %d %d", c->title, c->format ? c->format : "", c->id, c->width, c->align_right); - deadbeef->conf_set_str (key, value); -} - -void -gtkpl_column_rewrite_config (gtkpl_column_t *head, const char *title) { - char key[128]; - snprintf (key, sizeof (key), "%s.column.", title); - deadbeef->conf_remove_items (key); - - gtkpl_column_t * c; - int i = 0; - for (c = head; c; c = c->next, i++) { - gtkpl_column_update_config (title, c, i); - } -} - -/////// end of column management code - static int main_get_count (void) { return deadbeef->pl_getcount (PL_MAIN); @@ -275,35 +100,6 @@ void main_external_drag_n_drop (DdbListviewIter before, char *mem, int length) { gtkui_receive_fm_drop ((DB_playItem_t *)before, mem, length); } -static int main_col_count (void) { - int cnt = 0; - for (gtkpl_column_t *c = main_columns; c; c = c->next, cnt++); - return cnt; -} - -DdbListviewColIter main_col_first (void) { - return (DdbListviewColIter)main_columns; -} -DdbListviewColIter main_col_next (DdbListviewColIter c) { - return (DdbListviewColIter)((gtkpl_column_t *)c)->next; -} - -static const char *main_col_get_title (DdbListviewColIter c) { - return ((gtkpl_column_t *)c)->title; -} - -int main_col_get_width (DdbListviewColIter c) { - return ((gtkpl_column_t *)c)->width; -} - -int main_col_get_justify (DdbListviewColIter c) { - return ((gtkpl_column_t *)c)->align_right; -} - -int main_col_get_sort (DdbListviewColIter c) { - return ((gtkpl_column_t *)c)->sort_order; -} - gboolean playlist_tooltip_handler (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer unused) { @@ -316,84 +112,95 @@ playlist_tooltip_handler (GtkWidget *widget, gint x, gint y, gboolean keyboard_m return FALSE; } -void main_col_sort (DdbListviewColIter col) { - gtkpl_column_t *c = (gtkpl_column_t *)col; - deadbeef->pl_sort (PL_MAIN, c->id, c->format, c->sort_order-1); +// columns + +typedef struct { + int id; + char *format; +} col_info_t; + +void +main_col_sort (int col, int sort_order, void *user_data) { + col_info_t *c = (col_info_t*)user_data; + deadbeef->pl_sort (PL_MAIN, c->id, c->format, sort_order-1); } -void main_col_move (DdbListviewColIter which, int inspos) { - // remove c from list - gtkpl_column_t *c = (gtkpl_column_t *)which; - if (c == main_columns) { - main_columns = c->next; - } - else { - gtkpl_column_t *cc; - for (cc = main_columns; cc; cc = cc->next) { - if (cc->next == c) { - cc->next = c->next; - break; - } - } - } - c->next = NULL; - // reinsert c at position inspos update header_dragging to new idx - if (inspos == 0) { - c->next = main_columns; - main_columns = c; - } - else { - int idx = 0; - gtkpl_column_t *prev = NULL; - gtkpl_column_t *cc = NULL; - for (cc = main_columns; cc; cc = cc->next, idx++, prev = cc) { - if (idx+1 == inspos) { - gtkpl_column_t *next = cc->next; - cc->next = c; - c->next = next; - break; - } - } +static DdbListview *last_playlist; +static int active_column; + +void +append_column_from_textdef (DdbListview *listview, const uint8_t *def) { + // syntax: "title" "format" id width alignright + char token[MAX_TOKEN]; + const char *p = def; + char title[MAX_TOKEN]; + int id; + char fmt[MAX_TOKEN]; + int width; + int align; + + parser_init (); + + p = gettoken_warn_eof (p, token); + if (!p) { + return; } - gtkpl_column_rewrite_config (main_columns, "playlist"); -} + strcpy (title, token); -void main_col_set_width (DdbListviewColIter c, int width) { - int idx = 0; - ((gtkpl_column_t *)c)->width = width; - gtkpl_column_t *cc; - for (cc = main_columns; cc != c; cc = cc->next, idx++); - if (cc == main_columns) { - gtkpl_column_update_config ("playlist", (gtkpl_column_t *)c, idx); + p = gettoken_warn_eof (p, token); + if (!p) { + return; } - else { - trace ("error: main_col_set_width fail\n"); + strcpy (fmt, token); + + p = gettoken_warn_eof (p, token); + if (!p) { + return; } -} -void main_col_set_sort (DdbListviewColIter c, int sort) { - int idx = 0; - ((gtkpl_column_t *)c)->sort_order = sort; - gtkpl_column_t *cc; - for (cc = main_columns; cc != c; cc = cc->next, idx++); - if (cc == main_columns) { - gtkpl_column_update_config ("playlist", (gtkpl_column_t *)c, idx); + id = atoi (token); + + p = gettoken_warn_eof (p, token); + if (!p) { + return; } - else { - trace ("error: main_col_set_sort fail\n"); + width = atoi (token); + + p = gettoken_warn_eof (p, token); + if (!p) { + return; } + align = atoi (token); + + col_info_t *inf = malloc (sizeof (col_info_t)); + memset (inf, 0, sizeof (col_info_t)); + inf->format = strdup (fmt); + inf->id = id; + ddb_listview_column_append (listview, title, width, align, inf); } + +#if 0 void -columns_free (gtkpl_column_t **head) { - while (*head) { - DdbListviewColIter next = (*head)->next; - gtkpl_column_free (*head); - *head = next; - } +gtkpl_column_update_config (const char *title, gtkpl_column_t * c, int idx) { + char key[128]; + char value[128]; + snprintf (key, sizeof (key), "%s.column.%d", title, idx); + snprintf (value, sizeof (value), "\"%s\" \"%s\" %d %d %d", c->title, c->format ? c->format : "", c->id, c->width, c->align_right); + deadbeef->conf_set_str (key, value); } -static DdbListview *last_playlist; -static gtkpl_column_t *active_column; +void +gtkpl_column_rewrite_config (gtkpl_column_t *head, const char *title) { + char key[128]; + snprintf (key, sizeof (key), "%s.column.", title); + deadbeef->conf_remove_items (key); + gtkpl_column_t * c; + int i = 0; + for (c = head; c; c = c->next, i++) { + gtkpl_column_update_config (title, c, i); + } +} +#endif void on_add_column_activate (GtkMenuItem *menuitem, gpointer user_data) @@ -411,8 +218,11 @@ on_add_column_activate (GtkMenuItem *menuitem, if (id >= DB_COLUMN_ID_MAX) { id = -1; } - gtkpl_column_insert_before (&main_columns, active_column, gtkpl_column_alloc (title, 100, id, format, align)); - gtkpl_column_rewrite_config (main_columns, title); + col_info_t *inf = malloc (sizeof (col_info_t)); + memset (inf, 0, sizeof (col_info_t)); + inf->format = strdup (format); + inf->id = id; + ddb_listview_column_insert (last_playlist, active_column, title, 100, align, inf); ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_REFRESH_HSCROLL | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS); } gtk_widget_destroy (dlg); @@ -427,15 +237,26 @@ on_edit_column_activate (GtkMenuItem *menuitem, return; GtkWidget *dlg = create_editcolumndlg (); gtk_window_set_title (GTK_WINDOW (dlg), "Edit column"); - gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "title")), active_column->title); - gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "format")), active_column->format); - if (active_column->id == -1) { + + const char *title; + int width; + int align_right; + col_info_t *inf; + int res = ddb_listview_column_get_info (last_playlist, active_column, &title, &width, &align_right, (void **)&inf); + if (res == -1) { + trace ("attempted to edit non-existing column\n"); + return; + } + + gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "title")), title); + gtk_entry_set_text (GTK_ENTRY (lookup_widget (dlg, "format")), inf->format); + if (inf->id == -1) { gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "id")), DB_COLUMN_ID_MAX); } else { - gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "id")), active_column->id); + gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "id")), inf->id); } - gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "align")), active_column->align_right); + gtk_combo_box_set_active (GTK_COMBO_BOX (lookup_widget (dlg, "align")), align_right); gint response = gtk_dialog_run (GTK_DIALOG (dlg)); if (response == GTK_RESPONSE_OK) { const gchar *title = gtk_entry_get_text (GTK_ENTRY (lookup_widget (dlg, "title"))); @@ -445,13 +266,10 @@ on_edit_column_activate (GtkMenuItem *menuitem, if (id >= DB_COLUMN_ID_MAX) { id = -1; } - free (active_column->title); - free (active_column->format); - active_column->title = strdup (title); - active_column->format = strdup (format); - active_column->id = id; - active_column->align_right = align; - gtkpl_column_rewrite_config (main_columns, title); + free (inf->format); + inf->format = strdup (format); + inf->id = id; + ddb_listview_column_set_info (last_playlist, active_column, title, width, align, inf); ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS); } @@ -466,9 +284,7 @@ on_remove_column_activate (GtkMenuItem *menuitem, if (!active_column) return; - gtkpl_column_remove (&main_columns, active_column); - gtkpl_column_rewrite_config (main_columns, "playlist"); - + ddb_listview_column_remove (last_playlist, active_column); ddb_listview_refresh (last_playlist, DDB_REFRESH_COLUMNS | DDB_REFRESH_LIST | DDB_REFRESH_HSCROLL | DDB_EXPOSE_LIST | DDB_EXPOSE_COLUMNS); } @@ -481,17 +297,24 @@ void main_selection_changed (DdbListviewIter it, int idx) { ddb_listview_draw_row (search, idx, it); } -void main_draw_column_data (GdkDrawable *drawable, DdbListviewIter it, int idx, DdbListviewColIter column, int x, int y, int width, int height) { - gtkpl_column_t *c = (gtkpl_column_t *)column; +void main_draw_column_data (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter it, int idx, int column, int x, int y, int width, int height) { if (deadbeef->pl_is_group_title ((DB_playItem_t *)it)) { - if (c == main_columns) { + if (column == 0) { float clr[] = {0, 0.1, 0.5}; draw_set_fg_color (clr); draw_text (x + 5, y + height/2 - draw_get_font_size ()/2 - 2, 1000, 0, ((DB_playItem_t *)it)->fname); } return; } - if (it == deadbeef->streamer_get_playing_track () && c->id == DB_COLUMN_PLAYING) { + const char *ctitle; + int cwidth; + int calign_right; + col_info_t *cinf; + int res = ddb_listview_column_get_info (listview, column, &ctitle, &cwidth, &calign_right, (void **)&cinf); + if (res == -1) { + return; + } + if (it == deadbeef->streamer_get_playing_track () && cinf->id == DB_COLUMN_PLAYING) { int paused = deadbeef->get_output ()->state () == OUTPUT_STATE_PAUSED; int buffering = !deadbeef->streamer_ok_to_read (-1); uintptr_t pixbuf; @@ -504,17 +327,17 @@ void main_draw_column_data (GdkDrawable *drawable, DdbListviewIter it, int idx, else { pixbuf = buffering16_pixbuf; } - draw_pixbuf ((uintptr_t)drawable, pixbuf, x + c->width/2 - 8, y + height/2 - 8, 0, 0, 16, 16); + draw_pixbuf ((uintptr_t)drawable, pixbuf, x + cwidth/2 - 8, y + height/2 - 8, 0, 0, 16, 16); } else { char text[1024]; - deadbeef->pl_format_title (it, idx, text, sizeof (text), c->id, c->format); + deadbeef->pl_format_title (it, idx, text, sizeof (text), cinf->id, cinf->format); - if (c->align_right) { - draw_text (x+5, y + height/2 - draw_get_font_size ()/2 - 2, c->width-10, 1, text); + if (calign_right) { + draw_text (x+5, y + height/2 - draw_get_font_size ()/2 - 2, cwidth-10, 1, text); } else { - draw_text (x + 5, y + height/2 - draw_get_font_size ()/2 - 2, c->width-10, 0, text); + draw_text (x + 5, y + height/2 - draw_get_font_size ()/2 - 2, cwidth-10, 0, text); } } } @@ -627,10 +450,10 @@ create_headermenu (void) } void -main_header_context_menu (DdbListview *ps, DdbListviewColIter c) { +main_header_context_menu (DdbListview *ps, int column) { GtkWidget *menu = create_headermenu (); last_playlist = ps; - active_column = c; + active_column = column; gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, ps, 3, gtk_get_current_event_time()); } @@ -823,6 +646,8 @@ DdbListviewBinding main_binding = { .draw_column_data = main_draw_column_data, // columns + .col_sort = main_col_sort, +#if 0 .col_count = main_col_count, .col_first = main_col_first, .col_next = main_col_next, @@ -830,11 +655,10 @@ DdbListviewBinding main_binding = { .col_get_width = main_col_get_width, .col_get_justify = main_col_get_justify, .col_get_sort = main_col_get_sort, - .col_sort = main_col_sort, .col_move = main_col_move, - .col_set_width = main_col_set_width, .col_set_sort = main_col_set_sort, +#endif // callbacks .handle_doubleclick = main_handle_doubleclick, @@ -844,6 +668,18 @@ DdbListviewBinding main_binding = { .delete_selected = main_delete_selected, }; +void +add_column_helper (DdbListview *listview, const char *title, int width, int id, const char *format, int align_right) { + if (!format) { + format = ""; + } + col_info_t *inf = malloc (sizeof (col_info_t)); + memset (inf, 0, sizeof (col_info_t)); + inf->id = id; + inf->format = strdup (format); + ddb_listview_column_append (listview, title, width, align_right, inf); +} + void main_playlist_init (GtkWidget *widget) { play16_pixbuf = draw_load_pixbuf ("play_16.png"); @@ -857,16 +693,17 @@ main_playlist_init (GtkWidget *widget) { DB_conf_item_t *col = deadbeef->conf_find ("playlist.column.", NULL); if (!col) { + DdbListview *listview = playlist; // create default set of columns - gtkpl_column_append (&main_columns, gtkpl_column_alloc ("Playing", 50, DB_COLUMN_PLAYING, NULL, 0)); - gtkpl_column_append (&main_columns, gtkpl_column_alloc ("Artist / Album", 150, DB_COLUMN_ARTIST_ALBUM, NULL, 0)); - gtkpl_column_append (&main_columns, gtkpl_column_alloc ("Track №", 50, DB_COLUMN_TRACK, NULL, 1)); - gtkpl_column_append (&main_columns, gtkpl_column_alloc ("Title / Track Artist", 150, DB_COLUMN_TITLE, NULL, 0)); - gtkpl_column_append (&main_columns, gtkpl_column_alloc ("Duration", 50, DB_COLUMN_DURATION, NULL, 0)); + add_column_helper (listview, "Playing", 50, DB_COLUMN_PLAYING, NULL, 0); + add_column_helper (listview, "Artist / Album", 150, DB_COLUMN_ARTIST_ALBUM, NULL, 0); + add_column_helper (listview, "Track №", 50, DB_COLUMN_TRACK, NULL, 1); + add_column_helper (listview, "Title / Track Artist", 150, DB_COLUMN_TITLE, NULL, 0); + add_column_helper (listview, "Duration", 50, DB_COLUMN_DURATION, NULL, 0); } else { while (col) { - gtkpl_append_column_from_textdef (&main_columns, col->value); + append_column_from_textdef (playlist, col->value); col = deadbeef->conf_find ("playlist.column.", col); } } @@ -884,7 +721,6 @@ main_playlist_init (GtkWidget *widget) { void main_playlist_free (void) { - columns_free (&main_columns); } void -- cgit v1.2.3