ui/gtk/list.c

changeset 722
6466b4f16e5e
parent 701
6fdec085c385
child 723
e513086eadbb
--- a/ui/gtk/list.c	Sun Aug 24 13:38:16 2025 +0200
+++ b/ui/gtk/list.c	Sun Aug 24 14:58:27 2025 +0200
@@ -45,16 +45,16 @@
 #include "dnd.h"
 
 
-void* ui_strmodel_getvalue(void *elm, int column) {
-    return column == 0 ? elm : NULL;
+static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+    ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata;
+    return getvalue(elm, col);
 }
 
-static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
-    if(model->getvalue2) {
-        return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
-    } else if(model->getvalue) {
-        return model->getvalue(elm, col);
-    }
+static void* str_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+    return elm;
+}
+
+static void* null_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
     return NULL;
 }
 
@@ -75,6 +75,37 @@
     }
 }
 
+static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
+    UiListView *tableview = malloc(sizeof(UiListView));
+    memset(tableview, 0, sizeof(UiListView));
+    tableview->obj = obj;
+    tableview->model = args->model;
+    tableview->onactivate = args->onactivate;
+    tableview->onactivatedata = args->onactivatedata;
+    tableview->onselection = args->onselection;
+    tableview->onselectiondata = args->onselectiondata;
+    tableview->ondragstart = args->ondragstart;
+    tableview->ondragstartdata = args->ondragstartdata;
+    tableview->ondragcomplete = args->ondragcomplete;
+    tableview->ondragcompletedata = args->ondragcompletedata;
+    tableview->ondrop = args->ondrop;
+    tableview->ondropdata = args->ondropdata;
+    tableview->selection.count = 0;
+    tableview->selection.rows = NULL;
+    
+    if(args->getvalue2) {
+        tableview->getvalue = args->getvalue2;
+        tableview->getvaluedata = args->getvalue2data;
+    } else if(args->getvalue) {
+        tableview->getvalue = getvalue_wrapper;
+        tableview->getvaluedata = (void*)args->getvalue;
+    } else {
+        tableview->getvalue = null_getvalue;
+    }
+    
+    return tableview;
+}
+
 #if GTK_CHECK_VERSION(4, 10, 0)
 
 
@@ -132,16 +163,17 @@
     }
 }
 
-static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
+static void column_factory_bind(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
     UiColData *col = userdata;
     UiList *list = col->listview->var ? col->listview->var->value : NULL;
+    UiListView *listview = col->listview;
     
     ObjWrapper *obj = gtk_list_item_get_item(item);
     UiModel *model = col->listview->model;
     UiModelType type = model->types[col->model_column];
     
     UiBool freevalue = FALSE;
-    void *data = model_getvalue(model, list, obj->data, obj->i, col->data_column, &freevalue);
+    void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue);
     GtkWidget *child = gtk_list_item_get_child(item);
     
     switch(type) {
@@ -173,7 +205,7 @@
             
         }
         case UI_ICON_TEXT_FREE: {
-            void *data2 = model_getvalue(model, list, obj->data, obj->i, col->data_column+1, &freevalue);
+            void *data2 = listview->getvalue(list, obj->data, obj->i, col->data_column+1, listview->getvaluedata, &freevalue);
             if(type == UI_ICON_TEXT_FREE) {
                 freevalue = TRUE;
             }
@@ -207,50 +239,25 @@
     return selection_model;
 }
 
