ocarina/gui/playlist.c

223 lines
5.8 KiB
C

/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/collection.h>
#include <core/string.h>
#include <gui/builder.h>
#include <gui/playlist.h>
#include <gui/sidebar.h>
enum playlist_sidebar_columns {
P_SB_IMAGE,
P_SB_NAME,
};
static GtkTreeStore *p_store;
static gchar *p_name = NULL;
static void __playlist_set(GtkTreeIter *iter, const gchar *name,
const gchar *image)
{
gtk_tree_store_set(p_store, iter, P_SB_NAME, name,
P_SB_IMAGE, image, -1);
}
static void __playlist_set_size(GtkTreeIter *iter, const gchar *name)
{
GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(p_store), iter);
unsigned int size = playlist_size(name);
const gchar *fmt = "%s\n%d track%s";
gchar *text;
if (gtk_tree_path_get_depth(path) == 1)
fmt = "<b>%s</b>\n%d track%s";
text = g_strdup_printf(fmt, name, size, (size == 1) ? "" : "s");
gtk_tree_store_set(p_store, iter, P_SB_NAME, text, -1);
gtk_tree_path_free(path);
g_free(text);
}
static void __playlist_add(GtkTreeIter *parent, const gchar *name,
const gchar *image)
{
GtkTreeIter iter;
gtk_tree_store_insert(p_store, &iter, parent, -1);
__playlist_set(&iter, name, image);
__playlist_set_size(&iter, name);
}
static gchar *__playlist_name(GtkTreeIter *iter)
{
GtkTreeModel *model = GTK_TREE_MODEL(p_store);
gchar *text, *parsed, *name, **split;
gtk_tree_model_get(model, iter, P_SB_NAME, &text, -1);
if (!text)
return NULL;
pango_parse_markup(text, -1, 0, NULL, &parsed, NULL, NULL);
split = g_strsplit(parsed, "\n", 2);
name = g_strdup(split[0]);
g_strfreev(split);
g_free(text);
g_free(parsed);
return name;
}
void __playlist_selection_changed(GtkTreeSelection *selection, gpointer data)
{
GtkStack *stack = GTK_STACK(gui_builder_widget("o_stack"));
GtkTreeModel *model = GTK_TREE_MODEL(p_store);
GtkTreeIter iter;
if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
if (p_name)
g_free(p_name);
p_name = __playlist_name(&iter);
gtk_stack_set_visible_child_name(stack, "queues");
gui_sidebar_selected(SB_PLAYLIST,
gui_queue(playlist_get_queue(p_name)));
}
}
gboolean __playlist_on_select(GtkTreeSelection *selection, GtkTreeModel *model,
GtkTreePath *path, gboolean selected, gpointer data)
{
struct queue *queue = NULL;
GtkTreeIter iter;
gchar *name;
gtk_tree_model_get_iter(model, &iter, path);
name = __playlist_name(&iter);
queue = playlist_get_queue(name);
g_free(name);
return queue != NULL;
}
static bool __playlist_queue_set_size(struct queue *queue, GtkTreeIter *iter)
{
gchar *name = __playlist_name(iter);
bool match = string_match(name, gui_queue(queue)->gq_text);
if (match)
__playlist_set_size(iter, name);
g_free(name);
return match;
}
static void __playlist_update_sizes(struct queue *queue)
{
GtkTreeModel *model = GTK_TREE_MODEL(p_store);
GtkTreeIter parent, iter;
if (!gtk_tree_model_get_iter_first(model, &parent))
return;
do {
if (__playlist_queue_set_size(queue, &parent))
return;
if (gtk_tree_model_iter_children(model, &iter, &parent)) {
do {
if (__playlist_queue_set_size(queue, &iter))
return;
} while (gtk_tree_model_iter_next(model, &iter));
}
} while (gtk_tree_model_iter_next(model, &parent));
}
static void *__playlist_init(struct queue *queue, void *data)
{
struct playlist *playlist = (struct playlist *)data;
unsigned int flags = 0;
if (string_match(playlist->pl_name, "Collection"))
flags = GQ_CAN_RANDOM;
return gui_queue_alloc(queue, playlist->pl_name, flags);
}
static void __playlist_added(struct queue *queue, unsigned int row)
{
gui_queue_added(queue, row);
__playlist_update_sizes(queue);
}
static void __playlist_removed(struct queue *queue, unsigned int row)
{
gui_queue_removed(queue, row);
__playlist_update_sizes(queue);
}
static bool __playlist_erase(struct queue *queue, struct track *track)
{
if (string_match(gui_playlist_cur(), "Collection"))
playlist_add("Hidden", track);
else if (string_match(gui_playlist_cur(), "Favorites") ||
string_match(gui_playlist_cur(), "Hidden"))
playlist_remove(gui_playlist_cur(), track);
return false;
}
void gui_playlist_init()
{
GtkTreeSelection *selection;
GtkTreeView *treeview;
GtkTreeIter parent;
GtkTreePath *path;
p_store = GTK_TREE_STORE(gui_builder_object("o_playlist_store"));
treeview = GTK_TREE_VIEW(gui_builder_widget("o_playlist_view"));
selection = gtk_tree_view_get_selection(treeview);
gtk_tree_store_insert(p_store, &parent, NULL, -1);
__playlist_set(&parent, "Collection", "media-optical");
__playlist_set_size(&parent, "Collection");
path = gtk_tree_model_get_path(GTK_TREE_MODEL(p_store), &parent);
gtk_tree_selection_select_path(selection, path);
gtk_tree_path_free(path);
gtk_tree_store_insert(p_store, &parent, NULL, -1);
__playlist_set(&parent, "History", "document-open-recent");
__playlist_set_size(&parent, "History");
/* Add "Playlist" header. */
gtk_tree_store_insert(p_store, &parent, NULL, -1);
gtk_tree_store_insert(p_store, &parent, NULL, -1);
__playlist_set(&parent, "<big>Playlists</big>", "emblem-documents");
/* Add playlists. */
__playlist_add(&parent, "Favorites", "emblem-favorite");
__playlist_add(&parent, "Hidden", "window-close");
__playlist_add(&parent, "Most Played", "go-up");
__playlist_add(&parent, "Least Played", "go-down");
__playlist_add(&parent, "Unplayed", "audio-x-generic");
gtk_tree_view_expand_all(treeview);
gtk_tree_selection_set_select_function(
gtk_tree_view_get_selection(treeview),
__playlist_on_select, NULL, NULL);
gtk_tree_store_insert(p_store, &parent, NULL, -1);
}
gchar *gui_playlist_cur()
{
return p_name;
}
struct queue_ops playlist_ops = {
.qop_init = __playlist_init,
.qop_deinit = gui_queue_free,
.qop_added = __playlist_added,
.qop_erase = __playlist_erase,
.qop_removed = __playlist_removed,
.qop_cleared = gui_queue_cleared,
.qop_updated = gui_queue_updated,
};