ui/gtk/list.c

changeset 853
380ec881faa2
parent 824
a0ea8f3aa6e8
child 855
37f8a9fa8251
--- a/ui/gtk/list.c	Thu Oct 16 15:57:05 2025 +0200
+++ b/ui/gtk/list.c	Fri Oct 17 15:44:30 2025 +0200
@@ -2089,7 +2089,7 @@
     if(sublist->separator) {
         GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
         gtk_list_box_row_set_header(row, separator);
-    } else if(sublist->header) {
+    } else if(sublist->header && !listbox->header_is_item) {
         GtkWidget *header = gtk_label_new(sublist->header);
         gtk_widget_set_halign(header, GTK_ALIGN_START);
         if(row == listbox->first_row) {
@@ -2177,6 +2177,7 @@
     UiListBox *uilistbox = malloc(sizeof(UiListBox));
     uilistbox->obj = obj;
     uilistbox->listbox = GTK_LIST_BOX(listbox);
+    uilistbox->header_is_item = args->header_is_item;
     uilistbox->getvalue = args->getvalue;
     uilistbox->getvaluedata = args->getvaluedata;
     uilistbox->onactivate = args->onactivate;
@@ -2326,12 +2327,17 @@
 }
 
 static void listbox_fill_row(UiListBox *listbox, GtkWidget *row, UiListBoxSubList *sublist, UiSubListItem *item, int index) {
+    UiBool is_header = index < 0;
+    
     GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
     if(item->icon) {
         GtkWidget *icon = ICON_IMAGE(item->icon);
         BOX_ADD(hbox, icon);
     }
     GtkWidget *label = gtk_label_new(item->label);
+    if(is_header) {
+        WIDGET_ADD_CSS_CLASS(label, "ui-listbox-header-row");
+    }
     gtk_widget_set_halign(label, GTK_ALIGN_START);
     BOX_ADD_EXPAND(hbox, label);
     if(item->badge) {
@@ -2352,6 +2358,9 @@
     event->userdata2 = listbox->onbuttonclickdata;
     event->value0 = index;
     
+    // TODO: semi-memory leak when listbox_fill_row is called again for the same row
+    // each row update will create a new UiEventDataExt object and a separate destroy handler
+    
     g_signal_connect(
             row,
             "destroy",
@@ -2390,7 +2399,8 @@
 }
 
 static void update_sublist_item(UiListBox *listbox, UiListBoxSubList *sublist, int index) {
-    GtkListBoxRow *row = gtk_list_box_get_row_at_index(listbox->listbox, sublist->startpos + index);
+    int header_row = listbox->header_is_item && sublist->header ? 1 : 0;
+    GtkListBoxRow *row = gtk_list_box_get_row_at_index(listbox->listbox, sublist->startpos + index + header_row);
     if(!row) {
         return;
     }
@@ -2438,22 +2448,32 @@
         return;
     }
     
-    size_t index = 0;
+    int index = 0;
     void *elm = list->first(list);
+    void *first = elm;
     
-    if(!elm && sublist->header) {
+    if(sublist->header && !listbox->header_is_item && !elm) {
         // empty row for header
         GtkWidget *row = gtk_list_box_row_new();
         cxListAdd(sublist->widgets, row);
         g_object_set_data(G_OBJECT(row), "ui_listbox", listbox);
         g_object_set_data(G_OBJECT(row), "ui_listbox_sublist", sublist);
         intptr_t rowindex = listbox_insert_index + index;
-        g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
+        //g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
         gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index);
         sublist->numitems = 1;
         return;
     }
     
+    int first_index = 0;
+    int header_row = 0;
+    if(listbox->header_is_item && sublist->header) {
+        index = -1;
+        first_index = -1;
+        header_row = 1;
+        elm = sublist->header;
+    }
+    
     while(elm) {
         UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
         if(listbox->getvalue) {
@@ -2464,8 +2484,8 @@
         
         // create listbox item
         GtkWidget *row = gtk_list_box_row_new();
-        listbox_fill_row(listbox, row, sublist, &item, (int)index);
-        if(index == 0) {
+        listbox_fill_row(listbox, row, sublist, &item, index);
+        if(index == first_index) {
             // first row in the sublist, set ui_listbox data to the row
             // which is then used by the headerfunc
             g_object_set_data(G_OBJECT(row), "ui_listbox", listbox);
@@ -2477,8 +2497,8 @@
             }
         }
         intptr_t rowindex = listbox_insert_index + index;
-        g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
-        gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index);
+        //g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
+        gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index + header_row);
         cxListAdd(sublist->widgets, row);
         
         // cleanup
@@ -2489,7 +2509,7 @@
         free(item.badge);
         
         // next row
-        elm = list->next(list);
+        elm = index >= 0 ? list->next(list) : first;
         index++;
     }
     
@@ -2523,7 +2543,7 @@
     eventdata.sublist_index = sublist->index;
     eventdata.row_index = data->value0;
     eventdata.sublist_userdata = sublist->userdata;
-    eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index);
+    eventdata.row_data = eventdata.row_index >= 0 ? eventdata.list->get(eventdata.list, eventdata.row_index) : NULL;
     eventdata.event_data = data->customdata2;
     
     UiEvent event;

mercurial