-static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
-    UiListView *tableview = malloc(sizeof(UiListView));
-    memset(tableview, 0, sizeof(UiListView));
-    tableview->obj = obj;
-    tableview->model = args->model;
-    tableview->onactivate = args->onactivate;
-    tableview->onactivatedata = args->onactivatedata;
-    tableview->onselection = args->onselection;
-    tableview->onselectiondata = args->onselectiondata;
-    tableview->ondragstart = args->ondragstart;
-    tableview->ondragstartdata = args->ondragstartdata;
-    tableview->ondragcomplete = args->ondragcomplete;
-    tableview->ondragcompletedata = args->ondragcompletedata;
-    tableview->ondrop = args->ondrop;
-    tableview->ondropdata = args->ondropdata;
-    tableview->selection.count = 0;
-    tableview->selection.rows = NULL;
-    return tableview;
-}
-
 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
     // to simplify things and share code with ui_table_create, we also
     // use a UiModel for the listview
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    if(args->getvalue2) {
-        model->getvalue2 = args->getvalue2;
-        model->getvalue2data = args->getvalue2data;
-    } else if(args->getvalue) {
-        model->getvalue = args->getvalue;
-    } else {
-        model->getvalue = ui_strmodel_getvalue;
-    }
     args->model = model;
     
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
     UiListView *listview = create_listview(obj, args);
+    if(!args->getvalue && !args->getvalue2) {
+        listview->getvalue = str_getvalue;
+    }
     
     listview->columns = malloc(sizeof(UiColData));
     listview->columns->listview = listview;
     listview->columns->data_column = 0;
     listview->columns->model_column = 0;
-    
+     
     GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
     g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
     g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
@@ -283,7 +290,7 @@
         ui_update_liststore(ls, list);
     } else if (args->static_elements && args->static_nelm > 0) {
         listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
-        listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
+        listview->getvalue = str_getvalue; // force string values
         ui_update_liststore_static(ls, listview->elements, listview->nelm);
     }
     
@@ -323,19 +330,15 @@
     // to simplify things and share code with ui_tableview_create, we also
     // use a UiModel for the listview
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    if(args->getvalue2) {
-        model->getvalue2 = args->getvalue2;
-        model->getvalue2data = args->getvalue2data;
-    } else if(args->getvalue) {
-        model->getvalue = args->getvalue;
-    } else {
-        model->getvalue = ui_strmodel_getvalue;
-    }
     args->model = model;
     
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
     UiListView *listview = create_listview(obj, args);
     
+    if(!args->getvalue && !args->getvalue2) {
+        listview->getvalue = str_getvalue;
+    }
+    
     listview->columns = malloc(sizeof(UiColData));
     listview->columns->listview = listview;
     listview->columns->data_column = 0;
@@ -373,7 +376,7 @@
         ui_update_liststore(ls, list);
     } else if (args->static_elements && args->static_nelm > 0) {
         listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
-        listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
+        listview->getvalue = str_getvalue; // force string values
         ui_update_liststore_static(ls, listview->elements, listview->nelm);
     }
     
@@ -704,12 +707,13 @@
 
 #else
 
