add new gtk4 listview/combobox implementation

Sun, 05 Jan 2025 17:31:53 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 05 Jan 2025 17:31:53 +0100
changeset 438
7b1d715e5c11
parent 437
f02a62de0328
child 439
bf7084544cb1

add new gtk4 listview/combobox implementation

application/main.c file | annotate | diff | comparison | revisions
ui/gtk/list.c file | annotate | diff | comparison | revisions
ui/gtk/list.h file | annotate | diff | comparison | revisions
--- a/application/main.c	Sun Jan 05 16:56:05 2025 +0100
+++ b/application/main.c	Sun Jan 05 17:31:53 2025 +0100
@@ -414,7 +414,7 @@
         ui_tab(obj, "Tab 1") {
             UiModel *model = ui_model(obj->ctx, UI_STRING, "col1", UI_INTEGER, "col2", UI_ICON, "col3", UI_ICON_TEXT, "col4", UI_INTEGER, "col5", -1);
             model->getvalue = table_getvalue;
-            ui_table(obj, .model = model, .list = doc->list2, .colspan = 2, .fill = UI_ON, .contextmenu = menubuilder, .multiselection = TRUE,
+            ui_listview(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");
         }
--- a/ui/gtk/list.c	Sun Jan 05 16:56:05 2025 +0100
+++ b/ui/gtk/list.c	Sun Jan 05 17:31:53 2025 +0100
@@ -48,6 +48,527 @@
     return column == 0 ? elm : NULL;
 }
 
+/*
+static GtkTargetEntry targetentries[] =
+    {
+      { "STRING",        0, 0 },
+      { "text/plain",    0, 1 },
+      { "text/uri-list", 0, 2 },
+    };
+*/
+
+#if GTK_CHECK_VERSION(4, 10, 0)
+
+
+/* BEGIN GObject wrapper for generic pointers */
+
+typedef struct _ObjWrapper {
+    GObject parent_instance;
+    void *data;
+} ObjWrapper;
+
+typedef struct _ObjWrapperClass {
+    GObjectClass parent_class;
+} ObjWrapperClass;
+
+G_DEFINE_TYPE(ObjWrapper, obj_wrapper, G_TYPE_OBJECT)
+
+static void obj_wrapper_class_init(ObjWrapperClass *klass) {
+    
+}
+
+static void obj_wrapper_init(ObjWrapper *self) {
+    self->data = NULL;
+}
+
+ObjWrapper* obj_wrapper_new(void* data) {
+    ObjWrapper *obj = g_object_new(obj_wrapper_get_type(), NULL);
+    obj->data = data;
+    return obj;
+}
+
+/* END GObject wrapper for generic pointers */
+
+static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
+    UiColData *col = userdata;
+    UiModel *model = col->listview->model;
+    UiModelType type = model->types[col->model_column];
+    if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
+        GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
+        GtkWidget *image = gtk_image_new();
+        GtkWidget *label = gtk_label_new(NULL);
+        BOX_ADD(hbox, image);
+        BOX_ADD(hbox, label);
+        gtk_list_item_set_child(item, hbox);
+        g_object_set_data(G_OBJECT(hbox), "image", image);
+        g_object_set_data(G_OBJECT(hbox), "label", label);
+    } else if(type == UI_ICON) {
+        GtkWidget *image = gtk_image_new();
+        gtk_list_item_set_child(item, image);
+    } else {
+        GtkWidget *label = gtk_label_new(NULL);
+        gtk_label_set_xalign(GTK_LABEL(label), 0);
+        gtk_list_item_set_child(item, label);
+    }
+}
+
+static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
+    UiColData *col = userdata;
+    
+    ObjWrapper *obj = gtk_list_item_get_item(item);
+    UiModel *model = col->listview->model;
+    UiModelType type = model->types[col->model_column];
+    
+    void *data = model->getvalue(obj->data, col->data_column);
+    GtkWidget *child = gtk_list_item_get_child(item);
+    
+    bool freevalue = TRUE;
+    switch(type) {
+        case UI_STRING: {
+            freevalue = FALSE;
+        }
+        case UI_STRING_FREE: {
+            gtk_label_set_label(GTK_LABEL(child), data);
+            if(freevalue) {
+                free(data);
+            }
+            break;
+        }
+        case UI_INTEGER: {
+            intptr_t intvalue = (intptr_t)data;
+            char buf[32];
+            snprintf(buf, 32, "%d", (int)intvalue);
+            gtk_label_set_label(GTK_LABEL(child), buf);
+            break;
+        }
+        case UI_ICON: {
+            UiIcon *icon = data;
+            if(icon) {
+                gtk_image_set_from_paintable(GTK_IMAGE(child), GDK_PAINTABLE(icon->info));
+            }
+            break;
+        }
+        case UI_ICON_TEXT: {
+            freevalue = FALSE;
+        }
+        case UI_ICON_TEXT_FREE: {
+            void *data2 = model->getvalue(obj->data, col->data_column+1);
+            GtkWidget *image = g_object_get_data(G_OBJECT(child), "image");
+            GtkWidget *label = g_object_get_data(G_OBJECT(child), "label");
+            if(data && image) {
+                UiIcon *icon = data;
+                gtk_image_set_from_paintable(GTK_IMAGE(image), GDK_PAINTABLE(icon->info));
+            }
+            if(data2 && label) {
+                gtk_label_set_label(GTK_LABEL(label), data2);
+            }
+            if(freevalue) {
+                free(data2);
+            }
+            break;
+        }
+    }
+}
+
+static GtkSelectionModel* create_selection_model(UiListView *listview, GListStore *liststore, bool multiselection) {
+    GtkSelectionModel *selection_model;
+    if(multiselection) {
+        selection_model = GTK_SELECTION_MODEL(gtk_multi_selection_new(G_LIST_MODEL(liststore)));
+    } else {
+        selection_model = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(liststore)));
+    }
+    g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), listview);
+    return selection_model;
+}
+
+static UiListView* create_listview(UiObject *obj, UiListArgs args) {
+    UiListView *tableview = malloc(sizeof(UiListView));
+    memset(tableview, 0, sizeof(UiListView));
+    tableview->obj = obj;
+    tableview->model = args.model;
+    tableview->onactivate = args.onactivate;
+    tableview->onactivatedata = args.onactivatedata;
+    tableview->onselection = args.onselection;
+    tableview->onselectiondata = args.onselectiondata;
+    tableview->ondragstart = args.ondragstart;
+    tableview->ondragstartdata = args.ondragstartdata;
+    tableview->ondragcomplete = args.ondragcomplete;
+    tableview->ondragcompletedata = args.ondragcompletedata;
+    tableview->ondrop = args.ondrop;
+    tableview->ondropdata = args.ondropsdata;
+    tableview->selection.count = 0;
+    tableview->selection.rows = NULL;
+    return tableview;
+}
+
+UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
+    UiObject* current = uic_current_obj(obj);
+    
+    // to simplify things and share code with ui_tableview_create, we also
+    // use a UiModel for the listview
+    UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
+    model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+    args.model = model;
+    
+    GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
+    UiListView *listview = create_listview(obj, args);
+    
+    listview->columns = malloc(sizeof(UiColData));
+    listview->columns->listview = listview;
+    listview->columns->data_column = 0;
+    listview->columns->model_column = 0;
+    
+    GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
+    g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
+    g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
+    
+    GtkSelectionModel *selection_model = create_selection_model(listview, ls, args.multiselection);
+    GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
+    
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    
+    // init listview
+    listview->widget = view;
+    listview->var = var;
+    listview->liststore = ls;
+    listview->selectionmodel = selection_model;
+    g_signal_connect(
+                view,
+                "destroy",
+                G_CALLBACK(ui_listview_destroy),
+                listview);
+    
+    // bind listview to list
+    if(var && var->value) {
+        UiList *list = var->value;
+        
+        list->obj = listview;
+        list->update = ui_listview_update2;
+        list->getselection = ui_listview_getselection2;
+        list->setselection = ui_listview_setselection2;
+        
+        ui_update_liststore(ls, list);
+    }
+    
+    // event handling
+    if(args.onactivate) {
+        // columnview and listview can use the same callback function, because
+        // the first parameter (which is technically a different pointer type)
+        // is ignored
+        g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
+    }
+    
+    // add widget to parent
+    GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
+    gtk_scrolled_window_set_policy(
+            GTK_SCROLLED_WINDOW(scroll_area),
+            GTK_POLICY_AUTOMATIC,
+            GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
+    SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
+    
+    UI_APPLY_LAYOUT1(current, args);
+    current->container->add(current->container, scroll_area, FALSE);
+    
+    // ct->current should point to view, not scroll_area, to make it possible
+    // to add a context menu
+    current->container->current = view;
+    
+    return scroll_area;
+}
+
+UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
+    UiObject* current = uic_current_obj(obj);
+    
+    // to simplify things and share code with ui_tableview_create, we also
+    // use a UiModel for the listview
+    UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
+    model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+    args.model = model;
+    
+    GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
+    UiListView *listview = create_listview(obj, args);
+    
+    listview->columns = malloc(sizeof(UiColData));
+    listview->columns->listview = listview;
+    listview->columns->data_column = 0;
+    listview->columns->model_column = 0;
+    
+    GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
+    g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
+    g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
+    
+    GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
+    gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
+    
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    
+    // init listview
+    listview->widget = view;
+    listview->var = var;
+    listview->liststore = ls;
+    listview->selectionmodel = NULL;
+    g_signal_connect(
+                view,
+                "destroy",
+                G_CALLBACK(ui_listview_destroy),
+                listview);
+    
+    // bind listview to list
+    if(var && var->value) {
+        UiList *list = var->value;
+        
+        list->obj = listview;
+        list->update = ui_listview_update2;
+        list->getselection = ui_combobox_getselection;
+        list->setselection = ui_combobox_setselection;
+        
+        ui_update_liststore(ls, list);
+    }
+    
+    // event handling
+    if(args.onactivate) {
+        g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
+    }
+    
+    // add widget to parent 
+    UI_APPLY_LAYOUT1(current, args);
+    current->container->add(current->container, view, FALSE);
+    return view;
+}
+
+UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
+    UiObject* current = uic_current_obj(obj);
+    
+    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_listview(obj, args);
+    
+    GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args.multiselection);
+    GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
+    
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    
+    // init tableview
+    tableview->widget = view;
+    tableview->var = var;
+    tableview->liststore = ls;
+    tableview->selectionmodel = selection_model;
+    g_signal_connect(
+                view,
+                "destroy",
+                G_CALLBACK(ui_listview_destroy),
+                tableview);
+    
+    
+    // create columns from UiModel
+    UiModel *model = args.model;
+    int columns = model ? model->columns : 0;
+    
+    tableview->columns = calloc(columns, sizeof(UiColData));
+    
+    int addi = 0;
+    for(int i=0;i<columns;i++) {
+        tableview->columns[i].listview = tableview;
+        tableview->columns[i].model_column = i;
+        tableview->columns[i].data_column = i+addi;
+        
+        if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
+            // icon+text has 2 data columns
+            addi++;
+        }
+        
+        GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
+        UiColData *col = &tableview->columns[i]; 
+        g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
+	g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
+        
+        GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[i], factory);
+        gtk_column_view_column_set_resizable(column, true);
+        gtk_column_view_append_column(GTK_COLUMN_VIEW(view), column);
+    }
+    
+    // bind listview to list
+    if(var && var->value) {
+        UiList *list = var->value;
+        
+        list->obj = tableview;
+        list->update = ui_listview_update2;
+        list->getselection = ui_listview_getselection2;
+        list->setselection = ui_listview_setselection2;
+        
+        ui_update_liststore(ls, list);
+    }
+    
+    // event handling
+    if(args.onactivate) {
+        g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
+    }
+    
+    // add widget to parent
+    GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
+    gtk_scrolled_window_set_policy(
+            GTK_SCROLLED_WINDOW(scroll_area),
+            GTK_POLICY_AUTOMATIC,
+            GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
+    SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
+    
+    UI_APPLY_LAYOUT1(current, args);
+    current->container->add(current->container, scroll_area, FALSE);
+    
+    // ct->current should point to view, not scroll_area, to make it possible
+    // to add a context menu
+    current->container->current = view;
+    
+    return scroll_area;
+}
+
+static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) {
+    UiListSelection sel = { 0, NULL };
+    GtkBitset *bitset = gtk_selection_model_get_selection(model);
+    int n = gtk_bitset_get_size(bitset);
+    printf("bitset %d\n", n);
+    
+    gtk_bitset_unref(bitset);
+    return sel;
+}
+
+static void listview_event(ui_callback cb, void *cbdata, UiListView *view) {
+    UiEvent event;
+    event.obj = view->obj;
+    event.document = event.obj->ctx->document;
+    event.window = event.obj->window;
+    event.intval = view->selection.count;
+    event.eventdata = &view->selection;
+    if(cb) {
+        cb(&event, cbdata);
+    }
+}
+
+void ui_columnview_activate(void *ignore, guint position, gpointer userdata) {
+    UiListView *view = userdata;
+    listview_event(view->onactivate, view->onactivatedata, view);
+}
+
+void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer userdata) {
+    UiListView *view = userdata;
+    free(view->selection.rows);
+    view->selection.count = 0;
+    view->selection.rows = NULL;
+    
+    CX_ARRAY_DECLARE(int, newselection);
+    cx_array_initialize(newselection, 8);
+     
+    size_t nitems = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
+    
+    for(size_t i=0;i<nitems;i++) {
+        if(gtk_selection_model_is_selected(view->selectionmodel, i)) {
+            int s = (int)i;
+            cx_array_simple_add(newselection, s);
+        }
+    }
+    
+    if(newselection_size > 0) {
+        view->selection.count = newselection_size;
+        view->selection.rows = newselection;
+    } else {
+        free(newselection);
+    }
+    
+    listview_event(view->onselection, view->onselectiondata, view);
+}
+
+void ui_dropdown_activate(GtkDropDown* self, gpointer userdata) {
+    UiListView *view = userdata;
+    guint selection = gtk_drop_down_get_selected(GTK_DROP_DOWN(view->widget));
+    UiListSelection sel = { 0, NULL };
+    int sel2 = (int)selection;
+    if(selection != GTK_INVALID_LIST_POSITION) {
+        sel.count = 1;
+        sel.rows = &sel2;
+    }
+    
+    if(view->onactivate) {
+        UiEvent event;
+        event.obj = view->obj;
+        event.document = event.obj->ctx->document;
+        event.window = event.obj->window;
+        event.intval = view->selection.count;
+        event.eventdata = &view->selection;
+        view->onactivate(&event, view->onactivatedata);
+    }
+}
+
+void ui_update_liststore(GListStore *liststore, UiList *list) {
+    g_list_store_remove_all(liststore);
+    void *elm = list->first(list);
+    while(elm) {
+        ObjWrapper *obj = obj_wrapper_new(elm);
+        g_list_store_append(liststore, obj);
+        elm = list->next(list);
+    }
+}
+
+void ui_listview_update2(UiList *list, int i) {
+    UiListView *view = list->obj;
+    ui_update_liststore(view->liststore, view->var->value);
+}
+
+UiListSelection ui_listview_getselection2(UiList *list) {
+    UiListView *view = list->obj;
+    UiListSelection selection;
+    selection.count = view->selection.count;
+    selection.rows = calloc(selection.count, sizeof(int));
+    memcpy(selection.rows, view->selection.rows, selection.count*sizeof(int));
+    return selection;
+}
+
+void ui_listview_setselection2(UiList *list, UiListSelection selection) {
+    UiListView *view = list->obj;
+    UiListSelection newselection;
+    newselection.count = view->selection.count;
+    if(selection.count > 0) {
+        newselection.rows = calloc(newselection.count, sizeof(int));
+        memcpy(newselection.rows, selection.rows, selection.count*sizeof(int));
+    } else {
+        newselection.rows = NULL;
+    }
+    free(view->selection.rows);
+    view->selection = newselection;
+    
+    gtk_selection_model_unselect_all(view->selectionmodel);
+    if(selection.count > 0) {
+        for(int i=0;i<selection.count;i++) {
+            gtk_selection_model_select_item(view->selectionmodel, selection.rows[i], FALSE);
+        }
+    }
+}
+
+UiListSelection ui_combobox_getselection(UiList *list) {
+    UiListView *view = list->obj;
+    guint selection = gtk_drop_down_get_selected(GTK_DROP_DOWN(view->widget));
+    UiListSelection sel = { 0, NULL };
+    if(selection != GTK_INVALID_LIST_POSITION) {
+        sel.count = 1;
+        sel.rows = malloc(sizeof(int));
+        sel.rows[0] = (int)selection;
+    }
+    return sel;
+}
+
+void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+    UiListView *view = list->obj;
+    if(selection.count > 0) {
+        gtk_drop_down_set_selected(GTK_DROP_DOWN(view->widget), selection.rows[0]);
+    } else {
+        gtk_drop_down_set_selected(GTK_DROP_DOWN(view->widget), GTK_INVALID_LIST_POSITION);
+    }
+}
+
+#else
+
 static GtkListStore* create_list_store(UiList *list, UiModel *model) {
     int columns = model->columns;
     GType types[2*columns];
@@ -264,356 +785,6 @@
     return scroll_area;
 }
 
