add support for dynamic sublists (GTK)

3 weeks ago

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 16 Feb 2025 22:49:09 +0100 (3 weeks ago)
changeset 466
7c78b0b8b77d
parent 465
00735562b25b
child 467
08e0a66d3bd6

add support for dynamic sublists (GTK)

ui/gtk/list.c file | annotate | diff | comparison | revisions
ui/gtk/list.h file | annotate | diff | comparison | revisions
ui/ui/tree.h file | annotate | diff | comparison | revisions
--- a/ui/gtk/list.c	Sun Feb 16 21:15:17 2025 +0100
+++ b/ui/gtk/list.c	Sun Feb 16 22:49:09 2025 +0100
@@ -1566,6 +1566,34 @@
 }
 #endif
 
+
+static void add_sublist(UiListBox *uilistbox, CxList *sublists, UiSubList *sublist) {
+    UiListBoxSubList uisublist;
+    uisublist.var = uic_widget_var(
+            uilistbox->obj->ctx,
+            uilistbox->obj->ctx,
+            sublist->value,
+            sublist->varname,
+            UI_VAR_LIST);
+    uisublist.numitems = 0;
+    uisublist.header = sublist->header ? strdup(sublist->header) : NULL;
+    uisublist.separator = sublist->separator;
+    uisublist.widgets = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    uisublist.listbox = uilistbox;
+    uisublist.userdata = sublist->userdata;
+    uisublist.index = cxListSize(sublists);
+
+    // bind UiList
+    UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(sublists)-1);
+    UiList *list = uisublist.var->value;
+    if(list) {
+        list->obj = sublist_ptr;
+        list->update = ui_listbox_list_update;
+    }
+
+    cxListAdd(sublists, &uisublist);
+}
+
 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) {
     UiObject* current = uic_current_obj(obj);
     
@@ -1603,42 +1631,32 @@
     uilistbox->sublists->collection.destructor_data = obj;
     uilistbox->first_row = NULL;
     
-    if(args.numsublists == 0 && args.sublists) {
-        args.numsublists = INT_MAX;
-    }
-    for(int i=0;i<args.numsublists;i++) {
-        UiSubList sublist = args.sublists[i];
-        if(!sublist.varname && !sublist.value) {
-            break;
+    if(args.sublists) {
+        // static sublist initalization
+        if(args.numsublists == 0 && args.sublists) {
+            args.numsublists = INT_MAX;
+        }
+        for(int i=0;i<args.numsublists;i++) {
+            UiSubList sublist = args.sublists[i];
+            if(!sublist.varname && !sublist.value) {
+                break;
+            }
+            
+            add_sublist(uilistbox, uilistbox->sublists, &sublist);
         }
         
-        UiListBoxSubList uisublist;
-        uisublist.var = uic_widget_var(
-                obj->ctx,
-                current->ctx,
-                sublist.value,
-                sublist.varname,
-                UI_VAR_LIST);
-        uisublist.numitems = 0;
-        uisublist.header = sublist.header ? strdup(sublist.header) : NULL;
-        uisublist.separator = sublist.separator;
-        uisublist.widgets = cxLinkedListCreateSimple(CX_STORE_POINTERS);
-        uisublist.listbox = uilistbox;
-        uisublist.userdata = sublist.userdata;
-        uisublist.index = i;
-        
-        cxListAdd(uilistbox->sublists, &uisublist);
-        
-        // bind UiList
-        UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(uilistbox->sublists)-1);
-        UiList *list = uisublist.var->value;
-        if(list) {
-            list->obj = sublist_ptr;
-            list->update = ui_listbox_list_update;
+        // fill items
+        ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
+    } else {
+        UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.dynamic_sublist, args.varname, UI_VAR_LIST);
+        if(var) {
+            UiList *list = var->value;
+            list->obj = uilistbox;
+            list->update = ui_listbox_dynamic_update;
+            
+            ui_listbox_dynamic_update(list, 0);
         }
     }
-    // fill items
-    ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
     
     // register uilistbox for both widgets, so it doesn't matter which
     // widget is used later
@@ -1663,6 +1681,35 @@
     return scroll_area;
 }
 
+void ui_listbox_dynamic_update(UiList *list, int x) {
+    UiListBox *uilistbox = list->obj;
+    
+    // unbind/free previous list vars
+    CxIterator i = cxListIterator(uilistbox->sublists);
+    cx_foreach(UiListBoxSubList *, s, i) {
+        if(s->var) {
+            UiList *sl = s->var->value;
+            sl->obj = NULL;
+            sl->update = NULL;
+            if(s->var->type == UI_VAR_SPECIAL) {
+                ui_free(s->var->from_ctx, s->var);
+            }
+        }
+    }
+    
+    cxListFree(uilistbox->sublists);
+    CxList *new_sublists = cxArrayListCreateSimple(sizeof(UiListBoxSubList), list->count(list));
+    uilistbox->sublists = new_sublists;
+    
+    UiSubList *sublist = list->first(list);
+    while(sublist) {
+        add_sublist(uilistbox, new_sublists, sublist);
+        sublist = list->next(list);
+    }
+    
+    ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
+}
+
 void ui_listbox_update(UiListBox *listbox, int from, int to) {
     CxIterator i = cxListIterator(listbox->sublists);
     size_t pos = 0;
--- a/ui/gtk/list.h	Sun Feb 16 21:15:17 2025 +0100
+++ b/ui/gtk/list.h	Sun Feb 16 22:49:09 2025 +0100
@@ -161,6 +161,7 @@
 UiListSelection ui_combobox_getselection(UiList *list);
 void ui_combobox_setselection(UiList *list, UiListSelection selection);
 
+void ui_listbox_dynamic_update(UiList *list, int i);
 void ui_listbox_update(UiListBox *listbox, int from, int to);
 void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index);
 void ui_listbox_list_update(UiList *list, int i);
--- a/ui/ui/tree.h	Sun Feb 16 21:15:17 2025 +0100
+++ b/ui/ui/tree.h	Sun Feb 16 22:49:09 2025 +0100
@@ -183,11 +183,14 @@
     const int *groups;
     
     /*
-     * list of sublists
+     * static list of sublists
      * a sublist must have a varname or a value
      * 
      * the last entry in the list must contain all NULL values or numsublists
      * must contain the number of sublists
+     * 
+     * sublists can be NULL, in which case sublists are dynamically loaded
+     * from dynamic_sublist/varname
      */
     UiSubList *sublists;
     /*
@@ -198,6 +201,17 @@
     size_t numsublists;
     
     /*
+     * list value, that contains UiSubList* elements
+     */
+    UiList *dynamic_sublist;
+    
+    /*
+     * load sublists dynamically from a variable with the specified name
+     */
+    const char *varname;
+    
+    
+    /*
      * callback for each list item, that should fill all necessary
      * UiSubListItem fields
      */

mercurial