ocarina/gui/playlist.c

260 lines
6.4 KiB
C

/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/string.h>
#include <gui/filter.h>
#include <gui/model.h>
#include <gui/playlist.h>
#include <gui/treeview.h>
#include <gui/sidebar.h>
static void (*update_size[PL_MAX_TYPE])(struct playlist *) = {
[PL_SYSTEM] = gui_pl_system_update,
[PL_ARTIST] = gui_pl_artist_update,
[PL_LIBRARY] = gui_pl_library_update,
[PL_USER] = gui_pl_user_update,
};
static void (*select_playlist[PL_MAX_TYPE])(struct playlist *) = {
[PL_SYSTEM] = gui_pl_system_select,
[PL_ARTIST] = gui_pl_artist_select,
[PL_LIBRARY] = gui_pl_library_select,
[PL_USER] = gui_pl_user_select,
};
static inline void __gui_playlist_update_size(struct playlist *playlist)
{
update_size[playlist->pl_type](playlist);
}
static void __gui_playlist_alloc(struct playlist *playlist)
{
if (playlist->pl_type == PL_ARTIST)
gui_pl_artist_add(playlist);
}
static void __gui_playlist_added(struct playlist *playlist, struct track *track)
{
gui_model_add(playlist, track);
gui_filter_refilter(playlist);
__gui_playlist_update_size(playlist);
}
static void __gui_playlist_removed(struct playlist *playlist, struct track *track,
unsigned int n)
{
gui_model_remove(playlist, track, n);
__gui_playlist_update_size(playlist);
}
struct playlist_callbacks playlist_cb = {
.pl_cb_alloc = __gui_playlist_alloc,
.pl_cb_added = __gui_playlist_added,
.pl_cb_removed = __gui_playlist_removed,
.pl_cb_updated = gui_model_update,
};
static void __gui_playlist_add_selected_to(struct playlist *playlist)
{
GList *cur, *list = NULL;
struct track *track;
if (!playlist)
return;
list = gui_treeview_list_selected_tracks();
cur = g_list_first(list);
while (cur) {
track = (struct track *)cur->data;
playlist_add(playlist, track);
cur = g_list_next(cur);
}
g_list_free(list);
}
void __gui_playlist_add_favorites(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(playlist_lookup(PL_SYSTEM, "Favorites"));
}
void __gui_playlist_add_hidden(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(playlist_lookup(PL_SYSTEM, "Hidden"));
}
void __gui_playlist_add_user(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(gui_pl_user_add_dialog());
}
void __gui_playlist_add_other(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(data);
}
void __gui_playlist_add_queued(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(playlist_lookup(PL_SYSTEM, "Queued Tracks"));
}
void __gui_playlist_delete(GtkMenuItem *item, gpointer data)
{
struct playlist *playlist = gui_model_get_playlist();
GList *cur, *list = NULL;
struct track *track;
if (!playlist)
return;
list = gui_treeview_list_selected_tracks();
cur = g_list_first(list);
while (cur) {
track = (struct track *)cur->data;
playlist_remove(playlist, track);
cur = g_list_next(cur);
}
g_list_free(list);
}
void __gui_playlist_keypress(GtkTreeView *treeview, GdkEventKey *event,
gpointer data)
{
switch (event->keyval) {
case GDK_KEY_f:
__gui_playlist_add_favorites(NULL, NULL);
break;
case GDK_KEY_h:
__gui_playlist_add_hidden(NULL, NULL);
break;
case GDK_KEY_p:
__gui_playlist_add_user(NULL, NULL);
break;
case GDK_KEY_q:
__gui_playlist_add_queued(NULL, NULL);
break;
case GDK_KEY_Delete:
__gui_playlist_delete(NULL, NULL);
default:
break;
}
}
static GtkWidget *__gui_playlist_build_submenu(void)
{
struct playlist *playlist;
GList *list = gui_pl_user_list();
GList *cur = g_list_first(list);
GtkWidget *submenu, *item;
if (!list)
return NULL;
submenu = gtk_menu_new();
while (cur) {
playlist = (struct playlist *)cur->data;
item = gtk_menu_item_new_with_label(playlist->pl_name);
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
g_signal_connect(item, "activate",
G_CALLBACK(__gui_playlist_add_other),
playlist);
cur = g_list_next(cur);
}
gtk_widget_show_all(submenu);
g_list_free(list);
return submenu;
}
bool __gui_playlist_button_press(GtkTreeView *treeview, GdkEventButton *event,
gpointer data)
{
GtkWidget *submenu;
if (event->button != GDK_BUTTON_SECONDARY)
return false;
submenu = __gui_playlist_build_submenu();
gtk_menu_item_set_submenu(gui_rc_add_to_other(), submenu);
gtk_widget_set_visible(GTK_WIDGET(gui_rc_add_to_other()),
submenu != NULL);
gui_treeview_select_path_at_pos(event->x, event->y);
gtk_menu_popup_at_pointer(gui_rc_menu(), (GdkEvent *)event);
return true;
}
void __gui_playlist_row_activated(GtkTreeView *treeview, GtkTreePath *path,
GtkTreeViewColumn *col, gpointer data)
{
struct playlist *prev = playlist_current();
gui_sidebar_filter_path_select(path);
__gui_playlist_update_size(prev);
__gui_playlist_update_size(playlist_current());
}
void __gui_playlist_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter,
GtkTreePath *path, gpointer data)
{
gui_sidebar_filter_row_expanded(iter, false);
}
void __gui_playlist_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter,
GtkTreePath *path, gpointer data)
{
gui_sidebar_filter_row_expanded(iter, true);
}
void __gui_playlist_drag_data_received(GtkTreeView *treeview, GdkDragContext *context,
gint x, gint y, GtkSelectionData *data,
guint info, guint time, gpointer user_data)
{
struct playlist *playlist;
GtkTreeIter iter;
if (gui_sidebar_iter_from_xy(x, y, &iter))
playlist = gui_sidebar_iter_playlist(&iter);
if (!playlist)
playlist = gui_pl_user_add_dialog();
if (!playlist)
goto out;
if (playlist == playlist_lookup(PL_SYSTEM, "Collection") &&
gui_model_get_playlist() == playlist_lookup(PL_SYSTEM, "Hidden"))
__gui_playlist_delete(NULL, NULL);
else if (playlist != playlist_lookup(PL_SYSTEM, "History"))
__gui_playlist_add_selected_to(playlist);
out:
g_signal_stop_emission_by_name(treeview, "drag_data_received");
gtk_drag_finish(context, true, true, time);
}
bool __gui_playlist_init_idle()
{
struct playlist *playlist = playlist_current();
GtkTreeModel *filter = GTK_TREE_MODEL(gui_sidebar_filter());
GtkTreeIter iter;
gtk_tree_model_get_iter_first(filter, &iter);
do {
gui_sidebar_filter_set_expand(&iter);
} while (gtk_tree_model_iter_next(filter, &iter));
select_playlist[playlist->pl_type](playlist);
return true;
}
void gui_playlist_init()
{
gui_pl_system_init();
gui_pl_artist_init();
gui_pl_user_init();
gui_pl_library_init();
idle_schedule(IDLE_SYNC, __gui_playlist_init_idle, NULL);
}