-/*
-static void drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer udata) {
-    printf("drag begin\n");
-    
-}
-
-static void drag_end(
-        GtkWidget *widget,
-        GdkDragContext *context,
-        guint time,
-        gpointer udata)
-{
-    printf("drag end\n");
-    
-}
-*/
-
-/*
-static GtkTargetEntry targetentries[] =
-    {
-      { "STRING",        0, 0 },
-      { "text/plain",    0, 1 },
-      { "text/uri-list", 0, 2 },
-    };
-*/
-
-#if GTK_CHECK_VERSION(4, 10, 0)
-
-
-/* BEGIN GObject wrapper for generic pointers */
-
-typedef struct _ObjWrapper {
-    GObject parent_instance;
-    void *data;
-} ObjWrapper;
-
-typedef struct _ObjWrapperClass {
-    GObjectClass parent_class;
-} ObjWrapperClass;
-
-G_DEFINE_TYPE(ObjWrapper, obj_wrapper, G_TYPE_OBJECT)
-
-static void obj_wrapper_class_init(ObjWrapperClass *klass) {
-    
-}
-
-static void obj_wrapper_init(ObjWrapper *self) {
-    self->data = NULL;
-}
-
-ObjWrapper* obj_wrapper_new(void* data) {
-    ObjWrapper *obj = g_object_new(obj_wrapper_get_type(), NULL);
-    obj->data = data;
-    return obj;
-}
-
-/* END GObject wrapper for generic pointers */
-
-static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
-    UiColData *col = userdata;
-    UiModel *model = col->listview->model;
-    UiModelType type = model->types[col->model_column];
-    if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
-        GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
-        GtkWidget *image = gtk_image_new();
-        GtkWidget *label = gtk_label_new(NULL);
-        BOX_ADD(hbox, image);
-        BOX_ADD(hbox, label);
-        gtk_list_item_set_child(item, hbox);
-        g_object_set_data(G_OBJECT(hbox), "image", image);
-        g_object_set_data(G_OBJECT(hbox), "label", label);
-    } else if(type == UI_ICON) {
-        GtkWidget *image = gtk_image_new();
-        gtk_list_item_set_child(item, image);
-    } else {
-        GtkWidget *label = gtk_label_new(NULL);
-        gtk_label_set_xalign(GTK_LABEL(label), 0);
-        gtk_list_item_set_child(item, label);
-    }
-}
-
-static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
-    UiColData *col = userdata;
-    
-    ObjWrapper *obj = gtk_list_item_get_item(item);
-    UiModel *model = col->listview->model;
-    UiModelType type = model->types[col->model_column];
-    
-    void *data = model->getvalue(obj->data, col->data_column);
-    GtkWidget *child = gtk_list_item_get_child(item);
-    
-    bool freevalue = TRUE;
-    switch(type) {
-        case UI_STRING: {
-            freevalue = FALSE;
-        }
-        case UI_STRING_FREE: {
-            gtk_label_set_label(GTK_LABEL(child), data);
-            if(freevalue) {
-                free(data);
-            }
-            break;
-        }
-        case UI_INTEGER: {
-            intptr_t intvalue = (intptr_t)data;
-            char buf[32];
-            snprintf(buf, 32, "%d", (int)intvalue);
-            gtk_label_set_label(GTK_LABEL(child), buf);
-            break;
-        }
-        case UI_ICON: {
-            UiIcon *icon = data;
-            if(icon) {
-                gtk_image_set_from_paintable(GTK_IMAGE(child), GDK_PAINTABLE(icon->info));
-            }
-            break;
-        }
-        case UI_ICON_TEXT: {
-            freevalue = FALSE;
-        }
-        case UI_ICON_TEXT_FREE: {
-            void *data2 = model->getvalue(obj->data, col->data_column+1);
-            GtkWidget *image = g_object_get_data(G_OBJECT(child), "image");
-            GtkWidget *label = g_object_get_data(G_OBJECT(child), "label");
-            if(data && image) {
-                UiIcon *icon = data;
-                gtk_image_set_from_paintable(GTK_IMAGE(image), GDK_PAINTABLE(icon->info));
-            }
-            if(data2 && label) {
-                gtk_label_set_label(GTK_LABEL(label), data2);
-            }
-            if(freevalue) {
-                free(data2);
-            }
-            break;
-        }
-    }
-}
-
-UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
-    UiObject* current = uic_current_obj(obj);
-    
-    GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
-    //g_list_store_append(ls, v1);
-    
-    GtkSelectionModel *selection_model;
-    if(args.multiselection) {
-        selection_model = GTK_SELECTION_MODEL(gtk_multi_selection_new(G_LIST_MODEL(ls)));
-    } else {
-        selection_model = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(ls)));
-    }
-    
-    GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
-    
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
-    
-    // create obj to store all relevant data we need for handling events
-    // and list updates
-    UiListView *tableview = malloc(sizeof(UiListView));
-    tableview->obj = obj;
-    tableview->widget = view;
-    tableview->var = var;
-    tableview->model = args.model;
-    tableview->liststore = ls;
-    tableview->selectionmodel = selection_model;
-    tableview->onactivate = args.onactivate;
-    tableview->onactivatedata = args.onactivatedata;
-    tableview->onselection = args.onselection;
-    tableview->onselectiondata = args.onselectiondata;
-    tableview->ondragstart = args.ondragstart;
-    tableview->ondragstartdata = args.ondragstartdata;
-    tableview->ondragcomplete = args.ondragcomplete;
-    tableview->ondragcompletedata = args.ondragcompletedata;
-    tableview->ondrop = args.ondrop;
-    tableview->ondropdata = args.ondropsdata;
-    tableview->selection.count = 0;
-    tableview->selection.rows = NULL;
-    g_signal_connect(
-                view,
-                "destroy",
-                G_CALLBACK(ui_listview_destroy),
-                tableview);
-    
-    
-    // create columns from UiModel
-    UiModel *model = args.model;
-    int columns = model ? model->columns : 0;
-    
-    tableview->columns = calloc(columns, sizeof(UiColData));
-    
-    int addi = 0;
-    for(int i=0;i<columns;i++) {
-        tableview->columns[i].listview = tableview;
-        tableview->columns[i].model_column = i;
-        tableview->columns[i].data_column = i+addi;
-        
-        if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
-            // icon+text has 2 data columns
-            addi++;
-        }
-        
-        GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
-        UiColData *col = &tableview->columns[i]; 
-        g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
-	g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
-        
-        GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[i], factory);
-        gtk_column_view_column_set_resizable(column, true);
-        gtk_column_view_append_column(GTK_COLUMN_VIEW(view), column);
-    }
-    
-    // bind listview to list
-    if(var && var->value) {
-        UiList *list = var->value;
-        
-        list->obj = tableview;
-        list->update = ui_listview_update2;
-        list->getselection = ui_listview_getselection2;
-        list->setselection = ui_listview_setselection2;
-        
-        ui_update_liststore(ls, list);
-    }
-    
-    // event handling
-    if(args.onactivate) {
-        g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
-    }
-    // always handle selection-changed, to keep track of the current selection
-    g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), tableview);
-    
-    // add widget to parent
-    GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
-    gtk_scrolled_window_set_policy(
-            GTK_SCROLLED_WINDOW(scroll_area),
-            GTK_POLICY_AUTOMATIC,
-            GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
-    SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
-    
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, scroll_area, FALSE);
-    
-    // ct->current should point to view, not scroll_area, to make it possible
-    // to add a context menu
-    current->container->current = view;
-    
-    return scroll_area;
-}
-
-static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) {
-    UiListSelection sel = { 0, NULL };
-    GtkBitset *bitset = gtk_selection_model_get_selection(model);
-    int n = gtk_bitset_get_size(bitset);
-    printf("bitset %d\n", n);
-    
-    gtk_bitset_unref(bitset);
-    return sel;
-}
-
-static void listview_event(ui_callback cb, void *cbdata, UiListView *view) {
-    UiEvent event;
-    event.obj = view->obj;
-    event.document = event.obj->ctx->document;
-    event.window = event.obj->window;
-    event.intval = view->selection.count;
-    event.eventdata = &view->selection;
-    if(cb) {
-        cb(&event, cbdata);
-    }
-}
-
-void ui_columnview_activate(GtkColumnView* self, guint position, gpointer userdata) {
-    UiListView *view = userdata;
-    listview_event(view->onactivate, view->onactivatedata, view);
-}
-
-void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer userdata) {
-    UiListView *view = userdata;
-    free(view->selection.rows);
-    view->selection.count = 0;
-    view->selection.rows = NULL;
-    
-    CX_ARRAY_DECLARE(int, newselection);
-    cx_array_initialize(newselection, 8);
-     
-    size_t nitems = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
-    
-    for(size_t i=0;i<nitems;i++) {
-        if(gtk_selection_model_is_selected(view->selectionmodel, i)) {
-            int s = (int)i;
-            cx_array_simple_add(newselection, s);
-        }
-    }
-    
-    if(newselection_size > 0) {
-        view->selection.count = newselection_size;
-        view->selection.rows = newselection;
-    } else {
-        free(newselection);
-    }
-    
-    listview_event(view->onselection, view->onselectiondata, view);
-}
-
-void ui_update_liststore(GListStore *liststore, UiList *list) {
-    g_list_store_remove_all(liststore);
-    void *elm = list->first(list);
-    while(elm) {
-        ObjWrapper *obj = obj_wrapper_new(elm);
-        g_list_store_append(liststore, obj);
-        elm = list->next(list);
-    }
-}
-
-void ui_listview_update2(UiList *list, int i) {
-    UiListView *view = list->obj;
-    ui_update_liststore(view->liststore, view->var->value);
-}
-
-UiListSelection ui_listview_getselection2(UiList *list) {
-    UiListView *view = list->obj;
-    UiListSelection selection;
-    selection.count = view->selection.count;
-    selection.rows = calloc(selection.count, sizeof(int));
-    memcpy(selection.rows, view->selection.rows, selection.count*sizeof(int));
-    return selection;
-}
-
-void ui_listview_setselection2(UiList *list, UiListSelection selection) {
-    UiListView *view = list->obj;
-    UiListSelection newselection;
-    newselection.count = view->selection.count;
-    if(selection.count > 0) {
-        newselection.rows = calloc(newselection.count, sizeof(int));
-        memcpy(newselection.rows, selection.rows, selection.count*sizeof(int));
-    } else {
-        newselection.rows = NULL;
-    }
-    free(view->selection.rows);
-    view->selection = newselection;
-    
-    gtk_selection_model_unselect_all(view->selectionmodel);
-    if(selection.count > 0) {
-        for(int i=0;i<selection.count;i++) {
-            gtk_selection_model_select_item(view->selectionmodel, selection.rows[i], FALSE);
-        }
-    }
-}
-
-#else
-
 UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     UiObject* current = uic_current_obj(obj);
     
