ocarina/ocarina/playlist.cpp

320 lines
8.6 KiB
C++
Raw Normal View History

// Copyright (c) 2011 Bryan Schumaker
#include <libsaria/libsaria.h>
#include <libsaria/library.h>
#include <libsaria/format.h>
#include <libsaria/print.h>
#include <libsaria/deck.h>
#include <libsaria/ban.h>
#include <ocarina/ocarina.h>
#include <cstdio>
#include <sstream>
using namespace std;
struct PlaylistWidgets {
libsaria::Playlist *playlist;
GtkListStore *liststore;
GtkTreeView *treeview;
GtkTreeModel *filter;
GtkLabel *label;
GtkEntry *entry;
};
static PlaylistWidgets library_widgets;
static PlaylistWidgets recent_widgets;
static PlaylistWidgets banned_widgets;
static GtkWidget *focused_entry = NULL;
static string formatted(string str)
{
char *escaped = g_markup_escape_text(str.c_str(), -1);
string ret = escaped;
g_free(escaped);
return ret;
}
static struct PlaylistWidgets *find_widgets(libsaria::Playlist *plist)
{
if (plist == library_widgets.playlist)
return &library_widgets;
else if (plist == recent_widgets.playlist)
return &recent_widgets;
else if (plist == banned_widgets.playlist)
return &banned_widgets;
return NULL;
}
static unsigned int tabs_size()
{
GtkNotebook *tabs = GTK_NOTEBOOK(get_widget("PlaylistTabs"));
return gtk_notebook_get_n_pages(tabs) - 3;
}
static struct PlaylistWidgets *find_nth_widgets(unsigned int n)
{
unsigned int size = tabs_size();
/* Dynamic playlists */
if (n < size)
return NULL;
switch (n - size) {
case 0:
return &library_widgets;
case 1:
return &recent_widgets;
case 2:
return &banned_widgets;
}
return NULL;
}
static struct PlaylistWidgets *current_widgets()
{
GtkNotebook *tabs = GTK_NOTEBOOK(get_widget("PlaylistTabs"));
return find_nth_widgets(gtk_notebook_get_current_page(tabs));
}
static libsaria::Playlist *find_playlist(unsigned int n)
{
return find_nth_widgets(n)->playlist;
}
static libsaria::Playlist *current_playlist()
{
return current_widgets()->playlist;
}
void playlist_switch_to(string &key)
{
GtkNotebook *tabs = GTK_NOTEBOOK(get_widget("PlaylistTabs"));
unsigned int size = tabs_size();
if (key == "l")
gtk_notebook_set_current_page(tabs, size);
else if (key == "r")
gtk_notebook_set_current_page(tabs, size + 1);
else if (key == "b")
gtk_notebook_set_current_page(tabs, size + 2);
}
static gboolean is_visible(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
libsaria::Track *track;
libsaria::Playlist *plist = (libsaria::Playlist *)data;
gtk_tree_model_get(model, iter, 0, &track, -1);
return plist->is_visible(track);
}
static void do_filter(GtkWidget *entry, gpointer d)
{
string text = gtk_entry_get_text(GTK_ENTRY(entry));
libsaria::Playlist *plist = (libsaria::Playlist *)d;
plist->set_filter_text(text);
}
static gboolean on_focus_change(GtkWidget *entry, GdkEvent *event, gpointer data)
{
if (gtk_widget_is_focus(entry))
focused_entry = entry;
return FALSE;
}
bool playlist_entry_focused()
{
if (!focused_entry)
return false;
return gtk_widget_is_focus(focused_entry);
}
void playlist_focus_entry()
{
gtk_widget_grab_focus(GTK_WIDGET(current_widgets()->entry));
}
void playlist_focus_treeview()
{
gtk_widget_grab_focus(GTK_WIDGET(current_widgets()->treeview));
}
static void track_selected(GtkWidget *treeview, GtkTreePath *path,
GtkTreeViewColumn *col, gpointer data)
{
GtkTreeIter iter;
GtkTreeModel *model;
libsaria::Track *track;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, 0, &track, -1);
track->load(true);
}
static void set_playlist_length(libsaria::Playlist *playlist)
{
stringstream stream;
unsigned int size = playlist->get_size();
stream << size << " song";
if (size != 1)
stream << "s";
if (size != 0)
stream << ": " << libsaria::length_string(playlist->get_length());
update_length_label(stream.str());
}
static void update_track(libsaria::Track *track, GtkListStore *liststore,
GtkTreeIter *iter)
{
gtk_list_store_set(liststore, iter,
0, track,
1, track->get_track(),
2, track->get_title().c_str(),
3, track->get_lenstr().c_str(),
4, track->get_artist().c_str(),
5, track->get_album().c_str(),
6, track->get_year(),
7, track->get_count(),
8, track->get_last_played().c_str(),
9, formatted(track->get_filepath()).c_str(),
-1);
}
static void playlist_add(libsaria::Playlist *plist, libsaria::Track *track,
unsigned int index)
{
GtkTreeIter iter;
struct PlaylistWidgets *widgets = find_widgets(plist);
if (!widgets)
return;
gtk_list_store_insert(widgets->liststore, &iter, index);
update_track(track, widgets->liststore, &iter);
}
static void playlist_rm(libsaria::Playlist *plist, unsigned int index)
{
GtkTreeIter iter;
PlaylistWidgets *widgets = find_widgets(plist);
gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(widgets->liststore), &iter, NULL, index);
gtk_list_store_remove(widgets->liststore, &iter);
if (plist == current_playlist())
set_playlist_length(plist);
}
static void playlist_update(libsaria::Playlist *plist, libsaria::Track *track,
unsigned int index)
{
GtkTreeIter iter;
PlaylistWidgets *widgets = find_widgets(plist);
gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(widgets->liststore), &iter, NULL, index);
update_track(track, widgets->liststore, &iter);
}
static void set_playlist_size(libsaria::Playlist *plist)
{
char buf[11];
struct PlaylistWidgets *widgets = find_widgets(plist);
if (!widgets)
return;
sprintf(buf, "%u", plist->get_size());
gtk_label_set_text(widgets->label, buf);
if (plist == current_playlist())
set_playlist_length(plist);
}
static void playlist_refilter(libsaria::Playlist *plist)
{
struct PlaylistWidgets *widgets = find_widgets(plist);
if (widgets)
gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(widgets->filter));
}
void update_playlist(notify_t event, libsaria::PlaylistNotification *data)
{
if (event == PLAYLIST_ADD)
playlist_add(data->plist, data->track, data->index);
else if (event == PLAYLIST_RM)
playlist_rm(data->plist, data->index);
else if (event == PLAYLIST_SIZE)
set_playlist_size(data->plist);
else if (event == PLAYLIST_FILTER)
playlist_refilter(data->plist);
else if (event == PLAYLIST_UPDATE)
playlist_update(data->plist, data->track, data->index);
}
static void init_playlist_tab(struct PlaylistWidgets *widgets,
libsaria::Playlist *playlist,
const string &list_name,
const string &view_name,
const string &label_name,
const string &entry_name)
{
widgets->playlist = playlist;
widgets->liststore = GTK_LIST_STORE(get_object(list_name));
widgets->treeview = GTK_TREE_VIEW(get_widget(view_name));
widgets->filter = gtk_tree_model_filter_new(
GTK_TREE_MODEL(widgets->liststore), NULL);
widgets->label = GTK_LABEL(get_widget(label_name));
widgets->entry = GTK_ENTRY(get_widget(entry_name));
gtk_tree_view_set_model(widgets->treeview, widgets->filter);
gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(widgets->filter),
is_visible, playlist, NULL);
connect_signal(view_name, "row-activated", G_CALLBACK(track_selected), NULL);
connect_signal(entry_name, "changed", G_CALLBACK(do_filter), playlist);
connect_signal(entry_name, "focus-in-event", G_CALLBACK(on_focus_change), NULL);
}
static void on_switch_page(GtkNotebook *tabs, gpointer page,
unsigned int page_num, gpointer data)
{
set_playlist_length(find_playlist(page_num));
}
static void on_click_open(GtkWidget *b, gpointer d)
{
string file = run_chooser("FileChooser");
if (file != "") {
println("Playing file: " + file);
libsaria::play_outside_song(file);
}
}
static void init_tab_action()
{
GtkWidget *box = gtk_vbox_new(FALSE, 0);
GtkWidget *img = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
GtkWidget *open = gtk_button_new();
gtk_button_set_image(GTK_BUTTON(open), img);
g_signal_connect(open, "clicked", G_CALLBACK(on_click_open), NULL);
gtk_box_pack_start(GTK_BOX(box), open, false, false, 0);
gtk_box_pack_start(GTK_BOX(box), get_widget("BanButton"), false, false, 0);
gtk_widget_show_all(box);
gtk_notebook_set_action_widget(GTK_NOTEBOOK(get_widget("PlaylistTabs")),
box, GTK_PACK_END);
}
void init_playlist()
{
init_tab_action();
init_playlist_tab(&library_widgets, libsaria::library::get_playlist(),
"LibraryPlist", "LibraryPlistView",
"LibrarySize", "LibraryEntry");
init_playlist_tab(&recent_widgets, libsaria::deck::get_recent_plist(),
"RecentPlist", "RecentView",
"RecentSize", "RecentEntry");
init_playlist_tab(&banned_widgets, libsaria::ban::get_banned_plist(),
"BannedPlist", "BannedView",
"BannedSize", "BannedEntry");
connect_signal("PlaylistTabs", "switch-page", G_CALLBACK(on_switch_page), NULL);
}