/* * Copyright 2016 (c) Anna Schumaker. */ #include #include #include #include static const GTypeInfo queue_type_info; static const GInterfaceInfo queue_tree_model; static GObjectClass *parent_class = NULL; static gchar *font_current = "bold"; static gchar *font_regular = ""; static GType queue_columns[Q_MODEL_N_COLUMNS] = { [Q_MODEL_TRACK_NR] = G_TYPE_UINT, [Q_MODEL_TITLE] = G_TYPE_STRING, [Q_MODEL_LENGTH] = G_TYPE_STRING, [Q_MODEL_ARTIST] = G_TYPE_STRING, [Q_MODEL_ALBUM] = G_TYPE_STRING, [Q_MODEL_YEAR] = G_TYPE_UINT, [Q_MODEL_GENRE] = G_TYPE_STRING, [Q_MODEL_COUNT] = G_TYPE_UINT, [Q_MODEL_LAST_PLAY] = G_TYPE_STRING, [Q_MODEL_FILE_PATH] = G_TYPE_STRING, [Q_MODEL_FONT] = G_TYPE_STRING, }; static gboolean __queue_model_iter_nth(GuiQueueModel *model, GtkTreeIter *iter, gint n) { if (n >= queue_size(model->gqm_queue)) return FALSE; queue_iter_set(model->gqm_queue, &model->gqm_iter, n); iter->stamp = model->gqm_stamp; iter->user_data = &model->gqm_iter; iter->user_data2 = queue_iter_val(&model->gqm_iter); return TRUE; } static GtkTreeModelFlags _queue_model_get_flags(GtkTreeModel *model) { return GTK_TREE_MODEL_LIST_ONLY; } static gint _queue_model_get_n_columns(GtkTreeModel *model) { return Q_MODEL_N_COLUMNS; } static GType _queue_model_get_column_type(GtkTreeModel *model, gint index) { g_return_val_if_fail(index >= 0 && index < Q_MODEL_N_COLUMNS, G_TYPE_INVALID); return queue_columns[index]; } static gboolean _queue_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 __queue_model_iter_nth(GUI_QUEUE_MODEL(model), iter, indices[0]); } static GtkTreePath *_queue_model_get_path(GtkTreeModel *model, GtkTreeIter *iter) { struct queue_iter *q_it; GtkTreePath *path; g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(iter->user_data, FALSE); g_return_val_if_fail(iter->user_data2, FALSE); q_it = iter->user_data; path = gtk_tree_path_new(); gtk_tree_path_append_index(path, q_it->it_pos); return path; } static void _queue_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 < Q_MODEL_N_COLUMNS); g_value_init(value, queue_columns[column]); switch (column) { case Q_MODEL_TRACK_NR: g_value_set_uint(value, track->tr_track); break; case Q_MODEL_TITLE: g_value_set_static_string(value, track->tr_title); break; case Q_MODEL_LENGTH: g_value_take_string(value, string_sec2str(track->tr_length)); break; case Q_MODEL_ARTIST: g_value_set_static_string(value, track->tr_artist->ar_name); break; case Q_MODEL_ALBUM: g_value_set_static_string(value, track->tr_album->al_name); break; case Q_MODEL_YEAR: g_value_set_uint(value, track->tr_album->al_year); break; case Q_MODEL_GENRE: g_value_set_static_string(value, track->tr_genre->ge_name); break; case Q_MODEL_COUNT: g_value_set_uint(value, track->tr_count); break; case Q_MODEL_LAST_PLAY: g_value_take_string(value, track_last_play(track)); break; case Q_MODEL_FILE_PATH: str = track_path(track); g_value_take_string(value, g_markup_escape_text(str, -1)); g_free(str); break; case Q_MODEL_FONT: str = (track == audio_cur_track()) ? font_current : font_regular; g_value_set_static_string(value, str); break; } } static gboolean _queue_model_iter_next(GtkTreeModel *model, GtkTreeIter *iter) { GuiQueueModel *gqm = GUI_QUEUE_MODEL(model); g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(iter->user_data, FALSE); g_return_val_if_fail(iter->user_data2, FALSE); queue_iter_next(&gqm->gqm_iter); if (gqm->gqm_iter.it_iter == NULL) return FALSE; iter->stamp = gqm->gqm_stamp; iter->user_data = &gqm->gqm_iter; iter->user_data2 = queue_iter_val(&gqm->gqm_iter); return TRUE; } static gboolean _queue_model_iter_children(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent) { if (parent) return FALSE; return __queue_model_iter_nth(GUI_QUEUE_MODEL(model), iter, 0); } static gboolean _queue_model_iter_has_child(GtkTreeModel *model, GtkTreeIter *iter) { return FALSE; } static gint _queue_model_iter_n_children(GtkTreeModel *model, GtkTreeIter *iter) { if (iter != NULL) return 0; return queue_size(GUI_QUEUE_MODEL(model)->gqm_queue); } static gboolean _queue_model_iter_nth_child(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { if (parent) return FALSE; return __queue_model_iter_nth(GUI_QUEUE_MODEL(model), iter, n); } static gboolean _queue_model_iter_parent(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *child) { return FALSE; } static void _queue_model_init(GuiQueueModel *model) { model->gqm_stamp = g_random_int(); } static void _queue_model_finalize(GObject *object) { parent_class->finalize(object); } static void _queue_model_class_init(GuiQueueModelClass *class) { GObjectClass *object_class; parent_class = g_type_class_peek_parent(class); object_class = (GObjectClass *)class; object_class->finalize = _queue_model_finalize; } static void _queue_tree_model_init(GtkTreeModelIface *iface) { iface->get_flags = _queue_model_get_flags; iface->get_n_columns = _queue_model_get_n_columns; iface->get_column_type = _queue_model_get_column_type; iface->get_iter = _queue_model_get_iter; iface->get_path = _queue_model_get_path; iface->get_value = _queue_model_get_value; iface->iter_next = _queue_model_iter_next; iface->iter_children = _queue_model_iter_children; iface->iter_has_child = _queue_model_iter_has_child; iface->iter_n_children = _queue_model_iter_n_children; iface->iter_nth_child = _queue_model_iter_nth_child; iface->iter_parent = _queue_model_iter_parent; } GuiQueueModel *gui_queue_model_new(struct queue *queue) { GuiQueueModel *model = g_object_new(GUI_QUEUE_MODEL_TYPE, NULL); g_assert(model != NULL); model->gqm_queue = queue; return model; } GType gui_queue_model_get_type() { static GType queue_type = 0; if (queue_type == 0) { queue_type = g_type_register_static(G_TYPE_OBJECT, "GuiQueueModel", &queue_type_info, (GTypeFlags)0); g_type_add_interface_static(queue_type, GTK_TYPE_TREE_MODEL, &queue_tree_model); } return queue_type; } void gui_queue_model_add(GuiQueueModel *model, unsigned int row) { GtkTreePath *path = gtk_tree_path_new_from_indices(row, -1); GtkTreeIter iter; _queue_model_get_iter(GTK_TREE_MODEL(model), &iter, path); gtk_tree_model_row_inserted(GTK_TREE_MODEL(model), path, &iter); gtk_tree_path_free(path); } void gui_queue_model_remove(GuiQueueModel *model, unsigned int row) { GtkTreePath *path = gtk_tree_path_new_from_indices(row, -1); gtk_tree_model_row_deleted(GTK_TREE_MODEL(model), path); gtk_tree_path_free(path); } void gui_queue_model_clear(GuiQueueModel *model, unsigned int n) { unsigned int i; for (i = 1; i <= n; i++) gui_queue_model_remove(model, n - i); } void gui_queue_model_update(GuiQueueModel *model, unsigned int row) { GtkTreePath *path = gtk_tree_path_new_from_indices(row, -1); GtkTreeIter iter; _queue_model_get_iter(GTK_TREE_MODEL(model), &iter, path); gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter); gtk_tree_path_free(path); } struct track * gui_queue_model_path_get_track(GuiQueueModel *model, GtkTreePath *path) { GtkTreeIter iter; _queue_model_get_iter(GTK_TREE_MODEL(model), &iter, path); return gui_queue_model_iter_get_track(model, &iter); } static const GTypeInfo queue_type_info = { .class_size = sizeof(GuiQueueModelClass), .base_init = NULL, .base_finalize = NULL, .class_init = (GClassInitFunc)_queue_model_class_init, .class_finalize = NULL, .class_data = NULL, .instance_size = sizeof(GuiQueueModel), .n_preallocs = 0, .instance_init = (GInstanceInitFunc)_queue_model_init, }; static const GInterfaceInfo queue_tree_model = { .interface_init = (GInterfaceInitFunc)_queue_tree_model_init, .interface_finalize = NULL, .interface_data = NULL, };