ui/gtk/list.c

changeset 1245
4163776eef49
parent 1244
a29b53f97d1a
--- a/ui/gtk/list.c	Wed Sep 09 18:57:52 2026 +0200
+++ b/ui/gtk/list.c	Thu Sep 10 17:36:06 2026 +0200
@@ -40,6 +40,7 @@
 #include <cx/linked_list.h>
 
 #include "list.h"
+#include "tree.h"
 #include "button.h"
 #include "icon.h"
 #include "menu.h"
@@ -123,55 +124,18 @@
     return tableview;
 }
 
-static UiListView* create_treeview(UiObject *obj, UiTreeArgs *args) {
-    UiListView *treeview = malloc(sizeof(UiListView));
-    memset(treeview, 0, sizeof(UiListView));
-    treeview->obj = obj;
-    treeview->model = args->model;
-    treeview->multiselection = args->multiselection;
-    treeview->onactivate = args->onactivate;
-    treeview->onactivatedata = args->onactivatedata;
-    treeview->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL;
-    treeview->onselection = args->onselection;
-    treeview->onselectiondata = args->onselectiondata;
-    treeview->onselection_action = args->onselection_action ? strdup(args->onselection_action) : NULL;
-    treeview->ondragstart = args->ondragstart;
-    treeview->ondragstartdata = args->ondragstartdata;
-    treeview->ondragstart_action = args->ondragstart_action ? strdup(args->ondragstart_action) : NULL;
-    treeview->ondragcomplete = args->ondragcomplete;
-    treeview->ondragcompletedata = args->ondragcompletedata;
-    treeview->ondragcomplete_action = args->ondragcomplete_action ? strdup(args->ondragcomplete_action) : NULL;
-    treeview->ondrop = args->ondrop;
-    treeview->ondropdata = args->ondropdata;
-    treeview->ondrop_action = args->ondrop_action ? strdup(args->ondrop_action) : NULL;
-    treeview->selection.count = 0;
-    treeview->selection.rows = NULL;
-    treeview->current_row = -1;
-    
-#if GTK_CHECK_VERSION(4, 0, 0)
-    treeview->coldata.listview = treeview;
-    treeview->coldata.column = 0;
-#endif
-    
-    if(args->getvalue != NULL) {
-        treeview->getvalue = args->getvalue;
-        treeview->getvaluedata = args->getvaluedata;
-    } else {
-        args->getvalue = ui_null_getvalue;
-    }
-    
-    treeview->istreeview = TRUE;
-    treeview->getdepth = args->getdepth;
-    treeview->getdepthdata = args->getdepthdata;
-      
-    return treeview;
-}
-
 #if GTK_CHECK_VERSION(4, 10, 0)
 
 
 /* BEGIN GObject wrapper for generic pointers */
 
+typedef struct _ObjWrapper {
+    GObject parent_instance;
+    GListStore *children;
+    void *data;
+    int i;
+} ObjWrapper;
+
 typedef struct _ObjWrapperClass {
     GObjectClass parent_class;
 } ObjWrapperClass;
@@ -183,6 +147,7 @@
 }
 
 static void obj_wrapper_init(ObjWrapper *self) {
+    self->children = NULL;
     self->data = NULL;
 }
 
@@ -802,13 +767,12 @@
 
 UIWIDGET ui_treeview_create(UiObject *obj, UiTreeArgs *args) {
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
-    //g_list_store_append(ls, v1);
     
     // create obj to store all relevant data we need for handling events
     // and list updates
-    UiListView *tableview = create_treeview(obj, args);
+    UiListView *treeview = ui_create_treeview(obj, args);
     
-    GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection);
+    GtkSelectionModel *selection_model = create_selection_model(treeview, ls, args->multiselection);
     GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
     if(!args->show_header) {
         gtk_widget_set_visible(gtk_widget_get_first_child(view), FALSE);
@@ -817,15 +781,15 @@
     UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init tableview
-    tableview->widget = view;
-    tableview->var = var;
-    tableview->liststore = ls;
-    tableview->selectionmodel = selection_model;
+    treeview->widget = view;
+    treeview->var = var;
+    treeview->liststore = ls;
+    treeview->selectionmodel = selection_model;
     g_signal_connect(
                 view,
                 "destroy",
                 G_CALLBACK(ui_listview_destroy),
-                tableview);
+                treeview);
     
     
     // create columns from UiModel
@@ -833,42 +797,42 @@
     int columns = 0;
     if(model) {
         columns = model->columns;
-        ui_model_add_observer(model, ui_listview_update_model, tableview);
+        ui_model_add_observer(model, ui_listview_update_model, treeview);
     }
     
-    tableview->columns = calloc(columns, sizeof(int));
-    tableview->numcolumns = columns;
+    treeview->columns = calloc(columns, sizeof(int));
+    treeview->numcolumns = columns;
     
-    tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
-    tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
+    treeview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
+    treeview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
     
     int addi = 0;
     for(int i=0;i<columns;i++) {
-        tableview->columns[i] = i+addi;
+        treeview->columns[i] = i+addi;
         
         if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
             // icon+text has 2 data columns
             addi++;
         }
         