@@ -780,6 +951,221 @@
 }
 
 
+
+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));
+}
+
+UiListSelection ui_listview_getselection(UiList *list) {
+    UiListView *view = list->obj;
+    UiListSelection selection = ui_listview_selection(
+            gtk_tree_view_get_selection(GTK_TREE_VIEW(view->widget)),
+            NULL);
+    return selection;
+}
+
+void ui_listview_setselection(UiList *list, UiListSelection selection) {
+    UiListView *view = list->obj;
+    GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view->widget));
+    GtkTreePath *path = gtk_tree_path_new_from_indicesv(selection.rows, selection.count);
+    gtk_tree_selection_select_path(sel, path);
+    //g_object_unref(path);
+}
+
+
+
+/* --------------------------- ComboBox ---------------------------  */
+
+UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
+    UiObject* current = uic_current_obj(obj);
+    
+    UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
+    model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+    
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    
+    GtkWidget *combobox = ui_create_combobox(obj, model, var, args.onactivate, args.onactivatedata);
+    ui_set_name_and_style(combobox, args.name, args.style_class);
+    ui_set_widget_groups(obj->ctx, combobox, args.groups);
+    UI_APPLY_LAYOUT1(current, args);
+    current->container->add(current->container, combobox, FALSE);
+    current->container->current = combobox;
+    return combobox;
+}
+
+GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, ui_callback f, void *udata) {
+    GtkWidget *combobox = gtk_combo_box_new();
+       
+    UiListView *uicbox = malloc(sizeof(UiListView));
+    uicbox->obj = obj;
+    uicbox->widget = combobox;
+    
+    UiList *list = var ? var->value : NULL;
+    GtkListStore *listmodel = create_list_store(list, model);
+    
+    if(listmodel) {
+        gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(listmodel));
+        g_object_unref(listmodel);
+    }
+    
+    uicbox->var = var;
+    uicbox->model = model;
+    
+    g_signal_connect(
+                combobox,
+                "destroy",
+                G_CALLBACK(ui_combobox_destroy),
+                uicbox);
+    
+    // bind var
+    if(list) {
+        list->update = ui_combobox_modelupdate;
+        list->getselection = ui_combobox_getselection;
+        list->setselection = ui_combobox_setselection;
+        list->obj = uicbox;
+    }
+    
+    GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
+    gtk_cell_layout_set_attributes(
+            GTK_CELL_LAYOUT(combobox),
+            renderer,
+            "text",
+            0,
+            NULL);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
+    
+    // add callback
+    if(f) {
+        UiEventData *event = ui_malloc(obj->ctx, sizeof(UiEventData));
+        event->obj = obj;
+        event->userdata = udata;
+        event->callback = f;
+        event->value = 0;
+        event->customdata = NULL;
+
+        g_signal_connect(
+                combobox,
+                "changed",
+                G_CALLBACK(ui_combobox_change_event),
+                event);
+    }
+    
+    return combobox;
+}
+
+void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e) {
+    UiEvent event;
+    event.obj = e->obj;
+    event.window = event.obj->window;
+    event.document = event.obj->ctx->document;
+    event.eventdata = NULL;
+    event.intval = gtk_combo_box_get_active(widget);
+    e->callback(&event, e->userdata);
+}
+
+void ui_combobox_modelupdate(UiList *list, int i) {
+    UiListView *view = list->obj;
+    GtkListStore *store = create_list_store(view->var->value, view->model);
+    gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store));
+    g_object_unref(store);
+}
+
+UiListSelection ui_combobox_getselection(UiList *list) {
+    UiListView *combobox = list->obj;
+    UiListSelection ret;
+    ret.rows = malloc(sizeof(int*));
+    ret.count = 1;
+    ret.rows[0] = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox->widget));
+    return ret;
+}
+
+void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+    UiListView *combobox = list->obj;
+    if(selection.count > 0) {
+        gtk_combo_box_set_active(GTK_COMBO_BOX(combobox->widget), selection.rows[0]);
+    }
+}
+
+
+
+
+void ui_listview_activate_event(
+        GtkTreeView *treeview,
+        GtkTreePath *path,
+        GtkTreeViewColumn *column,
+        UiTreeEventData *event)
+{
+    UiListSelection selection = ui_listview_selection(
+            gtk_tree_view_get_selection(treeview),
+            event);
+    
+    UiEvent e;
+    e.obj = event->obj;
+    e.window = event->obj->window;
+    e.document = event->obj->ctx->document;
+    e.eventdata = &selection;
+    e.intval = selection.count > 0 ? selection.rows[0] : -1;
+    event->activate(&e, event->activatedata);
+    
+    if(selection.count > 0) {
+        free(selection.rows);
+    }
+}
+
+void ui_listview_selection_event(
+        GtkTreeSelection *treeselection,
+        UiTreeEventData *event)
+{
+    UiListSelection selection = ui_listview_selection(treeselection, event);
+    
+    UiEvent e;
+    e.obj = event->obj;
+    e.window = event->obj->window;
+    e.document = event->obj->ctx->document;
+    e.eventdata = &selection;
+    e.intval = selection.count > 0 ? selection.rows[0] : -1;
+    event->selection(&e, event->selectiondata);
+    
+    if(selection.count > 0) {
+        free(selection.rows);
+    }
+}
+
+UiListSelection ui_listview_selection(
+        GtkTreeSelection *selection,
+        UiTreeEventData *event)
+{
+    GList *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
+    
+    UiListSelection ls;
+    ls.count = g_list_length(rows);
+    ls.rows = calloc(ls.count, sizeof(int));
+    GList *r = rows;
+    int i = 0;
+    while(r) {
+        GtkTreePath *path = r->data;
+        ls.rows[i] = ui_tree_path_list_index(path);
+        r = r->next;
+        i++;
+    }
+    return ls;
+}
+
+int ui_tree_path_list_index(GtkTreePath *path) {
+    int depth = gtk_tree_path_get_depth(path);
+    if(depth == 0) {
+        fprintf(stderr, "UiError: treeview selection: depth == 0\n");
+        return -1;
+    }
+    int *indices = gtk_tree_path_get_indices(path);
+    return indices[depth - 1];
+}
+
+
 #endif
 
 
