/* * Copyright 2016 (c) Anna Schumaker. */ #include #include #include #include #include static gboolean __gui_model_iter_nth_child(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gint); static struct playlist *cur_playlist = NULL; static GObjectClass *parent_class = NULL; static GuiModel *gui_model = NULL; static GType gui_model_type = 0; static GType gui_model_columns[GUI_MODEL_N_COLUMNS] = { [GUI_MODEL_TRACK_NR] = G_TYPE_UINT, [GUI_MODEL_TITLE] = G_TYPE_STRING, [GUI_MODEL_LENGTH] = G_TYPE_STRING, [GUI_MODEL_ARTIST] = G_TYPE_STRING, [GUI_MODEL_ALBUM] = G_TYPE_STRING, [GUI_MODEL_YEAR] = G_TYPE_UINT, [GUI_MODEL_GENRE] = G_TYPE_STRING, [GUI_MODEL_COUNT] = G_TYPE_UINT, [GUI_MODEL_LAST_PLAY] = G_TYPE_STRING, [GUI_MODEL_FILE_PATH] = G_TYPE_STRING, [GUI_MODEL_FONT] = G_TYPE_STRING, }; static GtkTreeModelFlags __gui_model_get_flags(GtkTreeModel *model) { return GTK_TREE_MODEL_LIST_ONLY; } static gint __gui_model_get_n_columns(GtkTreeModel *model) { return GUI_MODEL_N_COLUMNS; } static GType __gui_model_get_column_type(GtkTreeModel *model, gint index) { g_return_val_if_fail(index >= 0, G_TYPE_INVALID); g_return_val_if_fail(index < GUI_MODEL_N_COLUMNS, G_TYPE_INVALID); return gui_model_columns[index]; } static gboolean __gui_model_get_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path) { gint *indices, depth; g_assert(path != NULL); indices = gtk_tree_path_get_indices_with_depth(path, &depth); g_assert(depth == 1); return __gui_model_iter_nth_child(model, iter, NULL, indices[0]); } static GtkTreePath *__gui_model_get_path(GtkTreeModel *model, GtkTreeIter *iter) { GtkTreePath *path; g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(iter->user_data2, FALSE); path = gtk_tree_path_new(); gtk_tree_path_append_index(path, GPOINTER_TO_UINT(iter->user_data)); return path; } static void __gui_model_get_value(GtkTreeModel *model, GtkTreeIter *iter, gint column, GValue *value) { struct track *track = iter->user_data2; gchar *str; g_return_if_fail(iter != NULL); g_return_if_fail(iter->user_data2 != NULL); g_return_if_fail(column < GUI_MODEL_N_COLUMNS); g_value_init(value, gui_model_columns[column]); switch (column) { case GUI_MODEL_TRACK_NR: g_value_set_uint(value, track->tr_track); break; case GUI_MODEL_TITLE: g_value_set_static_string(value, track->tr_title); break; case GUI_MODEL_LENGTH: g_value_take_string(value, string_sec2str(track->tr_length)); break; case GUI_MODEL_ARTIST: g_value_set_static_string(value, track->tr_album->al_artist->ar_name); break; case GUI_MODEL_ALBUM: g_value_set_static_string(value, track->tr_album->al_name); break; case GUI_MODEL_YEAR: g_value_set_uint(value, track->tr_album->al_year); break; case GUI_MODEL_GENRE: g_value_set_static_string(value, track->tr_album->al_genre->ge_name); break; case GUI_MODEL_COUNT: g_value_set_uint(value, track->tr_count); break; case GUI_MODEL_LAST_PLAY: g_value_take_string(value, track_last_play(track)); break; case GUI_MODEL_FILE_PATH: str = track_path(track); g_value_take_string(value, g_markup_escape_text(str, -1)); g_free(str); break; case GUI_MODEL_FONT: str = (track == audio_cur_track()) ? "bold" : ""; g_value_take_string(value, g_strdup(str)); break; } } static gboolean __gui_model_iter_next(GtkTreeModel *model, GtkTreeIter *iter) { unsigned int pos; g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(iter->user_data2, FALSE); pos = GPOINTER_TO_UINT(iter->user_data) + 1; return __gui_model_iter_nth_child(model, iter, NULL, pos); } static gboolean __gui_model_iter_children(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent) { return __gui_model_iter_nth_child(model, iter, parent, 0); } static gboolean __gui_model_iter_has_child(GtkTreeModel *model, GtkTreeIter *iter) { return FALSE; } static gint __gui_model_iter_n_children(GtkTreeModel *model, GtkTreeIter *iter) { if (iter != NULL || !cur_playlist) return 0; return queue_size(&cur_playlist->pl_queue); } static gboolean __gui_model_iter_nth_child(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { struct queue *queue = &cur_playlist->pl_queue; if (parent || !cur_playlist || n >= queue_size(queue)) return FALSE; iter->stamp = gui_model->gm_stamp; iter->user_data = GUINT_TO_POINTER(n); iter->user_data2 = queue_at(queue, n); return TRUE; } static gboolean __gui_model_iter_parent(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *child) { return FALSE; } static void __gui_model_init(GuiModel *model) { model->gm_stamp = g_random_int(); } static void __gui_model_finalize(GObject *object) { parent_class->finalize(object); } static void __gui_model_class_init(GuiModelClass *class) { GObjectClass *object_class = (GObjectClass *)class; object_class->finalize = __gui_model_finalize; parent_class = g_type_class_peek_parent(class); } static void __gui_tree_model_init(GtkTreeModelIface *iface) { iface->get_flags = __gui_model_get_flags; iface->get_n_columns = __gui_model_get_n_columns; iface->get_column_type = __gui_model_get_column_type; iface->get_iter = __gui_model_get_iter; iface->get_path = __gui_model_get_path; iface->get_value = __gui_model_get_value; iface->iter_next = __gui_model_iter_next; iface->iter_children = __gui_model_iter_children; iface->iter_has_child = __gui_model_iter_has_child; iface->iter_n_children = __gui_model_iter_n_children; iface->iter_nth_child = __gui_model_iter_nth_child; iface->iter_parent = __gui_model_iter_parent; } static const GTypeInfo gui_model_type_info = { .class_size = sizeof(GuiModelClass), .base_init = NULL, .base_finalize = NULL, .class_init = (GClassInitFunc)__gui_model_class_init, .class_finalize = NULL, .class_data = NULL, .instance_size = sizeof(GuiModel), .n_preallocs = 0, .instance_init = (GInstanceInitFunc)__gui_model_init, }; static const GInterfaceInfo gui_tree_model = { .interface_init = (GInterfaceInitFunc)__gui_tree_model_init, .interface_finalize = NULL, .interface_data = NULL, }; void gui_model_init(void) { gui_model_type = g_type_register_static(G_TYPE_OBJECT, "GuiModel", &gui_model_type_info, (GTypeFlags)0); g_type_add_interface_static(gui_model_type, GTK_TYPE_TREE_MODEL, &gui_tree_model); gui_model = g_object_new(gui_model_type, NULL); g_assert(gui_model != NULL); } void gui_model_deinit(void) { g_object_unref(gui_model); gui_model_type = 0; gui_model = NULL; cur_playlist = NULL; } static void __gui_model_set_runtime(void) { gchar *len = NULL; if (cur_playlist) len = string_sec2str_long(cur_playlist->pl_queue.q_length); gtk_label_set_text(gui_model_runtime(), len); g_free(len); } GuiModel *gui_model_get(void) { return gui_model; } GType gui_model_get_type() { return gui_model_type; } void gui_model_add(struct playlist *playlist, unsigned int row) { GtkTreePath *path; GtkTreeIter iter; if (cur_playlist != playlist) return; path = gtk_tree_path_new_from_indices(row, -1); __gui_model_get_iter(GTK_TREE_MODEL(gui_model), &iter, path); gtk_tree_model_row_inserted(GTK_TREE_MODEL(gui_model), path, &iter); __gui_model_set_runtime(); gtk_tree_path_free(path); } void gui_model_remove(struct playlist *playlist, unsigned int row) { GtkTreePath *path; if (cur_playlist != playlist) return; path = gtk_tree_path_new_from_indices(row, -1); gtk_tree_model_row_deleted(GTK_TREE_MODEL(gui_model), path); __gui_model_set_runtime(); gtk_tree_path_free(path); } void gui_model_clear(struct playlist *playlist, unsigned int n) { GtkTreePath *path; unsigned int i; if (!gui_model || cur_playlist != playlist) return; path = gtk_tree_path_new_from_indices(n - 1, -1); for (i = 0; i < n; i++) { gtk_tree_model_row_deleted(GTK_TREE_MODEL(gui_model), path); gtk_tree_path_prev(path); } __gui_model_set_runtime(); gtk_tree_path_free(path); } void gui_model_update(struct playlist *playlist, unsigned int row) { GtkTreePath *path; GtkTreeIter iter; if (cur_playlist != playlist) return; path = gtk_tree_path_new_from_indices(row, -1); __gui_model_get_iter(GTK_TREE_MODEL(gui_model), &iter, path); gtk_tree_model_row_changed(GTK_TREE_MODEL(gui_model), path, &iter); __gui_model_set_runtime(); gtk_tree_path_free(path); } void gui_model_set_playlist(struct playlist *playlist) { if (cur_playlist) gui_model_clear(cur_playlist, queue_size(&cur_playlist->pl_queue)); cur_playlist = playlist; __gui_model_set_runtime(); if (playlist && queue_size(&playlist->pl_queue) > 0) gui_model_add(playlist, 0); } struct playlist *gui_model_get_playlist(void) { return cur_playlist; } struct track * gui_model_path_get_track(GtkTreePath *path) { GtkTreeIter iter; __gui_model_get_iter(GTK_TREE_MODEL(gui_model), &iter, path); return gui_model_iter_get_track(&iter); }