implement single row list updates (GTK)

7 days ago

author
Olaf Winermann <olaf.wintermann@gmail.com>
date
Sun, 23 Mar 2025 18:09:24 +0100 (7 days ago)
changeset 503
fefdfe7b2fc5
parent 502
390c737daf08
child 504
f0c21da35aa4

implement single row list updates (GTK)

application/main.c file | annotate | diff | comparison | revisions
ui/common/types.c file | annotate | diff | comparison | revisions
ui/gtk/list.c file | annotate | diff | comparison | revisions
--- a/application/main.c	Tue Mar 18 17:47:40 2025 +0100
+++ b/application/main.c	Sun Mar 23 18:09:24 2025 +0100
@@ -35,6 +35,7 @@
 #include <cx/utils.h>
 
 #include "cx/string.h"
+#include "cx/list.h"
 
 #if !defined(UI_COCOA) && !defined(UI_MOTIF)
 
@@ -54,6 +55,7 @@
     UiList *srclist2;
     UiList *items;
     UiGeneric *web;
+    UiString *list_input;
 } MyDocument;
 
 MyDocument *doc1;
@@ -168,9 +170,9 @@
     ui_list_append(doc->list, "test2");
     ui_list_append(doc->list, "test3");
     doc->list2 = ui_list_new(docctx, "list2");
-    ui_list_append(doc->list2, "test1");
-    ui_list_append(doc->list2, "test2");
-    ui_list_append(doc->list2, "test3");
+    ui_list_append(doc->list2, strdup("test1"));
+    ui_list_append(doc->list2, strdup("test2"));
+    ui_list_append(doc->list2, strdup("test3"));
     doc->radio = ui_int_new(docctx, "radio");
     doc->tabview = ui_int_new(docctx, "tabview");
     doc->image = ui_generic_new(docctx, "image");
@@ -190,6 +192,8 @@
     
     doc->web = ui_generic_new(docctx, NULL);
     
+    doc->list_input = ui_string_new(docctx, "list_input");
+    
     //doc->text = ui_text_new(docctx, "text");
     return doc;
 }
@@ -348,6 +352,17 @@
     printf("dropdown[%d]: %s\n", event->intval, event->eventdata);
 }
 
+static void action_update_list(UiEvent *event, void *userdata) {
+    MyDocument *doc = event->document;
+    
+    char *newvalue = ui_get(doc->list_input);
+    CxList *list2 = doc->list2->data;
+    cxListRemove(list2, 1);
+    cxListInsert(list2, 1, strdup(newvalue));
+    
+    doc->list2->update(doc->list2, 1);
+}
+
 void application_startup(UiEvent *event, void *data) {
     // global list
     UiContext *global = ui_global_context();
@@ -436,6 +451,10 @@
             ui_table(obj, .model = model, .list = doc->list2, .colspan = 2, .fill = UI_ON, .contextmenu = menubuilder, .multiselection = TRUE,
                     .onactivate = action_table_activate, .onactivatedata = "activate",
                     .onselection = action_table_activate, .onselectiondata = "selection");
+            ui_hbox(obj, .fill = UI_OFF) {
+                ui_textfield(obj, .value = doc->list_input);
+                ui_button(obj, .label = "Update List Item 1", .onclick = action_update_list);
+            }
         }
         ui_tab(obj, "Tab 2") {
             ui_button(obj, .label = "Button 1 Start Thread", .onclick=action_start_thread);
--- a/ui/common/types.c	Tue Mar 18 17:47:40 2025 +0100
+++ b/ui/common/types.c	Sun Mar 23 18:09:24 2025 +0100
@@ -162,7 +162,7 @@
 
 UIEXPORT void ui_list_update(UiList *list) {
     if(list->update) {
-        list->update(list, 0);
+        list->update(list, -1);
     }
 }
 
--- a/ui/gtk/list.c	Tue Mar 18 17:47:40 2025 +0100
+++ b/ui/gtk/list.c	Sun Mar 23 18:09:24 2025 +0100
@@ -579,7 +579,16 @@
 
 void ui_listview_update2(UiList *list, int i) {
     UiListView *view = list->obj;
-    ui_update_liststore(view->liststore, list);
+    if(i < 0) {
+        ui_update_liststore(view->liststore, list);
+    } else {
+        void *value = list->get(list, i);
+        if(value) {
+            ObjWrapper *obj = obj_wrapper_new(value);
+            g_list_store_remove(view->liststore, i);
+            g_list_store_insert(view->liststore, i, obj);
+        }
+    }
 }
 
 UiListSelection ui_listview_getselection2(UiList *list) {
@@ -639,6 +648,86 @@
 
 #else
 
+static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, void *elm) {
+    // set column values
+    int c = 0;
+    for(int i=0;i<model->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);
+                intptr_t intptr = (intptr_t)data;
+                g_value_set_int(&value, (int)intptr);
+                break;
+            }
+            case UI_ICON: {
+                g_value_init(&value, G_TYPE_OBJECT);
+                UiIcon *icon = data;
+#if GTK_MAJOR_VERSION >= 4
+                g_value_set_object(&value, icon->info); // TODO: does this work?
+#else
+                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);
+                }
+#endif
+                break;
+            }
+            case UI_ICON_TEXT:
+            case UI_ICON_TEXT_FREE: {
+                UiIcon *icon = data;
+#if GTK_MAJOR_VERSION >= 4
+                if(icon) {
+                    GValue iconvalue = G_VALUE_INIT;
+                    g_value_init(&iconvalue, G_TYPE_OBJECT);
+                    g_value_set_object(&iconvalue, ui_icon_pixbuf(icon));
+                    gtk_list_store_set_value(store, &iter, c, &iconvalue);
+                }
+#else
+                GValue pixbufvalue = G_VALUE_INIT;
+                if(icon) {
+                    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);
+                }
+#endif
+                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);
+    }
+}
+
 static GtkListStore* create_list_store(UiList *list, UiModel *model) {
     int columns = model->columns;
     GType types[2*columns];
@@ -666,83 +755,7 @@
             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);
-                        intptr_t intptr = (intptr_t)data;
-                        g_value_set_int(&value, (int)intptr);
-                        break;
-                    }
-                    case UI_ICON: {
-                        g_value_init(&value, G_TYPE_OBJECT);
-                        UiIcon *icon = data;
-#if GTK_MAJOR_VERSION >= 4
-                        g_value_set_object(&value, icon->info); // TODO: does this work?
-#else
-                        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);
-                        }
-#endif
-                        break;
-                    }
-                    case UI_ICON_TEXT:
-                    case UI_ICON_TEXT_FREE: {
-                        UiIcon *icon = data;
-#if GTK_MAJOR_VERSION >= 4
-                        if(icon) {
-                            GValue iconvalue = G_VALUE_INIT;
-                            g_value_init(&iconvalue, G_TYPE_OBJECT);
-                            g_value_set_object(&iconvalue, ui_icon_pixbuf(icon));
-                            gtk_list_store_set_value(store, &iter, c, &iconvalue);
-                        }
-#else
-                        GValue pixbufvalue = G_VALUE_INIT;
-                        if(icon) {
-                            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);
-                        }
-#endif
-                        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);
-            }
+            update_list_row(store, &iter, model, elm);
             
             // next row
             elm = list->next(list);
@@ -1039,9 +1052,18 @@
 
 void ui_listview_update(UiList *list, int i) {
     UiListView *view = list->obj;
-    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));
+    if(i < 0) {
+        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));
+    } else {
+        void *elm = list->get(list, i);
+        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, elm);
+        }
+    }
 }
 
 UiListSelection ui_listview_getselection(UiList *list) {

mercurial