changeset 4728:ab79ddbdcf42

introduce new playlist widget
author Tomasz Mon <desowin@gmail.com>
date Thu, 17 Jul 2008 00:18:16 +0200
parents b53704474dd4
children 5e70c200eb8d
files src/audacious/Makefile src/audacious/playlist.c src/audacious/ui_new.c src/audacious/ui_playlist_widget.c src/audacious/ui_playlist_widget.h
diffstat 5 files changed, 336 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/Makefile	Wed Jul 16 16:37:42 2008 -0500
+++ b/src/audacious/Makefile	Thu Jul 17 00:18:16 2008 +0200
@@ -86,6 +86,7 @@
        legacy/ui_skinned_playlist.c				\
        legacy/ui_skinselector.c					\
        ui_urlopener.c					\
+       ui_playlist_widget.c				\
 
 ifeq ($(USE_DBUS),yes)
 SRCS += dbus.c
--- a/src/audacious/playlist.c	Wed Jul 16 16:37:42 2008 -0500
+++ b/src/audacious/playlist.c	Thu Jul 17 00:18:16 2008 +0200
@@ -1212,8 +1212,8 @@
 
     if (restart_playing)
         playback_initiate();
-
-    hook_call("playlist update", playlist);
+    else
+        hook_call("playlist update", playlist);
 }
 
 void
--- a/src/audacious/ui_new.c	Wed Jul 16 16:37:42 2008 -0500
+++ b/src/audacious/ui_new.c	Thu Jul 17 00:18:16 2008 +0200
@@ -25,9 +25,11 @@
 #include "playlist.h"
 #include "ui_fileopener.h"
 #include "ui_new.h"
+#include "ui_playlist_widget.h"
 
 static GtkWidget *label_prev, *label_current, *label_next, *label_time;
 static GtkWidget *slider;
+static GtkWidget *treeview;
 
 static gulong slider_change_handler_id;
 static gboolean slider_is_moving = FALSE;
@@ -105,6 +107,8 @@
 
     g_free(esc_title);
     g_free(title);
+
+    ui_playlist_widget_set_current(treeview, playlist_get_position(playlist_get_active()));
 }
 
 static void
@@ -113,6 +117,8 @@
     gchar *text = playlist_get_info_text(playlist);
     ui_set_song_info(text, NULL);
     g_free(text);
+
+    ui_playlist_widget_update(treeview);
 }
 
 static void
@@ -213,6 +219,7 @@
     }
 
     ui_clear_song_info();
+    ui_playlist_widget_set_current(treeview, -1);
 }
 
 static void
@@ -277,6 +284,8 @@
                            and some control elements like position bar */
     GtkWidget *shbox;   /* box for slider + time combo --nenolod */
 
+    GtkWidget *scrollwin;   /* widget to hold playlist widget */
+
     GtkToolItem *button_open, *button_add,
                 *button_play, *button_pause, *button_stop,
                 *button_previous, *button_next;
@@ -329,7 +338,7 @@
     gtk_box_pack_start(GTK_BOX(pcnbox), chbox, TRUE, TRUE, 0);
     gtk_box_pack_start(GTK_BOX(pcnbox), label_next, TRUE, TRUE, 0);
 
-    gtk_box_pack_start(GTK_BOX(vbox), pcnbox, TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(vbox), pcnbox, FALSE, TRUE, 0);
 
     shbox = gtk_hbox_new(FALSE, 0);
     gtk_box_pack_end(GTK_BOX(cvbox), shbox, TRUE, TRUE, 0);
@@ -343,6 +352,16 @@
     label_time = gtk_markup_label_new(NULL);
     gtk_box_pack_start(GTK_BOX(shbox), label_time, FALSE, FALSE, 0);
 
