2015-12-29 09:11:51 -05:00
|
|
|
/*
|
|
|
|
* Copyright 2015 (c) Anna Schumaker.
|
|
|
|
*/
|
2016-03-29 08:39:00 -04:00
|
|
|
#include <core/settings.h>
|
2016-08-25 10:34:00 -04:00
|
|
|
#include <core/string.h>
|
2016-08-26 10:00:26 -04:00
|
|
|
#include <gui/model.h>
|
2015-12-29 09:11:51 -05:00
|
|
|
#include <gui/sidebar.h>
|
2016-08-26 09:25:17 -04:00
|
|
|
#include <gui/treeview.h>
|
2015-12-29 09:11:51 -05:00
|
|
|
|
2016-08-25 10:58:24 -04:00
|
|
|
enum sidebar_columns {
|
|
|
|
SB_IMAGE,
|
|
|
|
SB_NAME,
|
|
|
|
SB_TYPE,
|
|
|
|
};
|
|
|
|
|
2015-12-29 09:11:51 -05:00
|
|
|
const gchar *SIDEBAR_SETTING = "gui.sidebar.pos";
|
2016-01-07 09:37:00 -05:00
|
|
|
|
2016-08-25 10:05:27 -04:00
|
|
|
static gchar *__gui_sidebar_size_str(struct playlist *playlist)
|
|
|
|
{
|
|
|
|
const gchar *fmt = "%s\n%d track%s";
|
|
|
|
unsigned int size;
|
|
|
|
|
|
|
|
if (!playlist)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
size = playlist_size(playlist->pl_type, playlist->pl_name);
|
|
|
|
if (playlist_cur() == playlist)
|
|
|
|
fmt = "<b>%s\n%d track%s</b>";
|
|
|
|
return g_markup_printf_escaped(fmt, playlist->pl_name, size,
|
|
|
|
(size != 1) ? "s" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __gui_sidebar_set(GtkTreeIter *iter, const gchar *name,
|
|
|
|
const gchar *image, enum playlist_type_t type)
|
|
|
|
{
|
|
|
|
gtk_tree_store_set(gui_sidebar_store(), iter, SB_NAME, name,
|
|
|
|
SB_IMAGE, image,
|
|
|
|
SB_TYPE, type, -1);
|
|
|
|
}
|
|
|
|
|
2016-08-25 11:41:40 -04:00
|
|
|
static void __gui_sidebar_set_playlist(GtkTreeIter *iter,
|
|
|
|
struct playlist *playlist,
|
|
|
|
const gchar *image)
|
|
|
|
{
|
|
|
|
gchar *text = __gui_sidebar_size_str(playlist);
|
|
|
|
__gui_sidebar_set(iter, text, image, playlist->pl_type);
|
|
|
|
g_free(text);
|
|
|
|
}
|
|
|
|
|
2016-08-25 09:30:46 -04:00
|
|
|
static void __gui_sidebar_add_header(GtkTreeIter *iter, const gchar *name,
|
|
|
|
const gchar *image)
|
|
|
|
{
|
|
|
|
gchar *formatted = g_strdup_printf("<big>%s</big>", name);
|
|
|
|
|
2016-08-25 10:05:27 -04:00
|
|
|
gtk_tree_store_insert(gui_sidebar_store(), iter, NULL, -1);
|
|
|
|
__gui_sidebar_set(iter, NULL, NULL, PL_MAX_TYPE);
|
|
|
|
gtk_tree_store_insert(gui_sidebar_store(), iter, NULL, -1);
|
|
|
|
__gui_sidebar_set(iter, formatted, image, PL_MAX_TYPE);
|
2016-08-25 09:30:46 -04:00
|
|
|
|
|
|
|
g_free(formatted);
|
|
|
|
}
|
|
|
|
|
2016-08-25 14:40:45 -04:00
|
|
|
static int __gui_sidebar_compare(GtkTreeIter *iter, const gchar *name,
|
|
|
|
enum playlist_type_t type)
|
|
|
|
{
|
|
|
|
gchar *cur;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (gui_sidebar_iter_type(iter) != type)
|
|
|
|
return gui_sidebar_iter_type(iter) - type;
|
|
|
|
|
|
|
|
cur = gui_sidebar_iter_name(iter);
|
|
|
|
ret = g_utf8_collate(cur, name);
|
|
|
|
g_free(cur);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2016-01-07 09:37:00 -05:00
|
|
|
|
2016-08-26 09:25:17 -04:00
|
|
|
static inline void __gui_sidebar_filter_iter_convert(GtkTreeIter *iter,
|
|
|
|
GtkTreeIter *child)
|
|
|
|
{
|
|
|
|
gtk_tree_model_filter_convert_iter_to_child_iter(gui_sidebar_filter(),
|
|
|
|
child, iter);
|
|
|
|
}
|
|
|
|
|
2016-08-25 15:36:17 -04:00
|
|
|
static gboolean __gui_sidebar_visible_func(GtkTreeModel *model,
|
|
|
|
GtkTreeIter *iter,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
enum playlist_type_t type = gui_sidebar_iter_type(iter);
|
|
|
|
gboolean ret = TRUE;
|
|
|
|
gchar *name;
|
|
|
|
|
|
|
|
if (type == PL_SYSTEM || type == PL_ARTIST) {
|
|
|
|
name = gui_sidebar_iter_name(iter);
|
|
|
|
if (name) {
|
|
|
|
ret = playlist_size(type, name) > 0;
|
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-26 09:25:17 -04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean __gui_sidebar_can_select(GtkTreeSelection *selection,
|
|
|
|
GtkTreeModel *model, GtkTreePath *path,
|
|
|
|
gboolean selected, gpointer data)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter, child;
|
|
|
|
|
|
|
|
gtk_tree_model_get_iter(model, &iter, path);
|
|
|
|
__gui_sidebar_filter_iter_convert(&iter, &child);
|
|
|
|
return gui_sidebar_iter_type(&child) != PL_MAX_TYPE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __gui_sidebar_selection_changed(GtkTreeSelection *selection, gpointer data)
|
|
|
|
{
|
|
|
|
GtkTreeModel *model = GTK_TREE_MODEL(gui_sidebar_filter());
|
2016-08-26 10:00:26 -04:00
|
|
|
bool active = false, sensitive = false;
|
2016-08-26 09:25:17 -04:00
|
|
|
struct playlist *playlist = NULL;
|
|
|
|
enum playlist_type_t type;
|
|
|
|
GtkTreeIter iter, child;
|
|
|
|
gchar *name;
|
|
|
|
|
|
|
|
if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
|
|
|
|
__gui_sidebar_filter_iter_convert(&iter, &child);
|
|
|
|
|
|
|
|
name = gui_sidebar_iter_name(&child);
|
|
|
|
type = gui_sidebar_iter_type(&child);
|
2016-08-26 10:00:26 -04:00
|
|
|
|
|
|
|
playlist = playlist_get(type, name);
|
|
|
|
active = playlist_get_random(type, name);
|
|
|
|
sensitive = (type != PL_SYSTEM) ||
|
|
|
|
!string_match(name, "History");
|
|
|
|
|
2016-08-26 09:25:17 -04:00
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
|
2016-08-26 10:00:26 -04:00
|
|
|
gtk_toggle_button_set_active(gui_random_button(), active);
|
|
|
|
gtk_widget_set_sensitive(GTK_WIDGET(gui_random_button()), sensitive);
|
2016-08-26 09:25:17 -04:00
|
|
|
gui_treeview_set_playlist(playlist);
|
2016-08-25 15:36:17 -04:00
|
|
|
}
|
|
|
|
|
2016-08-30 10:11:51 -04:00
|
|
|
bool __gui_sidebar_keypress(GtkTreeView *treeview, GdkEventKey *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
|
|
|
|
struct playlist *playlist = gui_model_get_playlist();
|
|
|
|
GtkTreeModel *model = GTK_TREE_MODEL(gui_sidebar_filter());
|
|
|
|
GtkTreeIter iter, child;
|
|
|
|
|
|
|
|
if (!playlist || event->keyval != GDK_KEY_Delete)
|
|
|
|
return false;
|
|
|
|
if (!gtk_tree_selection_get_selected(selection, &model, &iter))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
__gui_sidebar_filter_iter_convert(&iter, &child);
|
|
|
|
if (playlist_delete(playlist->pl_type, playlist->pl_name))
|
|
|
|
gtk_tree_store_remove(gui_sidebar_store(), &child);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-21 13:34:05 -04:00
|
|
|
void __gui_sidebar_resized(GtkPaned *pane, GParamSpec *pspec, gpointer data)
|
2015-12-29 09:11:51 -05:00
|
|
|
{
|
2016-03-29 08:39:00 -04:00
|
|
|
settings_set(SIDEBAR_SETTING, gtk_paned_get_position(pane));
|
2015-12-29 09:11:51 -05:00
|
|
|
}
|
|
|
|
|
2016-08-26 10:00:26 -04:00
|
|
|
void __gui_sidebar_random_toggled(GtkToggleButton *button, gpointer data)
|
|
|
|
{
|
|
|
|
struct playlist *playlist = gui_model_get_playlist();
|
|
|
|
bool active = gtk_toggle_button_get_active(button);
|
|
|
|
|
|
|
|
if (playlist) {
|
|
|
|
playlist_set_random(playlist->pl_type,
|
|
|
|
playlist->pl_name, active);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-29 09:11:51 -05:00
|
|
|
void gui_sidebar_init()
|
|
|
|
{
|
2016-08-25 09:30:46 -04:00
|
|
|
int pos = settings_get(SIDEBAR_SETTING);
|
2016-08-26 09:25:17 -04:00
|
|
|
GtkTreeSelection *selection;
|
2016-08-25 09:30:46 -04:00
|
|
|
GtkTreeIter iter;
|
|
|
|
|
2016-08-25 15:36:17 -04:00
|
|
|
if (!gui_sidebar_iter_first(&iter)) {
|
|
|
|
__gui_sidebar_add_header(&iter, "Playlists", "emblem-documents");
|
|
|
|
__gui_sidebar_add_header(&iter, "Dynamic", "emblem-generic");
|
|
|
|
__gui_sidebar_add_header(&iter, "Library", "emblem-system");
|
|
|
|
|
2016-08-26 09:25:17 -04:00
|
|
|
selection = gtk_tree_view_get_selection(gui_sidebar_treeview());
|
|
|
|
gtk_tree_selection_set_select_function(selection,
|
|
|
|
__gui_sidebar_can_select,
|
|
|
|
NULL, NULL);
|
2016-08-25 15:36:17 -04:00
|
|
|
gtk_tree_model_filter_set_visible_func(gui_sidebar_filter(),
|
|
|
|
__gui_sidebar_visible_func,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
2016-08-25 09:30:46 -04:00
|
|
|
|
2015-12-29 09:11:51 -05:00
|
|
|
if (pos > 0)
|
2016-08-21 13:34:05 -04:00
|
|
|
gtk_paned_set_position(gui_sidebar(), pos);
|
2015-12-29 09:11:51 -05:00
|
|
|
}
|
2016-08-25 10:58:24 -04:00
|
|
|
|
|
|
|
gboolean gui_sidebar_iter_first(GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
return gtk_tree_model_get_iter_first(gui_sidebar_model(), iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean gui_sidebar_iter_next(GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
return gtk_tree_model_iter_next(gui_sidebar_model(), iter);
|
|
|
|
}
|
|
|
|
|
2016-08-25 11:41:40 -04:00
|
|
|
gboolean gui_sidebar_iter_down(GtkTreeIter *iter, GtkTreeIter *child)
|
|
|
|
{
|
|
|
|
return gtk_tree_model_iter_children(gui_sidebar_model(), child, iter);
|
|
|
|
}
|
|
|
|
|
2016-08-25 10:58:24 -04:00
|
|
|
gchar *gui_sidebar_iter_name(GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
gchar *text = NULL, *parsed = NULL, *name, **split;
|
|
|
|
|
|
|
|
gtk_tree_model_get(gui_sidebar_model(), iter, SB_NAME, &text, -1);
|
|
|
|
if (!text)
|
|
|
|
return g_strdup("");
|
|
|
|
|
|
|
|
pango_parse_markup(text, -1, 0, NULL, &parsed, NULL, NULL);
|
|
|
|
if (!parsed)
|
|
|
|
return g_strdup("");
|
|
|
|
|
|
|
|
split = g_strsplit(parsed, "\n", 2);
|
|
|
|
name = g_strdup(split[0]);
|
|
|
|
|
|
|
|
g_strfreev(split);
|
|
|
|
g_free(parsed);
|
|
|
|
g_free(text);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum playlist_type_t gui_sidebar_iter_type(GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
enum playlist_type_t type;
|
|
|
|
gtk_tree_model_get(gui_sidebar_model(), iter, SB_TYPE, &type, -1);
|
|
|
|
return type;
|
|
|
|
}
|
2016-08-25 10:05:27 -04:00
|
|
|
|
|
|
|
void gui_sidebar_iter_add(GtkTreeIter *iter, struct playlist *playlist,
|
|
|
|
const gchar *image)
|
|
|
|
{
|
|
|
|
GtkTreeIter new;
|
|
|
|
gtk_tree_store_insert_before(gui_sidebar_store(), &new, NULL, iter);
|
2016-08-25 11:41:40 -04:00
|
|
|
__gui_sidebar_set_playlist(&new, playlist, image);
|
|
|
|
}
|
|
|
|
|
2016-08-25 14:40:45 -04:00
|
|
|
void gui_sidebar_iter_sort_child(GtkTreeIter *iter, struct playlist *playlist,
|
|
|
|
const gchar *image)
|
|
|
|
{
|
|
|
|
GtkTreeIter child, new;
|
|
|
|
|
|
|
|
if (!gui_sidebar_iter_down(iter, &child))
|
|
|
|
goto out_append;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (__gui_sidebar_compare(&child, playlist->pl_name,
|
|
|
|
playlist->pl_type) >= 0) {
|
|
|
|
gtk_tree_store_insert_before(gui_sidebar_store(),
|
|
|
|
&new, iter, &child);
|
|
|
|
__gui_sidebar_set_playlist(&new, playlist, image);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (gui_sidebar_iter_next(&child));
|
|
|
|
|
|
|
|
out_append:
|
|
|
|
gui_sidebar_iter_append_child(iter, playlist, image);
|
|
|
|
}
|
|
|
|
|
2016-08-25 11:41:40 -04:00
|
|
|
void gui_sidebar_iter_append_child(GtkTreeIter *iter, struct playlist *playlist,
|
|
|
|
const gchar *image)
|
|
|
|
{
|
|
|
|
GtkTreeIter new;
|
|
|
|
gtk_tree_store_insert_before(gui_sidebar_store(), &new, iter, NULL);
|
|
|
|
__gui_sidebar_set_playlist(&new, playlist, image);
|
2016-08-25 10:05:27 -04:00
|
|
|
}
|
2016-08-25 10:34:00 -04:00
|
|
|
|
2016-08-30 14:13:02 -04:00
|
|
|
void gui_sidebar_iter_update(GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
enum playlist_type_t type = gui_sidebar_iter_type(iter);
|
|
|
|
gchar *name, *text;
|
|
|
|
|
|
|
|
if (type >= PL_MAX_TYPE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
name = gui_sidebar_iter_name(iter);
|
|
|
|
text = __gui_sidebar_size_str(playlist_get(type, name));
|
|
|
|
gtk_tree_store_set(gui_sidebar_store(), iter, SB_NAME, text, -1);
|
|
|
|
|
|
|
|
g_free(name);
|
|
|
|
g_free(text);
|
|
|
|
}
|
|
|
|
|
2016-08-31 16:55:19 -04:00
|
|
|
void gui_sidebar_filter_path_select(GtkTreePath *path)
|
|
|
|
{
|
|
|
|
GtkTreeModel *model = GTK_TREE_MODEL(gui_sidebar_filter());
|
|
|
|
enum playlist_type_t type;
|
|
|
|
GtkTreeIter iter, child;
|
|
|
|
gchar *name;
|
|
|
|
|
|
|
|
gtk_tree_model_get_iter(model, &iter, path);
|
|
|
|
__gui_sidebar_filter_iter_convert(&iter, &child);
|
|
|
|
|
|
|
|
type = gui_sidebar_iter_type(&child);
|
|
|
|
if (type >= PL_MAX_TYPE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
name = gui_sidebar_iter_name(&child);
|
|
|
|
if (playlist_select(type, name))
|
|
|
|
gui_sidebar_iter_update(&child);
|
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
|
2016-08-25 10:34:00 -04:00
|
|
|
gboolean gui_sidebar_iter_find(GtkTreeIter *iter, const gchar *name,
|
|
|
|
enum playlist_type_t type)
|
|
|
|
{
|
|
|
|
do {
|
2016-08-25 14:40:45 -04:00
|
|
|
if (__gui_sidebar_compare(iter, name, type) == 0)
|
2016-08-25 10:34:00 -04:00
|
|
|
return TRUE;
|
|
|
|
} while (gui_sidebar_iter_next(iter));
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|