-static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, UiList *list, void *elm, int row) {
+static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIter *iter, UiList *list, void *elm, int row) {
+    UiModel *model = listview->model;
     // set column values
     int c = 0;
     for(int i=0;i<model->columns;i++,c++) {
         UiBool freevalue = FALSE;
-        void *data = model_getvalue(model, list, elm, row, c, &freevalue);
+        void *data = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
 
         GValue value = G_VALUE_INIT;
         switch(model->types[i]) {
@@ -774,7 +778,7 @@
                 c++;
                 
                 freevalue = FALSE;
-                char *str = model_getvalue(model, list, elm, row, c, &freevalue);
+                char *str = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
                 g_value_init(&value, G_TYPE_STRING);
                 g_value_set_string(&value, str);
                 if(model->types[i] == UI_ICON_TEXT_FREE || freevalue) {
@@ -788,7 +792,8 @@
     }
 }
 
-static GtkListStore* create_list_store(UiList *list, UiModel *model) {
+static GtkListStore* create_list_store(UiListView *listview, UiList *list) {
+    UiModel *model = listview->model;
     int columns = model->columns;
     GType types[2*columns];
     int c = 0;
@@ -816,7 +821,7 @@
             GtkTreeIter iter;
             gtk_list_store_insert (store, &iter, -1);
             
-            update_list_row(store, &iter, model, list, elm, i++);
+            update_list_row(listview, store, &iter, list, elm, i++);
             
             // next row
             elm = list->next(list);
@@ -850,36 +855,29 @@
 #endif
     
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    if(args->getvalue2) {
-        model->getvalue2 = args->getvalue2;
-        model->getvalue2data = args->getvalue2data;
-    } else if(args->getvalue) {
-        model->getvalue = args->getvalue;
-    } else {
-        model->getvalue = ui_strmodel_getvalue;
+    
+    UiListView *listview = create_listview(obj, args);
+    if(!args->getvalue && !args->getvalue2) {
+        listview->getvalue = str_getvalue;
     }
-    
-    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_object_unref(listmodel);
-    
-    UiListView *listview = malloc(sizeof(UiListView));
-    memset(listview, 0, sizeof(UiListView));
-    listview->obj = obj;
-    listview->widget = view;
-    listview->var = var;
     listview->model = model;
-    listview->selection.count = 0;
-    listview->selection.rows = NULL;
     g_signal_connect(
                 view,
                 "destroy",
                 G_CALLBACK(ui_listview_destroy),
                 listview);
     
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    
+    // init listview
+    listview->widget = view;
+    listview->var = var;
+    
+    UiList *list = var ? var->value : NULL;
+    GtkListStore *listmodel = create_list_store(listview, list);
+    gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
+    g_object_unref(listmodel);
+    
     // bind var
     list->update = ui_listview_update;
     list->getselection = ui_listview_getselection;
@@ -1015,36 +1013,23 @@
     
     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_object_unref(listmodel);
-    
     //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL);
     //g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL);
        
     // add TreeView as observer to the UiList to update the TreeView if the
     // data changes
-    UiListView *tableview = malloc(sizeof(UiListView));
-    memset(tableview, 0, sizeof(UiListView));
-    tableview->obj = obj;
-    tableview->widget = view;
-    tableview->var = var;
-    tableview->model = model;
-    tableview->ondragstart = args->ondragstart;
-    tableview->ondragstartdata = args->ondragstartdata;
-    tableview->ondragcomplete = args->ondragcomplete;
-    tableview->ondragcompletedata = args->ondragcompletedata;
-    tableview->ondrop = args->ondrop;
-    tableview->ondropdata = args->ondropdata;
-    tableview->selection.count = 0;
-    tableview->selection.rows = NULL;
+    UiListView *tableview = create_listview(obj, args);
     g_signal_connect(
                 view,
                 "destroy",
                 G_CALLBACK(ui_listview_destroy),
                 tableview);
     
+    UiList *list = var ? var->value : NULL;
+    GtkListStore *listmodel = create_list_store(tableview, list);
+    gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
+    g_object_unref(listmodel);
+    
     // bind var
     list->update = ui_listview_update;
     list->getselection = ui_listview_getselection;
@@ -1121,7 +1106,7 @@
 void ui_listview_update(UiList *list, int i) {
     UiListView *view = list->obj;
     if(i < 0) {
-        GtkListStore *store = create_list_store(list, view->model);
+        GtkListStore *store = create_list_store(view, list);
         gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store));
         g_object_unref(G_OBJECT(store));
     } else {
@@ -1129,7 +1114,7 @@
         GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget));
         GtkTreeIter iter;
         if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) {
-            update_list_row(GTK_LIST_STORE(store), &iter, view->model, list, elm, i);
+            update_list_row(view, GTK_LIST_STORE(store), &iter, list, elm, i);
         }
     }
 }
@@ -1159,46 +1144,43 @@
 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
     UiObject* current = uic_current_obj(obj);
     
-    UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    if(args->getvalue2) {
-        model->getvalue2 = args->getvalue2;
-        model->getvalue2data = args->getvalue2data;
-    } else if(args->getvalue) {
-        model->getvalue = args->getvalue;
-    } else {
-        model->getvalue = ui_strmodel_getvalue;
-    }
+    //GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    GtkWidget *combobox = gtk_combo_box_new();
     