+    treeview = ui_playlist_widget_new();
+    scrollwin = gtk_scrolled_window_new(NULL, NULL);
+    gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
+                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
+                                        GTK_SHADOW_IN);
+
+    gtk_box_pack_end(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
+
     ui_hooks_associate();
 
     slider_change_handler_id =
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_playlist_widget.c	Thu Jul 17 00:18:16 2008 +0200
@@ -0,0 +1,284 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2008 Tomasz Moń <desowin@gmail.com>
+ *
+ *  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "playlist.h"
+#include "playback.h"
+#include "strings.h"
+
+enum {
+    COLUMN_NUM = 0,
+    COLUMN_TEXT,
+    COLUMN_TIME,
+    COLUMN_WEIGHT,
+    N_COLUMNS
+};
+
+static void
+ui_playlist_widget_change_song(guint pos)
+{
+    playlist_set_position(playlist_get_active(), pos);
+
+    if (!playback_get_playing())
+        playback_initiate();
+}
+
+void
+ui_playlist_widget_set_current(GtkWidget *treeview, gint pos)
+{
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    GtkTreePath *path;
+    gchar *p;
+
+    model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
+
+    gint old_pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(treeview), "current"));
+
+    if (old_pos != -1) {
+        p = g_strdup_printf("%d", old_pos);
+        path = gtk_tree_path_new_from_string(p);
+        gtk_tree_model_get_iter(model, &iter, path);
+        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 3, PANGO_WEIGHT_NORMAL, -1);
+        g_free(p);
+        gtk_tree_path_free(path);
+    }
+
+    if (pos != -1) {
+        p = g_strdup_printf("%d", pos);
+        path = gtk_tree_path_new_from_string(p);
+        gtk_tree_model_get_iter(model, &iter, path);
+        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 3, PANGO_WEIGHT_BOLD, -1);
+        g_free(p);
+        gtk_tree_path_free(path);
+    }
+
+    g_object_set_data(G_OBJECT(treeview), "current", GINT_TO_POINTER(pos));
+}
+
+static void
+ui_playlist_widget_jump(GtkTreeView * treeview, gpointer data)
+{
+    GtkTreeModel *model;
+    GtkTreeSelection *selection;
+    GtkTreeIter iter;
+    guint pos;
+
+    model = gtk_tree_view_get_model(treeview);
+    selection = gtk_tree_view_get_selection(treeview);
+
+    if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
+        return;
+
+    gtk_tree_model_get(model, &iter, 0, &pos, -1);
+
+    ui_playlist_widget_change_song(pos - 1);
+
+    ui_playlist_widget_set_current(GTK_WIDGET(treeview), pos);
+}
+
+static gboolean
+ui_playlist_widget_keypress_cb(GtkWidget * widget,
+                            GdkEventKey * event,
+                            gpointer data)
+{
+    switch (event->keyval) {
+    case GDK_KP_Enter:
+        ui_playlist_widget_jump(GTK_TREE_VIEW(widget), NULL);
+        return TRUE;
+    default:
+        return FALSE;
+    };
+}
+
+void
+ui_playlist_widget_update(GtkWidget *widget)
+{
+    guint row;
+    gboolean valid;
+
+    GList *playlist_glist;
+    gchar *desc_buf = NULL;
+    gchar *length = NULL;
+    GtkTreeIter iter;
+    Playlist *playlist;
+    GtkTreeModel *store;
+    GtkTreeView *tree = GTK_TREE_VIEW(widget);
+
+    store = gtk_tree_view_get_model(tree);
+    valid = gtk_tree_model_get_iter_first(store, &iter);
+
+    row = 1;
+    playlist = playlist_get_active();
+
+    for (playlist_glist = playlist->entries; playlist_glist;
+         playlist_glist = g_list_next(playlist_glist)) {
+        PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
+
+        if (entry->title)
+            desc_buf = g_strdup(entry->title);
+        else {
+            gchar *realfn = NULL;
+            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
+            if (strchr(realfn ? realfn : entry->filename, '/'))
+                desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
+            else
+                desc_buf = str_assert_utf8(realfn ? realfn : entry->filename);
+            g_free(realfn); realfn = NULL;
+        }
+
+        if (entry->length != -1) {
+            length = g_strdup_printf("%d:%-2.2d", entry->length / 60000, (entry->length / 1000) % 60);
+        }
+
+        if (!valid)
+            gtk_list_store_append(GTK_LIST_STORE(store), &iter);
+        gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+                           COLUMN_NUM, row, COLUMN_TEXT, desc_buf,
+                           COLUMN_TIME, length,
+                           COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL, -1);
+        row++;
+
+        g_free(desc_buf);
+        desc_buf = NULL;
+
+        if (length) g_free(length);
+        length = NULL;
+
+        valid = gtk_tree_model_iter_next(store, &iter);
+    }
+
+    /* remove additional rows */
+    while (valid) {
+        valid = gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
+    }
+
+    ui_playlist_widget_set_current(widget, playlist_get_position(playlist));
+}
+
+static gboolean
+ui_playlist_widget_fill(gpointer treeview)
+{
+    GList *playlist_glist;
+    Playlist *playlist;
+    gchar *desc_buf = NULL;
+    gchar *length = NULL;
+    guint row;
+    GtkTreeIter iter;
+    GtkListStore *store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(treeview) );
+
+    /* detach model from treeview before fill */
+    g_object_ref(store);
+    gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL );
+
+    gtk_list_store_clear(store);
+
+    row = 1;
+    playlist = playlist_get_active();
+
+    PLAYLIST_LOCK(playlist);
+    for (playlist_glist = playlist->entries; playlist_glist;
+         playlist_glist = g_list_next(playlist_glist)) {
+
+        PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
+
+        if (entry->title)
+            desc_buf = g_strdup(entry->title);
+        else {
+            gchar *realfn = NULL;
+            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
+            if (strchr(realfn ? realfn : entry->filename, '/'))
+                desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
+            else
+                desc_buf = str_assert_utf8(realfn ? realfn : entry->filename);
+            g_free(realfn); realfn = NULL;
+        }
+
+        if (entry->length != -1) {
+            length = g_strdup_printf("%d:%-2.2d", entry->length / 60000, (entry->length / 1000) % 60);
+        }
+
+        gtk_list_store_append(GTK_LIST_STORE(store), &iter);
+        gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+                           COLUMN_NUM, row, COLUMN_TEXT, desc_buf,
+                           COLUMN_TIME, length,
+                           COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL, -1);
+        row++;
+
+        g_free(desc_buf);
+        desc_buf = NULL;
+
+        if (length) g_free(length);
+        length = NULL;
+    }
+    PLAYLIST_UNLOCK(playlist);
+
+    /* attach liststore to treeview */
+    gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(store));
+    g_object_unref(store);
+
+    return FALSE;
+}
+
+GtkWidget *
+ui_playlist_widget_new(void)
+{
+    GtkWidget *treeview;
+    GtkListStore *store;
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+
+    store = gtk_list_store_new(N_COLUMNS, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, PANGO_TYPE_WEIGHT);
+    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+    g_object_unref(store);
+
+    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
+    gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+    gtk_tree_view_column_set_spacing(column, 4);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_set_attributes(column, renderer, "text", COLUMN_NUM, NULL);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, TRUE);
+    gtk_tree_view_column_set_attributes(column, renderer, "text", COLUMN_TEXT, "weight", COLUMN_WEIGHT, NULL);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_set_attributes(column, renderer, "text", COLUMN_TIME, NULL);
+
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+    g_signal_connect(treeview, "row-activated",
+                     G_CALLBACK(ui_playlist_widget_jump), NULL);
+
+    g_signal_connect(treeview, "key-press-event",
+                     G_CALLBACK(ui_playlist_widget_keypress_cb), NULL);
+
+    ui_playlist_widget_fill(treeview);
+
+    g_object_set_data(G_OBJECT(treeview), "current", GINT_TO_POINTER(-1));
+
+    return treeview;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_playlist_widget.h	Thu Jul 17 00:18:16 2008 +0200
@@ -0,0 +1,29 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2008 Tomasz Moń <desowin@gmail.com>
+ *
+ *  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#ifndef UI_PLAYLIST_WIDGET_H
+#define UI_PLAYLIST_WIDGET_H
+
+#include <gtk/gtk.h>
+
+void ui_playlist_widget_set_current(GtkWidget *treeview, gint pos);
+void ui_playlist_widget_update(GtkWidget *widget);
+GtkWidget * ui_playlist_widget_new(void);
+
+#endif