@@ -1092,29 +1478,6 @@
     free(t);
 }
 */
- 
-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));
-}
-
-UiListSelection ui_listview_getselection(UiList *list) {
-    UiListView *view = list->obj;
-    UiListSelection selection = ui_listview_selection(
-            gtk_tree_view_get_selection(GTK_TREE_VIEW(view->widget)),
-            NULL);
-    return selection;
-}
-
-void ui_listview_setselection(UiList *list, UiListSelection selection) {
-    UiListView *view = list->obj;
-    GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view->widget));
-    GtkTreePath *path = gtk_tree_path_new_from_indicesv(selection.rows, selection.count);
-    gtk_tree_selection_select_path(sel, path);
-    //g_object_unref(path);
-}
 
 void ui_listview_destroy(GtkWidget *w, UiListView *v) {
     //gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL);
@@ -1132,193 +1495,6 @@
 }
 
 
-void ui_listview_activate_event(
-        GtkTreeView *treeview,
-        GtkTreePath *path,
-        GtkTreeViewColumn *column,
-        UiTreeEventData *event)
-{
-    UiListSelection selection = ui_listview_selection(
-            gtk_tree_view_get_selection(treeview),
-            event);
-    
-    UiEvent e;
-    e.obj = event->obj;
-    e.window = event->obj->window;
-    e.document = event->obj->ctx->document;
-    e.eventdata = &selection;
-    e.intval = selection.count > 0 ? selection.rows[0] : -1;
-    event->activate(&e, event->activatedata);
-    
-    if(selection.count > 0) {
-        free(selection.rows);
-    }
-}
-
-void ui_listview_selection_event(
-        GtkTreeSelection *treeselection,
-        UiTreeEventData *event)
-{
-    UiListSelection selection = ui_listview_selection(treeselection, event);
-    
-    UiEvent e;
-    e.obj = event->obj;
-    e.window = event->obj->window;
-    e.document = event->obj->ctx->document;
-    e.eventdata = &selection;
-    e.intval = selection.count > 0 ? selection.rows[0] : -1;
-    event->selection(&e, event->selectiondata);
-    
-    if(selection.count > 0) {
-        free(selection.rows);
-    }
-}
-
-UiListSelection ui_listview_selection(
-        GtkTreeSelection *selection,
-        UiTreeEventData *event)
-{
-    GList *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
-    
-    UiListSelection ls;
-    ls.count = g_list_length(rows);
-    ls.rows = calloc(ls.count, sizeof(int));
-    GList *r = rows;
-    int i = 0;
-    while(r) {
-        GtkTreePath *path = r->data;
-        ls.rows[i] = ui_tree_path_list_index(path);
-        r = r->next;
-        i++;
-    }
-    return ls;
-}
-
-int ui_tree_path_list_index(GtkTreePath *path) {
-    int depth = gtk_tree_path_get_depth(path);
-    if(depth == 0) {
-        fprintf(stderr, "UiError: treeview selection: depth == 0\n");
-        return -1;
-    }
-    int *indices = gtk_tree_path_get_indices(path);
-    return indices[depth - 1];
-}
-
-
-/* --------------------------- ComboBox ---------------------------  */
-
-UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) {
-    UiObject* current = uic_current_obj(obj);
-    
-    UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
-    
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
-    
-    GtkWidget *combobox = ui_create_combobox(obj, model, var, args.onactivate, args.onactivatedata);
-    ui_set_name_and_style(combobox, args.name, args.style_class);
-    ui_set_widget_groups(obj->ctx, combobox, args.groups);
-    UI_APPLY_LAYOUT1(current, args);
-    current->container->add(current->container, combobox, FALSE);
-    current->container->current = combobox;
-    return combobox;
-}
-
-GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, ui_callback f, void *udata) {
-    GtkWidget *combobox = gtk_combo_box_new();
-       
-    UiListView *uicbox = malloc(sizeof(UiListView));
-    uicbox->obj = obj;
-    uicbox->widget = combobox;
-    
-    UiList *list = var ? var->value : NULL;
-    GtkListStore *listmodel = create_list_store(list, model);
-    
-    if(listmodel) {
-        gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(listmodel));
-        g_object_unref(listmodel);
-    }
-    
-    uicbox->var = var;
-    uicbox->model = model;
-    
-    g_signal_connect(
-                combobox,
-                "destroy",
-                G_CALLBACK(ui_combobox_destroy),
-                uicbox);
-    
-    // bind var
-    if(list) {
-        list->update = ui_combobox_modelupdate;
-        list->getselection = ui_combobox_getselection;
-        list->setselection = ui_combobox_setselection;
-        list->obj = uicbox;
-    }
-    
-    GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
-    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
-    gtk_cell_layout_set_attributes(
-            GTK_CELL_LAYOUT(combobox),
-            renderer,
-            "text",
-            0,
-            NULL);
-    gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
-    
-    // add callback
-    if(f) {
-        UiEventData *event = ui_malloc(obj->ctx, sizeof(UiEventData));
-        event->obj = obj;
-        event->userdata = udata;
-        event->callback = f;
-        event->value = 0;
-        event->customdata = NULL;
-
-        g_signal_connect(
-                combobox,
-                "changed",
-                G_CALLBACK(ui_combobox_change_event),
-                event);
-    }
-    
-    return combobox;
-}
-
-void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e) {
-    UiEvent event;
-    event.obj = e->obj;
-    event.window = event.obj->window;
-    event.document = event.obj->ctx->document;
-    event.eventdata = NULL;
-    event.intval = gtk_combo_box_get_active(widget);
-    e->callback(&event, e->userdata);
-}
-
-void ui_combobox_modelupdate(UiList *list, int i) {
-    UiListView *view = list->obj;
-    GtkListStore *store = create_list_store(view->var->value, view->model);
-    gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store));
-    g_object_unref(store);
-}
-
-UiListSelection ui_combobox_getselection(UiList *list) {
-    UiListView *combobox = list->obj;
-    UiListSelection ret;
-    ret.rows = malloc(sizeof(int*));
-    ret.count = 1;
-    ret.rows[0] = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox->widget));
-    return ret;
-}
-
-void ui_combobox_setselection(UiList *list, UiListSelection selection) {
-    UiListView *combobox = list->obj;
-    if(selection.count > 0) {
-        gtk_combo_box_set_active(GTK_COMBO_BOX(combobox->widget), selection.rows[0]);
-    }
-}
-
-
 /* ------------------------------ Source List ------------------------------ */
 
 static void ui_destroy_sourcelist(GtkWidget *w, UiListBox *v) {
--- a/ui/gtk/list.h	Sun Jan 05 16:56:05 2025 +0100
+++ b/ui/gtk/list.h	Sun Jan 05 17:31:53 2025 +0100
@@ -113,9 +113,11 @@
 UiListSelection ui_listview_getselection2(UiList *list);
 void ui_listview_setselection2(UiList *list, UiListSelection selection);
 
-void ui_columnview_activate(GtkColumnView* self, guint position, gpointer userdata);
+void ui_columnview_activate(void *ignore, guint position, gpointer userdata);
 void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer user_data);
 
+void ui_dropdown_activate(GtkDropDown* self, gpointer userdata);
+
 #endif
 
 void* ui_strmodel_getvalue(void *elm, int column);
@@ -132,6 +134,9 @@
 void ui_combobox_destroy(GtkWidget *w, UiListView *v);
 void ui_listview_destroy(GtkWidget *w, UiListView *v);
 
+#if GTK_CHECK_VERSION(4, 10, 0)
+
+#else
 void ui_listview_activate_event(
         GtkTreeView *tree_view,
         GtkTreePath *path,
@@ -144,6 +149,7 @@
         GtkTreeSelection *selection,
         UiTreeEventData *event);
 int ui_tree_path_list_index(GtkTreePath *path);
+#endif
 
 void ui_listview_add_dnd(UiListView *listview, UiListArgs *args);
 void ui_listview_enable_drop(UiListView *listview, UiListArgs *args);

mercurial