/* * Copyright 2016 (c) Anna Schumaker. */ #include #include #include #include #include struct col_map_entry { enum compare_t compare; const gchar *setting; }; static const struct col_map_entry GUI_COL_MAP[GUI_MODEL_N_COLUMNS] = { [GUI_MODEL_TRACK_NR] = { COMPARE_TRACK, "gui.queue.track" }, [GUI_MODEL_TITLE] = { COMPARE_TITLE, "gui.queue.title" }, [GUI_MODEL_LENGTH] = { COMPARE_LENGTH, "gui.queue.length" }, [GUI_MODEL_ARTIST] = { COMPARE_ARTIST, "gui.queue.artist" }, [GUI_MODEL_ALBUM] = { COMPARE_ALBUM, "gui.queue.album" }, [GUI_MODEL_YEAR] = { COMPARE_YEAR, "gui.queue.year" }, [GUI_MODEL_GENRE] = { COMPARE_GENRE, "gui.queue.genre" }, [GUI_MODEL_COUNT] = { COMPARE_COUNT, "gui.queue.count" }, [GUI_MODEL_LAST_PLAY] = { COMPARE_PLAYED, NULL }, }; static unsigned int sort_count = 0; static gchar *sort_text = NULL; static bool can_scroll = true; static int __gui_treeview_colum_match_sort(enum compare_t compare) { struct playlist *playlist = gui_model_get_playlist(); GSList *cur = playlist ? playlist->pl_sort : NULL; while (cur) { int field = GPOINTER_TO_INT(cur->data); if (abs(field) == compare) return field; cur = g_slist_next(cur); } return 0; } static void __gui_treeview_set_sort_indicators() { GtkTreeViewColumn *col; unsigned int i, order; int field; for (i = 0; i < GUI_MODEL_N_COLUMNS; i++) { col = gtk_tree_view_get_column(gui_treeview(), i); if (!col) continue; field = __gui_treeview_colum_match_sort(GUI_COL_MAP[i].compare); order = (field > 0) ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING; gtk_tree_view_column_set_sort_indicator(col, field != 0); gtk_tree_view_column_set_sort_order(col, order); } } static void __gui_treeview_clear_sorting() { sort_count = 0; if (sort_text) { g_free(sort_text); sort_text = NULL; gtk_label_set_text(gui_sorting(), ""); } } static void __gui_treeview_set_sorting(gchar *text) { gchar *formatted; __gui_treeview_clear_sorting(); if (!text) return; sort_text = g_strdup(text); formatted = g_strdup_printf("Sorting: {%s}", text); gtk_label_set_text(gui_sorting(), formatted); g_free(formatted); } static int __gui_treeview_dec_sort(gpointer data) { if (sort_count > 0) sort_count--; if (sort_count == 0) __gui_treeview_clear_sorting(); return FALSE; } static gchar *__gui_treeview_sort_text_append(GtkTreeViewColumn *col) { const gchar *title = gtk_tree_view_column_get_title(col); gchar *text, **split; unsigned int i; if (!sort_text) return g_strdup(title); if (gtk_tree_view_column_get_sort_order(col) == GTK_SORT_ASCENDING) return g_strdup_printf("%s, %s", sort_text, title); /* Find the column and prefix it with a minus sign */ split = g_strsplit(sort_text, ", ", 0); for (i = 0; split[i] != NULL; i++) { if (g_strcmp0(split[i], title) == 0) break; } g_free(split[i]); split[i] = g_strdup_printf("-%s", title); text = g_strjoinv(", ", split); g_strfreev(split); return text; } static void __gui_treeview_column_clicked(GtkTreeViewColumn *col, gpointer data) { struct playlist *playlist = gui_model_get_playlist(); enum compare_t compare = GPOINTER_TO_UINT(data); gchar *text; if (!playlist) return; if (sort_count == 0) playlist_clear_sort(playlist); if (!playlist_sort(playlist, compare)) return; __gui_treeview_set_sort_indicators(); text = __gui_treeview_sort_text_append(col); __gui_treeview_set_sorting(text); g_free(text); sort_count++; g_timeout_add_seconds(3, __gui_treeview_dec_sort, NULL); } void __gui_treeview_column_resized(GtkTreeViewColumn *col, GParamSpec *pspec, gpointer data) { settings_set(GUI_COL_MAP[GPOINTER_TO_UINT(data)].setting, gtk_tree_view_column_get_width(col)); } void __gui_treeview_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { can_scroll = false; gui_filter_path_load_track(path); can_scroll = true; } void gui_treeview_init() { GtkTreeViewColumn *col; int i, pos; gtk_tree_view_set_model(gui_treeview(), GTK_TREE_MODEL(gui_filter_get())); for (i = 0; i < GUI_MODEL_N_COLUMNS; i++) { col = gtk_tree_view_get_column(gui_treeview(), i); if (col) { g_signal_connect(col, "clicked", G_CALLBACK(__gui_treeview_column_clicked), GUINT_TO_POINTER(GUI_COL_MAP[i].compare)); g_signal_connect(col, "notify::width", G_CALLBACK(__gui_treeview_column_resized), GUINT_TO_POINTER(i)); pos = settings_get(GUI_COL_MAP[i].setting); if (pos > 0) gtk_tree_view_column_set_fixed_width(col, pos); } } } void gui_treeview_deinit() { __gui_treeview_clear_sorting(); } void gui_treeview_set_playlist(struct playlist *playlist) { gui_filter_set_playlist(playlist); __gui_treeview_clear_sorting(); __gui_treeview_set_sort_indicators(); gui_treeview_scroll(); } void gui_treeview_scroll() { int pos = playlist_current_index(gui_model_get_playlist()); GtkTreePath *path; if (!can_scroll || pos < 0) return; path = gui_filter_path_from_index(pos); if (!path) return; gtk_tree_view_set_cursor(gui_treeview(), path, NULL, false); gtk_tree_view_scroll_to_cell(gui_treeview(), path, NULL, true, 0.5, 0.5); gtk_tree_path_free(path); } void gui_treeview_select_path_at_pos(unsigned int x, unsigned int y) { GtkTreePath *path; if (gtk_tree_view_get_path_at_pos(gui_treeview(), x, y, &path, NULL, NULL, NULL)) { gtk_tree_selection_select_path(gui_treeview_selection(), path); gtk_tree_path_free(path); } } GList *gui_treeview_list_selected_tracks(void) { GtkTreeSelection *selection = gui_treeview_selection(); GList *rows = gtk_tree_selection_get_selected_rows(selection, NULL); GList *cur = g_list_first(rows); GList *list = NULL; while (cur) { list = g_list_append(list, gui_filter_path_get_track(cur->data)); cur = g_list_next(cur); } g_list_free_full(rows, (GDestroyNotify) gtk_tree_path_free); gtk_tree_selection_unselect_all(selection); return list; }