ui/gtk/container.c

branch
newapi
changeset 422
c1354a29a7e9
parent 410
a080c69125d1
--- a/ui/gtk/container.c	Mon Dec 30 12:50:52 2024 +0100
+++ b/ui/gtk/container.c	Mon Dec 30 19:48:05 2024 +0100
@@ -946,6 +946,126 @@
 
 
 
+/* -------------------- ItemList Container -------------------- */
+
+static void remove_item(void *data, void *item) {
+    UiGtkItemListContainer *ct = data;
+    UiObject *obj = item;
+    if(ct->remove_items) {
+        BOX_REMOVE(ct->widget, obj->widget);
+    }
+    uic_object_destroy(obj);
+}
+
+static void update_itemlist(UiList *list, int c) {
+    UiGtkItemListContainer *ct = list->obj;
+    
+    CxMap *new_items = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    new_items->collection.advanced_destructor = remove_item;
+    new_items->collection.destructor_data = ct;
+    
+    // only create new widgets for new elements, so at first we have
+    // to find which elements are new
+    // check which elements in the list are already in the container
+    void *elm = list->first(list);
+    int j = 0;
+    while(elm) {
+        CxHashKey key = cx_hash_key(&elm, sizeof(void*));
+        UiObject *item_obj = cxMapRemoveAndGet(ct->current_items, key);
+        if(item_obj) {
+            g_object_ref(G_OBJECT(item_obj->widget));
+            BOX_REMOVE(ct->widget, item_obj->widget);
+            cxMapPut(new_items, key, item_obj);
+        }
+        elm = list->next(list);
+        j++;
+    }
+    
+    // ct->current_items only contains elements, that are not in the list
+    cxMapDestroy(ct->current_items); // calls destructor remove_item
+    ct->current_items = new_items;
+    
+    // add all items
+    int index = 0;
+    elm = list->first(list);
+    while(elm) {
+        CxHashKey key = cx_hash_key(&elm, sizeof(void*));
+        UiObject *item_obj = cxMapGet(ct->current_items, key);
+        if(item_obj) {
+            // re-add previously created widget
+            ui_box_container_add(ct->container, item_obj->widget, FALSE);
+        } else {
+            // create new widget and object for this list element
+            CxMempool *mp = cxBasicMempoolCreate(256);
+            const CxAllocator *a = mp->allocator;
+            UiObject *obj = cxCalloc(a, 1, sizeof(UiObject));
+            obj->ctx = uic_context(obj, mp);
+            obj->window = NULL;
+            obj->widget = ui_subcontainer_create(
+                    ct->subcontainer,
+                    obj,
+                    ct->spacing,
+                    ct->columnspacing,
+                    ct->rowspacing,
+                    ct->margin);
+            ui_box_container_add(ct->container, obj->widget, FALSE);
+            if(ct->create_ui) {
+                ct->create_ui(obj, index, elm, ct->userdata);
+            }
+            cxMapPut(new_items, key, obj);
+        }
+        elm = list->next(list);
+        index++;
+    }
+}
+
+static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *container) {
+    container->remove_items = FALSE;
+    cxMapDestroy(container->current_items);
+    free(container);
+}
+
+UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) {
+    UiObject *current = uic_current_obj(obj);
+    UiContainer *ct = current->container;
+    UI_APPLY_LAYOUT1(current, args);
+    
+    GtkWidget *box = args.container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing);
+    ui_set_name_and_style(box, args.name, args.style_class);
+    GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box;
+    ct->add(ct, widget, TRUE);
+    
+    UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer));
+    container->parent = obj;
+    container->widget = box;
+    container->container = ui_box_container(current, box, args.container);
+    container->create_ui = args.create_ui;
+    container->userdata = args.userdata;
+    container->subcontainer = args.subcontainer;
+    container->current_items = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    container->current_items->collection.advanced_destructor = remove_item;
+    container->current_items->collection.destructor_data = container;
+    container->margin = args.sub_margin;
+    container->spacing = args.sub_spacing;
+    container->columnspacing = args.sub_columnspacing;
+    container->rowspacing = args.sub_rowspacing;
+    container->remove_items = TRUE;
+    
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_LIST);
+    if(var) {
+        UiList *list = var->value;
+        list->obj = container;
+        list->update = update_itemlist;
+        update_itemlist(list, 0);
+    }
+    g_signal_connect(
+                box,
+                "destroy",
+                G_CALLBACK(destroy_itemlist_container),
+                container);
+    
+    return box;
+}
 
 
 

mercurial