diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2010-02-07 22:20:19 +0100 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2010-02-07 22:20:19 +0100 |
commit | d7644e273f412f9e6fa5dff8d39daba1e8be5228 (patch) | |
tree | 0f3d2f8988bb13859684ecf784f092ec8c2c3789 | |
parent | ed94b40b44f283b4ef8c22ee731b59c8faa6d22b (diff) |
tabs for multiple playlists WIP
-rw-r--r-- | deadbeef.h | 10 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | playlist.c | 49 | ||||
-rw-r--r-- | playlist.h | 5 | ||||
-rw-r--r-- | plugins.c | 8 | ||||
-rw-r--r-- | plugins/gtkui/Makefile.am | 3 | ||||
-rw-r--r-- | plugins/gtkui/callbacks.c | 4 | ||||
-rw-r--r-- | plugins/gtkui/callbacks.h | 25 | ||||
-rw-r--r-- | plugins/gtkui/deadbeef.glade | 53 | ||||
-rw-r--r-- | plugins/gtkui/gdkdrawing.c | 13 | ||||
-rw-r--r-- | plugins/gtkui/interface.c | 44 | ||||
-rw-r--r-- | plugins/gtkui/tabs.c | 169 |
12 files changed, 330 insertions, 54 deletions
@@ -277,7 +277,15 @@ typedef struct { int (*cond_wait) (uintptr_t cond, uintptr_t mutex); int (*cond_signal) (uintptr_t cond); int (*cond_broadcast) (uintptr_t cond); - // playlist access + // playlist management + int (*plt_get_count) (void); + void (*plt_add) (int before, const char *title); + void (*plt_remove) (int plt); + void (*plt_free) (void); + void (*plt_set_curr) (int plt); + int (*plt_get_curr) (void); + const char * (*plt_get_title) (int plt); + // playlist tracks access DB_playItem_t * (*pl_item_alloc) (void); void (*pl_item_ref) (DB_playItem_t *it); void (*pl_item_unref) (DB_playItem_t *it); @@ -572,6 +572,7 @@ main (int argc, char *argv[]) { messagepump_init (); // required to push messages while handling commandline plug_load_all (); // required to add files to playlist from commandline + plt_add (0, "Test"); plt_add (0, "Default"); // execute server commands in local context @@ -77,28 +77,36 @@ plt_add (int before, const char *title) { memset (plt, 0, sizeof (playlist_t)); plt->title = strdup (title); - playlist_t *p = NULL; - - if (before > 0) { - p = playlists_head; - int i; - for (i = 0; p && i < before; i++) { - p = p->next; + playlist_t *p_before = NULL; + playlist_t *p_after = playlists_head; + + for (int i = 0; i < before; i++) { + if (i >= before+1) { + break; + } + p_before = p_after; + if (p_after) { + p_after = p_after->next; + } + else { + p_after = playlists_head; } } - - if (!p) { - plt->next = playlists_head; - playlists_head = plt; + + printf ("p_before %p, p_after %p, plt %p\n", p_before, p_after, plt); + if (p_before) { + p_before->next = plt; } else { - playlist_t *next = p->next; - p->next = plt; - plt->next = next; + playlists_head = plt; } + plt->next = p_after; if (!playlist) { playlist = plt; } + + printf ("playlists_head=%p\n", playlists_head); + playlists_count++; } @@ -157,6 +165,19 @@ plt_get_curr (void) { return -1; } +const char * +plt_get_title (int plt) { + int i; + playlist_t *p = playlists_head; + for (i = 0; p && i <= plt; i++) { + if (i == plt) { + return p->title; + } + p = p->next; + } + return NULL; +} + playlist_t * plt_get_curr_ptr (void) { return playlist; @@ -55,7 +55,7 @@ typedef struct playItem_s { unsigned in_playlist : 1; // 1 if item is in playlist } playItem_t; -typedef struct playlist_s{ +typedef struct playlist_s { char *title; playItem_t *head[PL_MAX_ITERATORS]; // head of linked list playItem_t *tail[PL_MAX_ITERATORS]; // tail of linked list @@ -82,6 +82,9 @@ plt_set_curr (int plt); int plt_get_curr (void); +const char * +plt_get_title (int plt); + playlist_t * plt_get_curr_ptr (void); @@ -101,6 +101,14 @@ static DB_functions_t deadbeef_api = { .cond_wait = cond_wait, .cond_signal = cond_signal, .cond_broadcast = cond_broadcast, + // playlist management + .plt_get_count = plt_get_count, + .plt_add = plt_add, + .plt_remove = plt_remove, + .plt_free = plt_free, + .plt_set_curr = plt_set_curr, + .plt_get_curr = plt_get_curr, + .plt_get_title = plt_get_title, // playlist access .pl_item_alloc = (DB_playItem_t* (*)(void))pl_item_alloc, .pl_item_ref = (void (*)(DB_playItem_t *))pl_item_ref, diff --git a/plugins/gtkui/Makefile.am b/plugins/gtkui/Makefile.am index 146e76db..3ef740f5 100644 --- a/plugins/gtkui/Makefile.am +++ b/plugins/gtkui/Makefile.am @@ -9,7 +9,8 @@ gtkui_la_SOURCES = gtkui.c gtkui.h\ search.c search.h\ fileman.c\ pluginconf.c\ - parser.c parser.h + parser.c parser.h\ + tabs.c gtkui_la_LDFLAGS = -module diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c index 737fcaa3..e031f909 100644 --- a/plugins/gtkui/callbacks.c +++ b/plugins/gtkui/callbacks.c @@ -2301,7 +2301,3 @@ on_trackproperties_delete_event (GtkWidget *widget, trackproperties = NULL; return FALSE; } - - - - diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h index 40c0048c..5070d73e 100644 --- a/plugins/gtkui/callbacks.h +++ b/plugins/gtkui/callbacks.h @@ -811,3 +811,28 @@ on_pref_dynsamplerate_clicked (GtkButton *button, void on_pref_close_clicked (GtkButton *button, gpointer user_data); + +gboolean +on_tabbar_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +gboolean +on_tabbar_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +gboolean +on_tabbar_configure_event (GtkWidget *widget, + GdkEventConfigure *event, + gpointer user_data); + +gboolean +on_tabbar_expose_event (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data); + +gboolean +on_tabbar_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer user_data); diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade index 239398b9..34ea1a3f 100644 --- a/plugins/gtkui/deadbeef.glade +++ b/plugins/gtkui/deadbeef.glade @@ -794,6 +794,23 @@ </child> <child> + <widget class="GtkDrawingArea" id="tabbar"> + <property name="height_request">24</property> + <property name="visible">True</property> + <signal name="button_press_event" handler="on_tabbar_button_press_event" last_modification_time="Sun, 07 Feb 2010 19:07:32 GMT"/> + <signal name="button_release_event" handler="on_tabbar_button_release_event" last_modification_time="Sun, 07 Feb 2010 19:07:35 GMT"/> + <signal name="configure_event" handler="on_tabbar_configure_event" last_modification_time="Sun, 07 Feb 2010 19:07:41 GMT"/> + <signal name="expose_event" handler="on_tabbar_expose_event" last_modification_time="Sun, 07 Feb 2010 19:07:50 GMT"/> + <signal name="motion_notify_event" handler="on_tabbar_motion_notify_event" last_modification_time="Sun, 07 Feb 2010 19:08:05 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> <widget class="GtkFrame" id="frame1"> <property name="border_width">1</property> <property name="visible">True</property> @@ -811,6 +828,24 @@ <property name="column_spacing">0</property> <child> + <widget class="GtkVScrollbar" id="playscroll"> + <property name="visible">True</property> + <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> + <property name="inverted">False</property> + <property name="adjustment">0 0 1 1 0 0</property> + <signal name="value_changed" handler="on_playscroll_value_changed" last_modification_time="Sat, 04 Jul 2009 01:42:24 GMT"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> <widget class="GtkHBox" id=" "> <property name="visible">True</property> <property name="homogeneous">False</property> @@ -885,24 +920,6 @@ </child> <child> - <widget class="GtkVScrollbar" id="playscroll"> - <property name="visible">True</property> - <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> - <property name="inverted">False</property> - <property name="adjustment">0 0 1 1 0 0</property> - <signal name="value_changed" handler="on_playscroll_value_changed" last_modification_time="Sat, 04 Jul 2009 01:42:24 GMT"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - <property name="x_options">fill</property> - <property name="y_options">fill</property> - </packing> - </child> - - <child> <widget class="GtkHScrollbar" id="playhscroll"> <property name="visible">True</property> <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> diff --git a/plugins/gtkui/gdkdrawing.c b/plugins/gtkui/gdkdrawing.c index b2fe9710..29238689 100644 --- a/plugins/gtkui/gdkdrawing.c +++ b/plugins/gtkui/gdkdrawing.c @@ -142,9 +142,14 @@ draw_text_with_colors (float x, float y, int width, int align, const char *text) void draw_get_text_extents (const char *text, int len, int *w, int *h) { draw_init_font (); + pango_layout_set_width (pangolayout, 1000 * PANGO_SCALE); + pango_layout_set_alignment (pangolayout, PANGO_ALIGN_LEFT); pango_layout_set_text (pangolayout, text, len); - PangoRectangle ext; - pango_layout_get_pixel_extents (pangolayout, &ext, NULL); - *w = ext.width; - *h = ext.height; + PangoRectangle ink; + PangoRectangle log; + pango_layout_get_pixel_extents (pangolayout, &ink, &log); + *w = ink.width; + *h = ink.height; + printf ("ink: %d %d %d %d\n", ink.x, ink.y, ink.width, ink.height); + printf ("log: %d %d %d %d\n", log.x, log.y, log.width, log.height); } diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c index 797186a7..c0897f13 100644 --- a/plugins/gtkui/interface.c +++ b/plugins/gtkui/interface.c @@ -110,13 +110,14 @@ create_mainwin (void) GtkWidget *image5; GtkWidget *seekbar; GtkWidget *volumebar; + GtkWidget *tabbar; GtkWidget *frame1; GtkWidget *table1; + GtkWidget *playscroll; GtkWidget *_; GtkWidget *vbox3; GtkWidget *header; GtkWidget *playlist; - GtkWidget *playscroll; GtkWidget *playhscroll; GtkWidget *statusbar; GtkAccelGroup *accel_group; @@ -501,6 +502,11 @@ create_mainwin (void) gtk_widget_set_size_request (volumebar, 70, -1); gtk_widget_set_events (volumebar, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + tabbar = gtk_drawing_area_new (); + gtk_widget_show (tabbar); + gtk_box_pack_start (GTK_BOX (vbox1), tabbar, FALSE, TRUE, 0); + gtk_widget_set_size_request (tabbar, -1, 24); + frame1 = gtk_frame_new (NULL); gtk_widget_show (frame1); gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 0); @@ -510,6 +516,12 @@ create_mainwin (void) gtk_widget_show (table1); gtk_container_add (GTK_CONTAINER (frame1), table1); + playscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 1, 1, 0, 0))); + gtk_widget_show (playscroll); + gtk_table_attach (GTK_TABLE (table1), playscroll, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + _ = gtk_hbox_new (FALSE, 0); gtk_widget_show (_); gtk_table_attach (GTK_TABLE (table1), _, 0, 1, 0, 1, @@ -531,12 +543,6 @@ create_mainwin (void) gtk_box_pack_start (GTK_BOX (vbox3), playlist, TRUE, TRUE, 0); gtk_widget_set_events (playlist, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); - playscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 1, 1, 0, 0))); - gtk_widget_show (playscroll); - gtk_table_attach (GTK_TABLE (table1), playscroll, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - playhscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 0, 0, 0, 0))); gtk_widget_show (playhscroll); gtk_table_attach (GTK_TABLE (table1), playhscroll, 0, 1, 1, 2, @@ -700,6 +706,24 @@ create_mainwin (void) g_signal_connect ((gpointer) volumebar, "scroll_event", G_CALLBACK (on_volumebar_scroll_event), NULL); + g_signal_connect ((gpointer) tabbar, "button_press_event", + G_CALLBACK (on_tabbar_button_press_event), + NULL); + g_signal_connect ((gpointer) tabbar, "button_release_event", + G_CALLBACK (on_tabbar_button_release_event), + NULL); + g_signal_connect ((gpointer) tabbar, "configure_event", + G_CALLBACK (on_tabbar_configure_event), + NULL); + g_signal_connect ((gpointer) tabbar, "expose_event", + G_CALLBACK (on_tabbar_expose_event), + NULL); + g_signal_connect ((gpointer) tabbar, "motion_notify_event", + G_CALLBACK (on_tabbar_motion_notify_event), + NULL); + g_signal_connect ((gpointer) playscroll, "value_changed", + G_CALLBACK (on_playscroll_value_changed), + NULL); g_signal_connect ((gpointer) header, "expose_event", G_CALLBACK (on_header_expose_event), NULL); @@ -766,9 +790,6 @@ create_mainwin (void) g_signal_connect ((gpointer) playlist, "drag_data_delete", G_CALLBACK (on_playlist_drag_data_delete), NULL); - g_signal_connect ((gpointer) playscroll, "value_changed", - G_CALLBACK (on_playscroll_value_changed), - NULL); g_signal_connect ((gpointer) playhscroll, "value_changed", G_CALLBACK (on_playhscroll_value_changed), NULL); @@ -853,13 +874,14 @@ create_mainwin (void) GLADE_HOOKUP_OBJECT (mainwin, image5, "image5"); GLADE_HOOKUP_OBJECT (mainwin, seekbar, "seekbar"); GLADE_HOOKUP_OBJECT (mainwin, volumebar, "volumebar"); + GLADE_HOOKUP_OBJECT (mainwin, tabbar, "tabbar"); GLADE_HOOKUP_OBJECT (mainwin, frame1, "frame1"); GLADE_HOOKUP_OBJECT (mainwin, table1, "table1"); + GLADE_HOOKUP_OBJECT (mainwin, playscroll, "playscroll"); GLADE_HOOKUP_OBJECT (mainwin, _, "_"); GLADE_HOOKUP_OBJECT (mainwin, vbox3, "vbox3"); GLADE_HOOKUP_OBJECT (mainwin, header, "header"); GLADE_HOOKUP_OBJECT (mainwin, playlist, "playlist"); - GLADE_HOOKUP_OBJECT (mainwin, playscroll, "playscroll"); GLADE_HOOKUP_OBJECT (mainwin, playhscroll, "playhscroll"); GLADE_HOOKUP_OBJECT (mainwin, statusbar, "statusbar"); diff --git a/plugins/gtkui/tabs.c b/plugins/gtkui/tabs.c new file mode 100644 index 00000000..43810498 --- /dev/null +++ b/plugins/gtkui/tabs.c @@ -0,0 +1,169 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "../../deadbeef.h" +#include <gtk/gtk.h> +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif +#include <string.h> +#include "gtkui.h" +#include "interface.h" +#include "support.h" +#include "drawing.h" + +static int tab_dragging = -1; +static int tab_movepos; + +gboolean +on_tabbar_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + + return FALSE; +} + + +gboolean +on_tabbar_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + + return FALSE; +} + + +gboolean +on_tabbar_configure_event (GtkWidget *widget, + GdkEventConfigure *event, + gpointer user_data) +{ + + return FALSE; +} + + +gboolean +on_tabbar_expose_event (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + GdkDrawable *backbuf = widget->window; + int hscrollpos = 0; + int x = -hscrollpos; + int w = 0; + int h = widget->allocation.height; + const char *detail = "button"; + int cnt = deadbeef->plt_get_count (); + int tab_selected = deadbeef->plt_get_curr (); + + // fill background + gdk_draw_rectangle (backbuf, widget->style->bg_gc[GTK_STATE_NORMAL], TRUE, 0, 0, widget->allocation.width, widget->allocation.height); + draw_begin ((uintptr_t)backbuf); + int need_draw_moving = 0; + int idx; + int widths[cnt]; + int fullwidth = 0; + for (idx = 0; idx < cnt; idx++) { + const char *title = deadbeef->plt_get_title (idx); + widths[idx] = 0; + int h = 0; + draw_get_text_extents (title, strlen (title), &widths[idx], &h); + widths[idx] += 10; + printf ("width %s %d %d\n", title, strlen (title), widths[idx]); + fullwidth += widths[idx]; + printf ("fullwidth %d\n", fullwidth); + } + x = -hscrollpos + fullwidth/* - widths[cnt-1]*/; + for (idx = cnt-1; idx >= 0; idx--) { + w = widths[idx]; + x -= w; + GdkRectangle area; + area.x = x; + area.y = 0; + area.width = w+5; + area.height = 24; + if (idx != tab_selected) { + gtk_paint_box (widget->style, widget->window, idx == tab_selected ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, GTK_SHADOW_OUT, &area, widget, "button", x, idx == tab_selected ? 0 : 1, w+5, 32); + 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); + const char *tab_title = deadbeef->plt_get_title (idx); + draw_text (x + 10, h/2-draw_get_font_size()/2, w, 0, tab_title); + } + } + gdk_draw_line (backbuf, widget->style->dark_gc[GTK_STATE_NORMAL], 0, widget->allocation.height-1, widget->allocation.width, widget->allocation.height-1); + // draw selected + { + idx = tab_selected; + w = widths[idx]; + x = -hscrollpos + fullwidth - w; + GdkRectangle area; + area.x = x; + area.y = 0; + area.width = w+5; + area.height = 24; + gtk_paint_box (widget->style, widget->window, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, &area, widget, "button", x, idx == tab_selected ? 0 : 1, w+5, 32); + 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); + const char *tab_title = deadbeef->plt_get_title (idx); + draw_text (x + 10, h/2-draw_get_font_size()/2, w, 0, tab_title); + } + + if (need_draw_moving) { + x = -hscrollpos; + for (idx = 0; idx < 10; idx++) { + w = widths[idx]; + if (idx == tab_dragging) { + // draw empty slot + if (x < widget->allocation.width) { + gtk_paint_box (widget->style, backbuf, GTK_STATE_ACTIVE, GTK_SHADOW_ETCHED_IN, NULL, widget, "button", x, 0, w, h); + } + x = tab_movepos; + if (x >= widget->allocation.width) { + break; + } + if (w > 0) { + gtk_paint_box (widget->style, backbuf, GTK_STATE_SELECTED, GTK_SHADOW_OUT, NULL, widget, "button", x, 0, w, h); + 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, tab_width-10, 0, tab_title); + } + break; + } + x += w; + } + } + draw_end (); + return FALSE; +} + + +gboolean +on_tabbar_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer user_data) +{ + + return FALSE; +} + |