summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-02-23 22:23:44 +0100
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-02-23 22:23:44 +0100
commit48e960ff2cbb08d7a442df93d2113af507ccfe92 (patch)
tree027a5e841acee59bc763c92e2da846160e2ebeb9 /plugins
parent06b370e4a5a456a2e4175b1977341bce1e5deb57 (diff)
moved column management into ddblistview
Diffstat (limited to 'plugins')
-rw-r--r--plugins/gtkui/ddblistview.c327
-rw-r--r--plugins/gtkui/ddblistview.h43
-rw-r--r--plugins/gtkui/mainplaylist.c452
3 files changed, 427 insertions, 395 deletions
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,
@@ -845,6 +669,18 @@ DdbListviewBinding main_binding = {
};
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");
pause16_pixbuf = draw_load_pixbuf ("pause_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