Sun, 18 Feb 2024 19:55:56 +0100
port table to new API, replace custom tree model with GtkListStore
application/main.c | file | annotate | diff | comparison | revisions | |
ui/gtk/model.c | file | annotate | diff | comparison | revisions | |
ui/gtk/model.h | file | annotate | diff | comparison | revisions | |
ui/gtk/objs.mk | file | annotate | diff | comparison | revisions | |
ui/gtk/tree.c | file | annotate | diff | comparison | revisions | |
ui/gtk/tree.h | file | annotate | diff | comparison | revisions |
--- a/application/main.c Fri Feb 16 19:37:51 2024 +0100 +++ b/application/main.c Sun Feb 18 19:55:56 2024 +0100 @@ -37,6 +37,7 @@ UiString *str1; UiString *str2; UiDouble *progress; + UiList *list; } MyDocument; MyDocument *doc1; @@ -62,9 +63,26 @@ doc->str1 = ui_string_new(docctx, "str1"); doc->str1 = ui_string_new(docctx, "str2"); doc->progress = ui_double_new(docctx, "progress"); + doc->list = ui_list_new(docctx, "list"); + ui_list_append(doc->list, "test1"); + ui_list_append(doc->list, "test2"); + ui_list_append(doc->list, "test3"); return doc; } +UiIcon *icon = NULL; + +static void* list_getvalue(void *elm, int col) { + if(col == 0) { + if(!icon) { + icon = ui_icon("folder", 24); + } + return icon; + } + char *str = elm; + return col == 1 ? str : "x"; +} + void application_startup(UiEvent *event, void *data) { UiObject *obj = ui_window("Test", NULL); @@ -95,6 +113,11 @@ ui_newline(obj); ui_textfield(obj, .value = doc->str1); + ui_newline(obj); + + UiModel *model = ui_model(obj->ctx, UI_ICON_TEXT, "Col 1", UI_STRING, "Col 2", -1); + model->getvalue = list_getvalue; + ui_table(obj, .hexpand = true, .vexpand = true, .colspan = 2, .varname = "list", .model = model); } ui_show(obj);
--- 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; -}
--- a/ui/gtk/model.h Fri Feb 16 19:37:51 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +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. - */ - -#ifndef MODEL_H -#define MODEL_H - -#include "../ui/toolkit.h" -#include "../common/context.h" -#include "../ui/tree.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct UiListModel UiListModel; - -/* - * UiList to GtkTreeModel wrapper - */ -struct UiListModel { - GObject object; - UiObject *obj; - UiModel *model; - UiVar *var; - GType *columntypes; - int numcolumns; - int stamp; -}; - -/* - * initialize the class and register the type - */ -void ui_list_init(); - -/* - * Creates a UiListModel for a given UiList - */ -UiListModel* ui_list_model_new(UiObject *obj, UiVar *var, UiModel *info); - -void ui_list_model_dispose(GObject *obj); -void ui_list_model_finalize(GObject *obj); - - -// interface functions - -GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model); - -gint ui_list_model_get_n_columns(GtkTreeModel *tree_model); - -GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index); - -gboolean ui_list_model_get_iter( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreePath *path); - -GtkTreePath* ui_list_model_get_path( - GtkTreeModel *tree_model, - GtkTreeIter *iter); - -void ui_list_model_get_value( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gint column, - GValue *value); - -gboolean ui_list_model_iter_next( - GtkTreeModel *tree_model, - GtkTreeIter *iter); - -gboolean ui_list_model_iter_children( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent); - -gboolean ui_list_model_iter_has_child( - GtkTreeModel *tree_model, - GtkTreeIter *iter); - -gint ui_list_model_iter_n_children( - GtkTreeModel *tree_model, - GtkTreeIter *iter); - -gboolean ui_list_model_iter_nth_child( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent, - gint n); - -gboolean ui_list_model_iter_parent( - GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *child); - -/* dnd */ - -gboolean ui_list_model_drag_data_received( - GtkTreeDragDest *drag_dest, - GtkTreePath *dest, - GtkSelectionData *selection_data); - -gboolean ui_list_model_row_drop_possible( - GtkTreeDragDest *drag_dest, - GtkTreePath *dest_path, - GtkSelectionData *selection_data); - -gboolean ui_list_model_row_draggable( - GtkTreeDragSource *drag_source, - GtkTreePath *path); - -gboolean ui_list_model_drag_data_get( - GtkTreeDragSource *drag_source, - GtkTreePath *path, - GtkSelectionData *selection_data); - -gboolean ui_list_model_drag_data_delete( - GtkTreeDragSource *drag_source, - GtkTreePath *path); - -#ifdef __cplusplus -} -#endif - -#endif /* MODEL_H */
--- a/ui/gtk/objs.mk Fri Feb 16 19:37:51 2024 +0100 +++ b/ui/gtk/objs.mk Sun Feb 18 19:55:56 2024 +0100 @@ -38,7 +38,6 @@ GTKOBJ += button.o GTKOBJ += display.o GTKOBJ += text.o -GTKOBJ += model.o GTKOBJ += tree.o GTKOBJ += image.o GTKOBJ += graphics.o
--- a/ui/gtk/tree.c Fri Feb 16 19:37:51 2024 +0100 +++ b/ui/gtk/tree.c Sun Feb 18 19:55:56 2024 +0100 @@ -36,13 +36,112 @@ #include "container.h" #include "tree.h" +#include "image.h" void* ui_strmodel_getvalue(void *elm, int column) { return column == 0 ? elm : NULL; } +static GtkListStore* create_list_store(UiList *list, UiModel *model) { + int columns = model->columns; + GType types[2*columns]; + int c = 0; + for(int i=0;i<columns;i++,c++) { + switch(model->types[i]) { + case UI_STRING: + case UI_STRING_FREE: types[c] = G_TYPE_STRING; break; + case UI_INTEGER: types[c] = G_TYPE_INT; break; + case UI_ICON: types[c] = G_TYPE_OBJECT; break; + case UI_ICON_TEXT: + case UI_ICON_TEXT_FREE: { + types[c] = G_TYPE_OBJECT; + types[++c] = G_TYPE_STRING; + } + } + } + + GtkListStore *store = gtk_list_store_newv(c, types); + + if(list) { + void *elm = list->first(list); + while(elm) { + // insert new row + GtkTreeIter iter; + gtk_list_store_insert (store, &iter, -1); + + // set column values + int c = 0; + for(int i=0;i<columns;i++,c++) { + void *data = model->getvalue(elm, c); + + GValue value = G_VALUE_INIT; + switch(model->types[i]) { + case UI_STRING: + case UI_STRING_FREE: { + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, data); + if(model->types[i] == UI_STRING_FREE) { + free(data); + } + break; + } + case UI_INTEGER: { + g_value_init(&value, G_TYPE_INT); + int *intptr = data; + g_value_set_int(&value, *intptr); + break; + } + case UI_ICON: { + g_value_init(&value, G_TYPE_OBJECT); + UiIcon *icon = data; + if(!icon->pixbuf && icon->info) { + GError *error = NULL; + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); + icon->pixbuf = pixbuf; + } + + if(icon->pixbuf) { + g_value_set_object(&value, icon->pixbuf); + } + + break; + } + case UI_ICON_TEXT: + case UI_ICON_TEXT_FREE: { + GValue pixbufvalue = G_VALUE_INIT; + UiIcon *icon = data; + if(!icon->pixbuf && icon->info) { + GError *error = NULL; + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); + icon->pixbuf = pixbuf; + } + g_value_init(&pixbufvalue, G_TYPE_OBJECT); + g_value_set_object(&pixbufvalue, icon->pixbuf); + gtk_list_store_set_value(store, &iter, c, &pixbufvalue); + c++; + + char *str = model->getvalue(elm, c); + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, str); + if(model->types[i] == UI_ICON_TEXT_FREE) { + free(str); + } + break; + } + } + + gtk_list_store_set_value(store, &iter, c, &value); + } + + // next row + elm = list->next(list); + } + } + + return store; +} UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { @@ -66,7 +165,7 @@ UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); model->getvalue = getvalue; UiList *list = var->value; - UiListModel *listmodel = ui_list_model_new(obj, var, model); + GtkListStore *listmodel = create_list_store(list, model); gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); UiListView *listview = malloc(sizeof(UiListView)); @@ -88,7 +187,7 @@ if(f) { UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); event->obj = obj; - event->userdata = udata; + event->activatedata = udata; event->activate = f; event->selection = NULL; @@ -156,12 +255,17 @@ { "text/uri-list", 0, 2 }, }; -UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) { +UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) { + UiObject* current = uic_current_obj(obj); + // create treeview GtkWidget *view = gtk_tree_view_new(); + UiModel *model = args.model; + int columns = model ? model->columns : 0; + int addi = 0; - for(int i=0;i<model->columns;i++) { + for(int i=0;i<columns;i++) { GtkTreeViewColumn *column = NULL; if(model->types[i] == UI_ICON_TEXT) { column = gtk_tree_view_column_new(); @@ -178,6 +282,14 @@ gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1); addi++; + } else if (model->types[i] == UI_ICON) { + GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes( + model->titles[i], + iconrenderer, + "pixbuf", + i + addi, + NULL); } else { GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( @@ -198,8 +310,10 @@ #endif - UiList *list = var->value; - UiListModel *listmodel = ui_list_model_new(obj, var, model); + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); + + UiList *list = var ? var->value : NULL; + GtkListStore *listmodel = create_list_store(list, model); gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL); @@ -225,17 +339,18 @@ // add callback UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); event->obj = obj; - event->activate = cb.activate; - event->selection = cb.selection; - event->userdata = cb.userdata; - if(cb.activate) { + event->activate = args.onactivate; + event->selection = args.onselection; + event->activatedata = args.onactivatedata; + event->selectiondata = args.onselectiondata; + if(args.onactivate) { g_signal_connect( view, "row-activated", G_CALLBACK(ui_listview_activate_event), event); } - if(cb.selection) { + if(args.onselection) { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(view)); g_signal_connect( @@ -258,32 +373,16 @@ GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS gtk_container_add(GTK_CONTAINER(scroll_area), view); - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, scroll_area, TRUE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, scroll_area, FALSE); // ct->current should point to view, not scroll_area, to make it possible // to add a context menu - ct->current = view; + current->container->current = view; return scroll_area; } -UIWIDGET ui_table_deprecated(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_table_var(obj, var, model, cb); -} - -UIWIDGET ui_table_nv(UiObject *obj, char *varname, UiModel *model, UiListCallbacks cb) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - return ui_table_var(obj, var, model, cb); - } else { - // TODO: error - } - return NULL; -} GtkWidget* ui_get_tree_widget(UIWIDGET widget) { GList *c = gtk_container_get_children(GTK_CONTAINER(widget)); @@ -370,9 +469,9 @@ void ui_listview_update(UiList *list, int i) { UiListView *view = list->obj; - UiListModel *model = ui_list_model_new(view->obj, view->var, view->model); - gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model)); - g_object_unref(G_OBJECT(model)); + GtkListStore *store = create_list_store(list, view->model); + gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); // TODO: free old model } @@ -407,7 +506,7 @@ e.document = event->obj->ctx->document; e.eventdata = selection; e.intval = selection->count > 0 ? selection->rows[0] : -1; - event->activate(&e, event->userdata); + event->activate(&e, event->activatedata); if(selection->count > 0) { free(selection->rows); @@ -427,7 +526,7 @@ e.document = event->obj->ctx->document; e.eventdata = selection; e.intval = selection->count > 0 ? selection->rows[0] : -1; - event->selection(&e, event->userdata); + event->selection(&e, event->selectiondata); if(selection->count > 0) { free(selection->rows); @@ -486,24 +585,29 @@ } UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { + /* UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); model->getvalue = getvalue; - UiListModel *listmodel = ui_list_model_new(obj, var, model); + UiList *list = var ? var->value : NULL; + GtkListStore *store = create_list_store(list, model); - GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata); + //GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata); UiContainer *ct = uic_get_current_container(obj); ct->add(ct, combobox, FALSE); return combobox; + */ + return NULL; } -GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata) { - GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); +GtkWidget* ui_create_combobox(UiObject *obj, GtkListStore *store, ui_callback f, void *udata) { + GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); UiListView *uicbox = malloc(sizeof(UiListView)); uicbox->obj = obj; uicbox->widget = combobox; - uicbox->var = model->var; - uicbox->model = model->model; + // TODO + //uicbox->var = model->var; + //uicbox->model = model->model; g_signal_connect( combobox, @@ -512,9 +616,9 @@ uicbox); // bind var - UiList *list = model->var->value; - list->update = ui_combobox_modelupdate; - list->obj = uicbox; + //UiList *list = model->var->value; + //list->update = ui_combobox_modelupdate; + //list->obj = uicbox; GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); @@ -556,7 +660,7 @@ void ui_combobox_modelupdate(UiList *list, int i) { UiListView *view = list->obj; - UiListModel *model = ui_list_model_new(view->obj, view->var, view->model); - gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(model)); + GtkListStore *store = create_list_store(view->var->value, view->model); + gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store)); }
--- a/ui/gtk/tree.h Fri Feb 16 19:37:51 2024 +0100 +++ b/ui/gtk/tree.h Sun Feb 18 19:55:56 2024 +0100 @@ -31,7 +31,6 @@ #include "../ui/tree.h" #include "toolkit.h" -#include "model.h" #ifdef __cplusplus extern "C" { @@ -48,7 +47,8 @@ UiObject *obj; ui_callback activate; ui_callback selection; - void *userdata; + void *activatedata; + void *selectiondata; } UiTreeEventData; void* ui_strmodel_getvalue(void *elm, int column); @@ -76,7 +76,7 @@ int ui_tree_path_list_index(GtkTreePath *path); UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata); -GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata); +GtkWidget* ui_create_combobox(UiObject *obj, GtkListStore *store, ui_callback f, void *udata); void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e); void ui_combobox_modelupdate(UiList *list, int i);