port table to new API, replace custom tree model with GtkListStore newapi

Sun, 18 Feb 2024 19:55:56 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 18 Feb 2024 19:55:56 +0100
branch
newapi
changeset 268
1b321a0c624f
parent 267
79dd183dd4cb
child 269
3380100e20f5

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);
         

mercurial