-        add_column(tableview, i);
+        add_column(treeview, i);
     }
     
     // bind listview to list
     if(var && var->value) {
         UiList *list = var->value;
         
-        list->obj = tableview;
+        list->obj = treeview;
         list->update = ui_listview_update2;
         list->getselection = ui_listview_getselection2;
         list->setselection = ui_listview_setselection2;
         
-        ui_update_liststore(ls, list);
+        ui_update_tree_liststore(ls, list);
     }
     
     // event handling
     if(args->onactivate || args->onactivate_action) {
-        g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
+        g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), treeview);
     }
     if(args->contextmenu) {
         UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
@@ -1066,6 +1030,10 @@
     }
 }
 
+void ui_update_tree_liststore(GListStore *liststore, UiList *list) {
+    
+}
+
 void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm) {
     g_list_store_remove_all(liststore);
     for(int i=0;i<nelm;i++) {
@@ -3068,3 +3036,147 @@
         data->callback(&event, data->userdata);
     }
 }
+
+/* ------------------------------ SourceList2 ------------------------------ */
+
+static void ui_destroy_sourcelist2(GtkWidget *w, UiListBox2 *v) {
+    cxListFree(v->rows);
+    free(v->onactivate_action);
+    free(v->onbuttonclick_action);
+    free(v);
+}
+
+UIWIDGET ui_sourcelist2_create(UiObject *obj, UiSourceList2Args *args) {
+#ifdef UI_GTK3
+    GtkWidget *listbox = g_object_new(ui_sidebar_list_box_get_type(), NULL);
+#else
+    GtkWidget *listbox = gtk_list_box_new();
+#endif
+    if(!args->style_class) {
+#if GTK_MAJOR_VERSION >= 4
+        WIDGET_ADD_CSS_CLASS(listbox, "navigation-sidebar");
+#else
+        WIDGET_ADD_CSS_CLASS(listbox, "sidebar");
+#endif
+    }
+    GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
+    SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox);
+    
+    ui_set_name_and_style(listbox, args->name, args->style_class);
+    ui_set_widget_states(obj->ctx, listbox, args->states);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, scroll_area, &layout);
+    
+    UiListBox2 *uilistbox = malloc(sizeof(UiListBox2));
+    uilistbox->obj = obj;
+    uilistbox->listbox = GTK_LIST_BOX(listbox);
+    uilistbox->rows = cxArrayListCreate(NULL, CX_STORE_POINTERS, 64);
+    uilistbox->getvalue = args->getvalue;
+    uilistbox->getvaluedata = args->getvaluedata;
+    uilistbox->getdepth = args->getdepth;
+    uilistbox->getdepthdata = args->getdepthdata;
+    uilistbox->onactivate = args->onactivate;
+    uilistbox->onactivatedata = args->onactivatedata;
+    uilistbox->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL;
+    uilistbox->onbuttonclick = args->onbuttonclick;
+    uilistbox->onbuttonclickdata = args->onbuttonclickdata;
+    uilistbox->onbuttonclick_action = args->onbuttonclick_action ? strdup(args->onbuttonclick_action) : NULL;
+    
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+    uilistbox->var = var;
+    if(var) {
+        UiList *list = var->value;
+        list->update = ui_listbox2_update;
+        list->getselection = ui_listbox2_getselection;
+        list->setselection = ui_listbox2_setselection;
+        list->obj = uilistbox;
+        ui_listbox2_update(list, -1);
+    }
+    
+    // register uilistbox for both widgets, so it doesn't matter which
+    // widget is used later
+    g_object_set_data(G_OBJECT(scroll_area), "ui_listbox", uilistbox);
+    g_object_set_data(G_OBJECT(listbox), "ui_listbox", uilistbox);
+    
+    if(args->contextmenu) {
+        UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, listbox);
+        ui_widget_set_contextmenu(listbox, menu);
+    }
+    
+    // signals
+    g_signal_connect(
+                listbox,
+                "destroy",
+                G_CALLBACK(ui_destroy_sourcelist2),
+                uilistbox);
+    
+    if(args->onactivate) {
+        g_signal_connect(
+                listbox,
+                "row-activated",
+                G_CALLBACK(ui_listbox2_row_activate),
+                NULL);
+    }
+    
+    return scroll_area;
+}
+
+
+static int listbox2_update_item(UiListBox2 *listbox, GtkWidget *row, UiList *list, void *elm, int index) {
+    UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
+    if(listbox->getvalue) {
+        listbox->getvalue(list,elm, index, &item, listbox->getvaluedata);
+    }
+    
+    GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
+    
+    return 0;
+}
+
+static void listbox2_update_all(UiListBox2 *listbox) {
+    gtk_list_box_remove_all(listbox->listbox);
+    cxListClear(listbox->rows);
+    if(!listbox->var) {
+        return;
+    }
+    UiList *list = listbox->var->value;
+    if(!list) {
+        return;
+    }
+    
+    
+    int index = 0;
+    void *elm = list->first(list);
+    while(elm) {
+        GtkWidget *row = gtk_list_box_row_new();
+        cxListAdd(listbox->rows, row);
+        gtk_list_box_append(listbox->listbox, row);
+        int node_depth = listbox2_update_item(listbox, row, list, elm, index);
+        
+        elm = list->next(list);
+        index++;
+    }
+}
+
+void ui_listbox2_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
+    
+}
+
+
+void ui_listbox2_update(UiList *list, int i) {
+    UiListBox2 *listbox = list->obj;
+    if(i >= 0) {
+        // TODO
+    } else {
+        listbox2_update_all(listbox);
+    }
+}
+
+UiListSelection ui_listbox2_getselection(UiList *list) {
+    
+}
+
+void ui_listbox2_setselection(UiList *list, UiListSelection selection) {
+    
+}

mercurial