ocarina/gui/view.c

294 lines
7.7 KiB
C

/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/audio.h>
#include <core/playlist.h>
#include <core/settings.h>
#include <gui/builder.h>
#include <gui/filter.h>
#include <gui/queue.h>
#include <gui/treeview.h>
#include <gui/view.h>
#include <gui/window.h>
#include <glib/gi18n.h>
#include <stdlib.h>
static const gchar *QUEUE_SETTINGS[GUI_MODEL_N_COLUMNS] = {
[GUI_MODEL_TRACK_NR] = "gui.queue.track",
[GUI_MODEL_TITLE] = "gui.queue.title",
[GUI_MODEL_LENGTH] = "gui.queue.length",
[GUI_MODEL_ARTIST] = "gui.queue.artist",
[GUI_MODEL_ALBUM] = "gui.queue.album",
[GUI_MODEL_YEAR] = "gui.queue.year",
[GUI_MODEL_GENRE] = "gui.queue.genre",
[GUI_MODEL_COUNT] = "gui.queue.count",
};
static GtkTreeView *view_treeview = NULL;
static unsigned int __view_get_column_index(GtkTreeViewColumn *col)
{
unsigned int i;
if (!view_treeview)
return GUI_MODEL_N_COLUMNS;
for (i = 0; i < GUI_MODEL_N_COLUMNS; i++) {
if (col == gtk_tree_view_get_column(view_treeview, i))
return i;
}
return GUI_MODEL_N_COLUMNS;
}
void __view_column_resized(GtkTreeViewColumn *col, GParamSpec *pspec,
gpointer data)
{
unsigned int index = __view_get_column_index(col);
settings_set(QUEUE_SETTINGS[index], gtk_tree_view_column_get_width(col));
}
struct view_add_data {
enum playlist_type_t vad_type;
const gchar *vad_name;
};
static void __view_add_to_playlist(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
struct view_add_data *vad = (struct view_add_data *)data;
playlist_add(vad->vad_type, vad->vad_name, gui_filter_path_get_track(path));
}
static void __view_delete_selection(GtkTreeSelection *selection)
{
struct playlist *playlist = gui_model_get_playlist();
struct queue *queue = playlist ? &playlist->pl_queue : NULL;
GList *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
GList *cur = g_list_reverse(rows);
while (cur) {
queue_erase(queue, gui_filter_path_get_index(cur->data));
cur = g_list_next(cur);
}
g_list_free_full(rows, (GDestroyNotify) gtk_tree_path_free);
}
static gchar *__view_get_new_playlist_name(void)
{
unsigned int flags = GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL;
GtkWidget *entry, *dialog, *content;
gchar *text = NULL;
entry = gtk_entry_new();
dialog = gtk_dialog_new_with_buttons("New Playlist Name?",
gui_window(), flags,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_ACCEPT,
NULL);
content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
gtk_entry_set_activates_default(GTK_ENTRY(entry), true);
gtk_container_add(GTK_CONTAINER(content), entry);
gtk_widget_show_all(dialog);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
text = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
gtk_widget_destroy(dialog);
return text;
}
static void __view_process_selection(GtkTreeView *treeview, unsigned int keyval)
{
GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
struct view_add_data vad_data;
gchar *text = NULL;
switch (keyval) {
case GDK_KEY_f:
vad_data.vad_type = PL_SYSTEM;
vad_data.vad_name = "Favorites";
gtk_tree_selection_selected_foreach(selection,
__view_add_to_playlist,
&vad_data);
break;
case GDK_KEY_p:
text = __view_get_new_playlist_name();
if (!text || !playlist_new(PL_USER, text))
break;
vad_data.vad_type = PL_USER;
vad_data.vad_name = text;
gtk_tree_selection_selected_foreach(selection,
__view_add_to_playlist,
&vad_data);
g_free(text);
break;
case GDK_KEY_q:
vad_data.vad_type = PL_SYSTEM;
vad_data.vad_name = "Queued Tracks";
gtk_tree_selection_selected_foreach(selection,
__view_add_to_playlist,
&vad_data);
break;
case GDK_KEY_Delete:
__view_delete_selection(selection);
break;
}
}
void __view_keypress(GtkTreeView *treeview, GdkEventKey *event, gpointer data)
{
__view_process_selection(treeview, event->keyval);
}
void __view_rc_new_queue(GtkMenuItem *item, gpointer data)
{
__view_process_selection(view_treeview, GDK_KEY_q);
}
void __view_rc_add_to_queue(GtkMenuItem *item, gpointer data)
{
unsigned int i;
gchar *name;
for (i = 0; i < 10; i++) {
name = g_strdup_printf("o_queue_%d", i);
if (GTK_WIDGET(item) == gui_builder_widget(name))
__view_process_selection(view_treeview, GDK_KEY_0 + i);
g_free(name);
}
}
void __view_rc_add_favorites(GtkMenuItem *item, gpointer data)
{
__view_process_selection(view_treeview, GDK_KEY_f);
}
void __view_rc_add_hidden(GtkMenuItem *item, gpointer data)
{
GtkTreeSelection *selection = gtk_tree_view_get_selection(view_treeview);
GList *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
GList *cur = g_list_reverse(rows);
while (cur) {
playlist_add(PL_SYSTEM, "Hidden", gui_filter_path_get_track(cur->data));
cur = g_list_next(cur);
}
g_list_free_full(rows, (GDestroyNotify) gtk_tree_path_free);
}
void __view_rc_add_new(GtkMenuItem *item, gpointer data)
{
__view_process_selection(view_treeview, GDK_KEY_p);
}
static void __view_rc_add_other(GtkWidget *item, gpointer data)
{
GtkTreeView *treeview = gui_treeview();
GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
struct playlist *playlist = (struct playlist *)data;
struct view_add_data vad_data = {
.vad_type = PL_USER,
.vad_name = playlist->pl_name,
};
gtk_tree_selection_selected_foreach(selection,
__view_add_to_playlist,
&vad_data);
}
static gint __view_cmp_pl(gconstpointer a, gconstpointer b)
{
struct playlist *pl_a = (struct playlist *)a;
struct playlist *pl_b = (struct playlist *)b;
return g_utf8_collate(pl_a->pl_name, pl_b->pl_name);
}
static GtkWidget *__view_rc_build_submenu(void)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
GtkWidget *submenu, *item;
GList *iter, *list = NULL;
if (pl_user_db_get()->db_size == 0)
return NULL;
db_for_each(dbe, next, pl_user_db_get()) {
playlist = &USER_PLAYLIST(dbe)->pl_playlist;
list = g_list_insert_sorted(list, playlist, __view_cmp_pl);
}
submenu = gtk_menu_new();
iter = g_list_first(list);
while (iter) {
playlist = (struct playlist *)iter->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(__view_rc_add_other), playlist);
iter = g_list_next(iter);
}
return submenu;
}
bool __view_button_press(GtkTreeView *treeview, GdkEventButton *event,
gpointer data)
{
GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
GtkMenu *menu = GTK_MENU(gui_builder_widget("o_menu"));
GtkWidget *submenu = NULL;
GtkMenuItem *other;
GtkTreePath *path;
if (event->button != GDK_BUTTON_SECONDARY)
return false;
/* Select path if it isn't already selected */
if (gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
&path, NULL, NULL, NULL))
{
gtk_tree_selection_select_path(selection, path);
gtk_tree_path_free(path);
}
/* Set the "Other Playlists" submenu. */
other = GTK_MENU_ITEM(gui_builder_widget("o_add_to_other"));
submenu = __view_rc_build_submenu();
gtk_menu_item_set_submenu(other, submenu);
if (!submenu)
gtk_widget_hide(GTK_WIDGET(other));
else
gtk_widget_show_all(GTK_WIDGET(other));
gtk_menu_popup_at_pointer(menu, (GdkEvent *)event);
return true;
}
void gui_view_init()
{
GtkTreeViewColumn *col;
int i, pos;
view_treeview = gui_treeview();
for (i = 0; i < GUI_MODEL_N_COLUMNS; i++) {
col = gtk_tree_view_get_column(view_treeview, i);
pos = settings_get(QUEUE_SETTINGS[i]);
if (col && pos > 0)
gtk_tree_view_column_set_fixed_width(col, pos);
}
}
void gui_view_set_playlist(struct playlist *playlist)
{
gui_treeview_set_playlist(playlist);
}