/* * Copyright 2016 (c) Anna Schumaker. */ #include #include #include #include #include #include #include #include #include #include #include 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); }