--- a/ui/gtk/model.c Fri Feb 16 19:37:51 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,549 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "model.h" -#include "image.h" -#include "toolkit.h" - -#define IS_UI_LIST_MODEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), list_model_type)) -#define UI_LIST_MODEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), list_model_type, UiListModel)) - -static void list_model_class_init(GObjectClass *cl, gpointer data); -static void list_model_interface_init(GtkTreeModelIface *i, gpointer data); -static void list_model_init(UiListModel *instance, GObjectClass *cl); - -static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data); -static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data); - -static GObjectClass list_model_class; -static const GTypeInfo list_model_info = { - sizeof(GObjectClass), - NULL, - NULL, - (GClassInitFunc)list_model_class_init, - NULL, - NULL, - sizeof(UiListModel), - 0, - (GInstanceInitFunc)list_model_init -}; -static const GInterfaceInfo list_model_interface_info = { - (GInterfaceInitFunc)list_model_interface_init, - NULL, - NULL -}; -static GType list_model_type; - -static const GInterfaceInfo list_model_dnd_dest_interface_info = { - (GInterfaceInitFunc)list_model_dnd_dest_interface_init, - NULL, - NULL -}; -static const GInterfaceInfo list_model_dnd_src_interface_info = { - (GInterfaceInitFunc)list_model_dnd_src_interface_init, - NULL, - NULL -}; - -void ui_list_init() { - list_model_type = g_type_register_static( - G_TYPE_OBJECT, - "UiListModel", - &list_model_info, - (GTypeFlags)0); - g_type_add_interface_static( - list_model_type, - GTK_TYPE_TREE_MODEL, - &list_model_interface_info); - g_type_add_interface_static( - list_model_type, - GTK_TYPE_TREE_DRAG_DEST, - &list_model_dnd_dest_interface_info); - g_type_add_interface_static( - list_model_type, - GTK_TYPE_TREE_DRAG_SOURCE, - &list_model_dnd_src_interface_info); -} - -static void list_model_class_init(GObjectClass *cl, gpointer data) { - cl->dispose = ui_list_model_dispose; - cl->finalize = ui_list_model_finalize; - -} - -static void list_model_interface_init(GtkTreeModelIface *i, gpointer data) { - i->get_flags = ui_list_model_get_flags; - i->get_n_columns = ui_list_model_get_n_columns; - i->get_column_type = ui_list_model_get_column_type; - i->get_iter = ui_list_model_get_iter; - i->get_path = ui_list_model_get_path; - i->get_value = ui_list_model_get_value; - i->iter_next = ui_list_model_iter_next; - i->iter_children = ui_list_model_iter_children; - i->iter_has_child = ui_list_model_iter_has_child; - i->iter_n_children = ui_list_model_iter_n_children; - i->iter_nth_child = ui_list_model_iter_nth_child; - i->iter_parent = ui_list_model_iter_parent; -} - -static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data) { - i->drag_data_received = ui_list_model_drag_data_received; - i->row_drop_possible = ui_list_model_row_drop_possible; -} - -static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data) { - i->drag_data_delete = ui_list_model_drag_data_delete; - i->drag_data_get = ui_list_model_drag_data_get; - i->row_draggable = ui_list_model_row_draggable; -} - -static void list_model_init(UiListModel *instance, GObjectClass *cl) { - instance->columntypes = NULL; - instance->var = NULL; - instance->numcolumns = 0; - instance->stamp = g_random_int(); -} - -static GType ui_gtk_type(UiModelType type) { - switch(type) { - default: break; - case UI_STRING: return G_TYPE_STRING; - case UI_INTEGER: return G_TYPE_INT; - } - return G_TYPE_INVALID; -} - -static void ui_model_set_value(GType type, void *data, GValue *value) { - switch(type) { - default: break; - case G_TYPE_OBJECT: { - value->g_type = G_TYPE_OBJECT; - g_value_set_object(value, data); - return; - } - case G_TYPE_STRING: { - value->g_type = G_TYPE_STRING; - g_value_set_string(value, data); - return; - } - case G_TYPE_INT: { - value->g_type = G_TYPE_INT; - int *i = data; - g_value_set_int(value, *i); - return; - } - } - value->g_type = G_TYPE_INVALID; -} - -UiListModel* ui_list_model_new(UiObject *obj, UiVar *var, UiModel *info) { - UiListModel *model = g_object_new(list_model_type, NULL); - model->obj = obj; - model->model = info; - model->var = var; - model->columntypes = calloc(sizeof(GType), 2 * info->columns); - int ncol = 0; - for(int i=0;i<info->columns;i++) { - UiModelType type = info->types[i]; - if(type == UI_ICON_TEXT) { - model->columntypes[ncol] = G_TYPE_OBJECT; - ncol++; - model->columntypes[ncol] = G_TYPE_STRING; - } else { - model->columntypes[ncol] = ui_gtk_type(info->types[i]); - } - ncol++; - } - model->numcolumns = ncol; - return model; -} - -void ui_list_model_dispose(GObject *obj) { - -} - -void ui_list_model_finalize(GObject *obj) { - -} - - -GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) { - return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST); -} - -gint ui_list_model_get_n_columns(GtkTreeModel *tree_model) { - g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), 0); - UiListModel *model = UI_LIST_MODEL(tree_model); - return model->numcolumns; -} - -GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index) { - g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), G_TYPE_INVALID); - UiListModel *model = UI_LIST_MODEL(tree_model); - g_return_val_if_fail(index < model->numcolumns, G_TYPE_INVALID); - return model->columntypes[index]; -} - -gboolean ui_list_model_get_iter( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreePath *path) -{ - g_assert(IS_UI_LIST_MODEL(tree_model)); - UiListModel *model = UI_LIST_MODEL(tree_model); - UiList *list = model->var->value; - - // check the depth of the path - // a list must have a depth of 1 - gint depth = gtk_tree_path_get_depth(path); - g_assert(depth == 1); - - // get row - gint *indices = gtk_tree_path_get_indices(path); - gint row = indices[0]; - - // check row - if(row == 0) { - // we don't need to count if the first element is requested - if(list->first(list) == NULL) { - return FALSE; - } - } else if(row >= list->count(list)) { - return FALSE; - } - - // the UiList has an integrated iterator - // we only get a value to adjust it - void *val = NULL; - if(row == 0) { - val = list->first(list); - } else { - val = list->get(list, row); - } - - iter->stamp = model->stamp; - iter->user_data = list->iter; - iter->user_data2 = (gpointer)(intptr_t)row; // list->index - iter->user_data3 = val; - - return val ? TRUE : FALSE; -} - -GtkTreePath* ui_list_model_get_path( - GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), NULL); - g_return_val_if_fail(iter != NULL, NULL); - g_return_val_if_fail(iter->user_data != NULL, NULL); - - UiListModel *model = UI_LIST_MODEL(tree_model); - - GtkTreePath *path = gtk_tree_path_new(); - gtk_tree_path_append_index(path, (int)(intptr_t)iter->user_data2); // list->index - - return path; -} - -void ui_list_model_get_value( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gint column, - GValue *value) -{ - g_return_if_fail(IS_UI_LIST_MODEL(tree_model)); - g_return_if_fail(iter != NULL); - g_return_if_fail(iter->user_data != NULL); - - UiListModel *model = UI_LIST_MODEL(tree_model); - UiList *list = model->var->value; - - g_return_if_fail(column < model->numcolumns); - - // TODO: return correct value from column - - //value->g_type = G_TYPE_STRING; - list->iter = iter->user_data; - //list->index = (int)(intptr_t)iter->user_data2; - //list->current = iter->user_data3; - if(model->model->getvalue) { - void *data = model->model->getvalue(iter->user_data3, column); - if(model->columntypes[column] == G_TYPE_OBJECT) { - UiImage *img = data; - ui_model_set_value(model->columntypes[column], img->pixbuf, value); - } else { - ui_model_set_value(model->columntypes[column], data, value); - } - } else { - value->g_type = G_TYPE_INVALID; - } -} - -gboolean ui_list_model_iter_next( - GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); - g_return_val_if_fail(iter != NULL, FALSE); - //g_return_val_if_fail(iter->user_data != NULL, FALSE); - - if(!iter->user_data) { - return FALSE; - } - - UiListModel *model = UI_LIST_MODEL(tree_model); - UiList *list = model->var->value; - list->iter = iter->user_data; - //list->index = (int)(intptr_t)iter->user_data2; - void *val = list->next(list); - iter->user_data = list->iter; - intptr_t index = (intptr_t)iter->user_data2; - index++; - //iter->user_data2 = (gpointer)(intptr_t)list->index; - iter->user_data2 = (gpointer)index; - iter->user_data3 = val; - return val ? TRUE : FALSE; -} - -gboolean ui_list_model_iter_children( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent) -{ - g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); - - UiListModel *model = UI_LIST_MODEL(tree_model); - UiList *list = model->var->value; - - if(parent) { - return FALSE; - } - - /* - * a list element has no children - * we set the iter to the first element - */ - void *val = list->first(list); - iter->stamp = model->stamp; - iter->user_data = list->iter; - iter->user_data2 = (gpointer)0; - iter->user_data3 = val; - - return val ? TRUE : FALSE; -} - -gboolean ui_list_model_iter_has_child( - GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - return FALSE; -} - -gint ui_list_model_iter_n_children( - GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - g_assert(IS_UI_LIST_MODEL(tree_model)); - - if(!iter) { - // return number of rows - UiListModel *model = UI_LIST_MODEL(tree_model); - UiList *list = model->var->value; - return list->count(list); - } - - return 0; -} - -gboolean ui_list_model_iter_nth_child( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent, - gint n) -{ - g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); - - if(parent) { - return FALSE; - } - - UiListModel *model = UI_LIST_MODEL(tree_model); - UiList *list = model->var->value; - - // check n - if(n == 0) { - // we don't need to count if the first element is requested - if(list->first(list) == NULL) { - return FALSE; - } - } else if(n >= list->count(list)) { - return FALSE; - } - - void *val = list->get(list, n); - iter->stamp = model->stamp; - iter->user_data = list->iter; - iter->user_data2 = (gpointer)(intptr_t)n; // list->index - iter->user_data3 = val; - - return val ? TRUE : FALSE; -} - -gboolean ui_list_model_iter_parent( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *child) -{ - return FALSE; -} - -// ****** dnd ****** - -gboolean ui_list_model_drag_data_received( - GtkTreeDragDest *drag_dest, - GtkTreePath *dest_path, - GtkSelectionData *selection_data) -{ - //printf("drag received\n"); - UiListModel *model = UI_LIST_MODEL(drag_dest); - /* - if(model->model->drop) { - gint *indices = gtk_tree_path_get_indices(dest_path); - gint row = indices[0]; - UiEvent e; - e.obj = model->obj; - e.window = e.obj->window; - e.document = e.obj->ctx->document; - e.eventdata = NULL; - e.intval = 0; - UiSelection s; - s.data = selection_data; - model->model->drop(&e, &s, model->var->value, row); - } - */ - return TRUE; -} - -gboolean ui_list_model_row_drop_possible( - GtkTreeDragDest *drag_dest, - GtkTreePath *dest_path, - GtkSelectionData *selection_data) -{ - //printf("row_drop_possible\n"); - UiListModel *model = UI_LIST_MODEL(drag_dest); - /* - if(model->model->candrop) { - gint *indices = gtk_tree_path_get_indices(dest_path); - gint row = indices[0]; - UiEvent e; - e.obj = model->obj; - e.window = e.obj->window; - e.document = e.obj->ctx->document; - e.eventdata = NULL; - e.intval = 0; - UiSelection s; - s.data = selection_data; - return model->model->candrop(&e, &s, model->var->value, row); - } - */ - return TRUE; -} - -gboolean ui_list_model_row_draggable( - GtkTreeDragSource *drag_source, - GtkTreePath *path) -{ - //printf("row_draggable\n"); - UiListModel *model = UI_LIST_MODEL(drag_source); - /* - if(model->model->candrag) { - gint *indices = gtk_tree_path_get_indices(path); - gint row = indices[0]; - UiEvent e; - e.obj = model->obj; - e.window = e.obj->window; - e.document = e.obj->ctx->document; - e.eventdata = NULL; - e.intval = 0; - return model->model->candrag(&e, model->var->value, row); - } - */ - return TRUE; -} - -gboolean ui_list_model_drag_data_get( - GtkTreeDragSource *drag_source, - GtkTreePath *path, - GtkSelectionData *selection_data) -{ - //printf("drag_data_get\n"); - UiListModel *model = UI_LIST_MODEL(drag_source); - /* - if(model->model->data_get) { - gint *indices = gtk_tree_path_get_indices(path); - gint row = indices[0]; - UiEvent e; - e.obj = model->obj; - e.window = e.obj->window; - e.document = e.obj->ctx->document; - e.eventdata = NULL; - e.intval = 0; - UiSelection s; - s.data = selection_data; - model->model->data_get(&e, &s, model->var->value, row); - } - */ - return TRUE; -} - -gboolean ui_list_model_drag_data_delete( - GtkTreeDragSource *drag_source, - GtkTreePath *path) -{ - //printf("drag_data_delete\n"); - UiListModel *model = UI_LIST_MODEL(drag_source); - /* - if(model->model->data_get) { - gint *indices = gtk_tree_path_get_indices(path); - gint row = indices[0]; - UiEvent e; - e.obj = model->obj; - e.window = e.obj->window; - e.document = e.obj->ctx->document; - e.eventdata = NULL; - e.intval = 0; - model->model->data_delete(&e, model->var->value, row); - } - */ - return TRUE; -}