ui/gtk/list.c

changeset 749
0f052f6f532c
parent 745
a4ee36ff7147
child 772
fa8afa19b8b6
--- a/ui/gtk/list.c	Wed Sep 03 17:48:46 2025 +0200
+++ b/ui/gtk/list.c	Sat Sep 06 12:40:04 2025 +0200
@@ -191,15 +191,29 @@
     return attr;
 }
 
-static void column_factory_bind(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
+static void column_factory_bind(GtkListItemFactory *unused, 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];
     
+    // cache the GtkListItem
+    CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
+    UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
+    if(row) {
+        if(row->items[col->model_column] == NULL) {
+            row->bound++;
+        }
+    } else {
+        row = calloc(1, sizeof(UiRowItems) + listview->numcolumns * sizeof(GtkListItem*));
+        cxMapPut(listview->bound_rows, row_key, row);
+        row->bound = 1;
+    }
+    row->items[col->model_column] = item;
+    
     UiBool freevalue = FALSE;
     void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue);
     GtkWidget *child = gtk_list_item_get_child(item);
@@ -289,6 +303,21 @@
     }
 }
 
+static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) {
+    ObjWrapper *obj = gtk_list_item_get_item(item);
+    UiListView *listview = col->listview;
+    CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
+    UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
+    if(row) {
+        row->items[col->model_column] = NULL;
+        row->bound--;
+        if(row->bound == 0) {
+            cxMapRemove(listview->bound_rows, row_key);
+        }
+    } // else: should not happen
+}
+    
+
 static GtkSelectionModel* create_selection_model(UiListView *listview, GListStore *liststore, bool multiselection) {
     GtkSelectionModel *selection_model;
     if(multiselection) {
@@ -316,10 +345,14 @@
         listview->getvalue = str_getvalue;
     }
     
+    listview->numcolumns = 1;
     listview->columns = malloc(sizeof(UiColData));
     listview->columns->listview = listview;
     listview->columns->data_column = 0;
     listview->columns->model_column = 0;
+    
+    listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
+    listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
      
     GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
     g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
@@ -402,11 +435,15 @@
         listview->getvalue = str_getvalue;
     }
     
+    listview->numcolumns = 1;
     listview->columns = malloc(sizeof(UiColData));
     listview->columns->listview = listview;
     listview->columns->data_column = 0;
     listview->columns->model_column = 0;
     
+    listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
+    listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
+    
     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);
@@ -495,6 +532,10 @@
     int columns = model ? model->columns : 0;
     
     tableview->columns = calloc(columns, sizeof(UiColData));
+    tableview->numcolumns = columns;
+    
+    tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
+    tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
     
     int addi = 0;
     for(int i=0;i<columns;i++) {
@@ -694,21 +735,20 @@
     } else {
         void *value = list->get(list, i);
         if(value) {
-            ObjWrapper *obj = obj_wrapper_new(value, i);
-            UiListSelection sel = list->getselection(list);
-            // TODO: if index i is selected, the selection is lost
-            // is it possible to update the item without removing it?
-            // workaround: save selection and reapply it
-            int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
-            if(count <= i) {
-                g_list_store_splice(view->liststore, i, 0, (void **)&obj, 1);
-            } else {
-                g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1);
+            ObjWrapper *obj = g_list_model_get_item(G_LIST_MODEL(view->liststore), i);
+            if(obj) {
+                obj->data = value;
             }
-            if(sel.count > 0) {
-                list->setselection(list, sel);
+            
+            CxHashKey row_key = cx_hash_key(&i, sizeof(int));
+            UiRowItems *row = cxMapGet(view->bound_rows, row_key);
+            if(row) {
+                for(int c=0;c<view->numcolumns;c++) {
+                    if(row->items[c] != NULL) {
+                        column_factory_bind(NULL, row->items[c], &view->columns[c]);
+                    }
+                }
             }
-            ui_listselection_free(sel);
         }
     }
 }
@@ -1870,6 +1910,7 @@
     free(v->columns);
     pango_attr_list_unref(v->default_attributes);
     pango_attr_list_unref(v->current_row_attributes);
+    cxMapFree(v->bound_rows);
 #endif
     free(v->selection.rows);
     free(v);

mercurial