-    GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata);
     ui_set_name_and_style(combobox, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, combobox, args->groups);
     UI_APPLY_LAYOUT2(current, args);
     current->container->add(current->container, combobox);
     current->container->current = combobox;
-    return combobox;
-}
-
-GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **elm, size_t nelm, ui_callback f, void *udata) {
-    GtkWidget *combobox = gtk_combo_box_new();
-       
-    UiListView *uicbox = malloc(sizeof(UiListView));
-    memset(uicbox, 0, sizeof(UiListView));
-    uicbox->obj = obj;
-    uicbox->widget = combobox;
+    
+    UiListView *listview = create_listview(obj, args);
+    listview->widget = combobox;
+    listview->model = ui_model(obj->ctx, UI_STRING, "", -1);
+    g_signal_connect(
+                combobox,
+                "destroy",
+                G_CALLBACK(ui_listview_destroy),
+                listview);
     
+    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);
-    
-    if(!list && elm && nelm > 0) {
-        listview_copy_static_elements(uicbox, elm, nelm);
-        for(int i=0;i<nelm;i++) {
+    GtkListStore *listmodel = create_list_store(listview, list);
+    if(var) {
+        listview->var = var;
+        list->update = ui_combobox_modelupdate;
+        list->getselection = ui_combobox_getselection;
+        list->setselection = ui_combobox_setselection;
+        list->obj = listview;
+        list->update(list, -1);
+    } else if(args->static_nelm > 0) {
+        listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
+        for(int i=0;i<args->static_nelm;i++) {
             GtkTreeIter iter;
             GValue value = G_VALUE_INIT;
             gtk_list_store_insert(listmodel, &iter, -1);
             g_value_init(&value, G_TYPE_STRING);
-            g_value_set_string(&value, uicbox->elements[i]);
+            g_value_set_string(&value, listview->elements[i]);
             gtk_list_store_set_value(listmodel, &iter, 0, &value);
         }
     }
@@ -1208,23 +1190,6 @@
         g_object_unref(listmodel);
     }
     
-    uicbox->var = var;
-    uicbox->model = model;
-    
-    g_signal_connect(
-                combobox,
-                "destroy",
-                G_CALLBACK(ui_combobox_destroy),
-                uicbox);
-    
-    // bind var
-    if(list) {
-        list->update = ui_combobox_modelupdate;
-        list->getselection = ui_combobox_getselection;
-        list->setselection = ui_combobox_setselection;
-        list->obj = uicbox;
-    }
-    
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
     gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
     gtk_cell_layout_set_attributes(
@@ -1236,13 +1201,13 @@
     gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
     
     // add callback
-    if(f) {
+    if(args->onactivate) {
         UiEventData *event = ui_malloc(obj->ctx, sizeof(UiEventData));
         event->obj = obj;
-        event->userdata = udata;
-        event->callback = f;
+        event->userdata = args->onactivatedata;
+        event->callback = args->onactivate;
         event->value = 0;
-        event->customdata = uicbox;
+        event->customdata = listview;
 
         g_signal_connect(
                 combobox,
@@ -1277,7 +1242,7 @@
 
 void ui_combobox_modelupdate(UiList *list, int i) {
     UiListView *view = list->obj;
-    GtkListStore *store = create_list_store(view->var->value, view->model);
+    GtkListStore *store = create_list_store(view, list);
     gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store));
     g_object_unref(store);
 }
@@ -1718,19 +1683,6 @@
     free(v);
 }
 
-void ui_combobox_destroy(GtkWidget *w, UiListView *v) {
-    if(v->var) {
-        ui_destroy_boundvar(v->obj->ctx, v->var);
-    }
-    if(v->elements) {
-        for(int i=0;i<v->nelm;i++) {
-            free(v->elements[i]);
-        }
-        free(v->elements);
-    }
-    free(v);
-}
-
 
 /* ------------------------------ Source List ------------------------------ */
 

mercurial