ui/gtk/tree.c

changeset 32
e5f4d8af567e
parent 29
3fc287f06305
child 41
7ada3db4cfa8
--- a/ui/gtk/tree.c	Mon Feb 12 21:13:23 2024 +0100
+++ b/ui/gtk/tree.c	Sun Jun 09 15:43:08 2024 +0200
@@ -36,16 +36,117 @@
 #include "container.h"
 
 #include "tree.h"
+#include "image.h"
 
 
 void* ui_strmodel_getvalue(void *elm, int column) {
     return column == 0 ? elm : NULL;
 }
 
+static GtkListStore* create_list_store(UiList *list, UiModel *model) {
+    int columns = model->columns;
+    GType types[2*columns];
+    int c = 0;
+    for(int i=0;i<columns;i++,c++) {
+        switch(model->types[i]) {
+            case UI_STRING: 
+            case UI_STRING_FREE: types[c] = G_TYPE_STRING; break;
+            case UI_INTEGER: types[c] = G_TYPE_INT; break;
+            case UI_ICON: types[c] = G_TYPE_OBJECT; break;
+            case UI_ICON_TEXT: 
+            case UI_ICON_TEXT_FREE: {
+                types[c] = G_TYPE_OBJECT;
+                types[++c] = G_TYPE_STRING;
+            }
+        }
+    }
+    
+    GtkListStore *store = gtk_list_store_newv(c, types);
+    
+    if(list) {
+        void *elm = list->first(list);
+	while(elm) {
+            // insert new row
+            GtkTreeIter iter;
+            gtk_list_store_insert (store, &iter, -1);
+            
+            // set column values
+            int c = 0;
+            for(int i=0;i<columns;i++,c++) {
+                void *data = model->getvalue(elm, c);
+                
+                GValue value = G_VALUE_INIT;
+                switch(model->types[i]) {
+                    case UI_STRING: 
+                    case UI_STRING_FREE: {
+                        g_value_init(&value, G_TYPE_STRING);
+                        g_value_set_string(&value, data);
+                        if(model->types[i] == UI_STRING_FREE) {
+                            free(data);
+                        }
+                        break;
+                    }
+                    case UI_INTEGER: {
+                        g_value_init(&value, G_TYPE_INT);
+                        int *intptr = data;
+                        g_value_set_int(&value, *intptr);
+                        break;
+                    }
+                    case UI_ICON: {
+                        g_value_init(&value, G_TYPE_OBJECT);
+                        UiIcon *icon = data;
+                        if(!icon->pixbuf && icon->info) {
+                            GError *error = NULL;
+                            GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error);
+                            icon->pixbuf = pixbuf;
+                        }
+                        
+                        if(icon->pixbuf) {
+                            g_value_set_object(&value, icon->pixbuf);
+                        }
+
+                        
+                        break;
+                    }
+                    case UI_ICON_TEXT:
+                    case UI_ICON_TEXT_FREE: {
+                        GValue pixbufvalue = G_VALUE_INIT;
+                        UiIcon *icon = data;
+                        if(!icon->pixbuf && icon->info) {
+                            GError *error = NULL;
+                            GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error);
+                            icon->pixbuf = pixbuf;
+                        }
+                        g_value_init(&pixbufvalue, G_TYPE_OBJECT);
+                        g_value_set_object(&pixbufvalue, icon->pixbuf);
+                        gtk_list_store_set_value(store, &iter, c, &pixbufvalue);
+                        c++;
+                        
+                        char *str = model->getvalue(elm, c);
+                        g_value_init(&value, G_TYPE_STRING);
+                        g_value_set_string(&value, str);
+                        if(model->types[i] == UI_ICON_TEXT_FREE) {
+                            free(str);
+                        }
+                        break;
+                    }
+                }
+                
+                gtk_list_store_set_value(store, &iter, c, &value);
+            }
+            
+            // next row
+            elm = list->next(list);
+        }
+    }
+    
+    return store;
+}
 
 
-
-UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
+UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
+    UiObject* current = uic_current_obj(obj);
+    
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
@@ -64,9 +165,12 @@
 #endif
     
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
-    model->getvalue = getvalue;
-    UiList *list = var->value;
-    UiListModel *listmodel = ui_list_model_new(obj, var, model);
+    model->getvalue = args.getvalue;
+    
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    
+    UiList *list = var ? var->value : NULL;
+    GtkListStore *listmodel = create_list_store(list, model);
     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
     
     UiListView *listview = malloc(sizeof(UiListView));
@@ -85,11 +189,11 @@
     list->obj = listview;
     
     // add callback
-    if(f) {
+    if(args.onactivate) {
         UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
         event->obj = obj;
-        event->userdata = udata;
-        event->activate = f;
+        event->activatedata = args.onactivatedata;
+        event->activate = args.onactivate;
         event->selection = NULL;
 
         g_signal_connect(
@@ -107,33 +211,16 @@
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     gtk_container_add(GTK_CONTAINER(scroll_area), view);
     
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, scroll_area, TRUE);
+    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
-    ct->current = view;
+    current->container->current = view;
     
     return scroll_area;
 }
 
-UIWIDGET ui_listview_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
-    UiVar *var = malloc(sizeof(UiVar));
-    var->value = list;
-    var->type = UI_VAR_SPECIAL;
-    return ui_listview_var(obj, var, getvalue, f, udata);
-}
-
-UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
-    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
-    if(var) {
-        return ui_listview_var(obj, var, getvalue, f, udata);
-    } else {
-        // TODO: error
-    }
-    return NULL;
-}
-
 static void drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer udata) {
     printf("drag begin\n");
     
@@ -156,12 +243,17 @@
       { "text/uri-list", 0, 2 },
     };
 
-UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) {
+UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
+    UiObject* current = uic_current_obj(obj);
+    
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
     
+    UiModel *model = args.model;
+    int columns = model ? model->columns : 0;
+    
     int addi = 0;
-    for(int i=0;i<model->columns;i++) {
+    for(int i=0;i<columns;i++) {
         GtkTreeViewColumn *column = NULL;
         if(model->types[i] == UI_ICON_TEXT) {
             column = gtk_tree_view_column_new();
@@ -178,6 +270,14 @@
             gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1);
             
             addi++;
+        } else if (model->types[i] == UI_ICON) {
+            GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new();
+            column = gtk_tree_view_column_new_with_attributes(
+                model->titles[i],
+                iconrenderer,
+                "pixbuf",
+                i + addi,
+                NULL);
         } else {
             GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
             column = gtk_tree_view_column_new_with_attributes(
@@ -198,8 +298,10 @@
     
 #endif
     
-    UiList *list = var->value;
-    UiListModel *listmodel = ui_list_model_new(obj, var, model);
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
+    
+    UiList *list = var ? var->value : NULL;
+    GtkListStore *listmodel = create_list_store(list, model);
     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
     
     //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL);
@@ -225,17 +327,18 @@
     // add callback
     UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
     event->obj = obj;
-    event->activate = cb.activate;
-    event->selection = cb.selection;
-    event->userdata = cb.userdata;
-    if(cb.activate) {
+    event->activate = args.onactivate;
+    event->selection = args.onselection;
+    event->activatedata = args.onactivatedata;
+    event->selectiondata = args.onselectiondata;
+    if(args.onactivate) {
         g_signal_connect(
                 view,
                 "row-activated",
                 G_CALLBACK(ui_listview_activate_event),
                 event);
     }
-    if(cb.selection) {
+    if(args.onselection) {
         GtkTreeSelection *selection = gtk_tree_view_get_selection(
                 GTK_TREE_VIEW(view));
         g_signal_connect(
@@ -258,32 +361,16 @@
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     gtk_container_add(GTK_CONTAINER(scroll_area), view);
     
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, scroll_area, TRUE);
+    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
-    ct->current = view;
+    current->container->current = view;
     
     return scroll_area;
 }
 
-UIWIDGET ui_table_deprecated(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) {
-    UiVar *var = malloc(sizeof(UiVar));
-    var->value = list;
-    var->type = UI_VAR_SPECIAL;
-    return ui_table_var(obj, var, model, cb);
-}
-
-UIWIDGET ui_table_nv(UiObject *obj, char *varname, UiModel *model, UiListCallbacks cb) {
-    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
-    if(var) {
-        return ui_table_var(obj, var, model, cb);
-    } else {
-        // TODO: error
-    }
-    return NULL;
-}
 
 GtkWidget* ui_get_tree_widget(UIWIDGET widget) {
     GList *c = gtk_container_get_children(GTK_CONTAINER(widget));
@@ -370,9 +457,9 @@
  
 void ui_listview_update(UiList *list, int i) {
     UiListView *view = list->obj;
-    UiListModel *model = ui_list_model_new(view->obj, view->var, view->model);
-    gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model));
-    g_object_unref(G_OBJECT(model));
+    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));
     // TODO: free old model
 }
 
@@ -407,7 +494,7 @@
     e.document = event->obj->ctx->document;
     e.eventdata = selection;
     e.intval = selection->count > 0 ? selection->rows[0] : -1;
-    event->activate(&e, event->userdata);
+    event->activate(&e, event->activatedata);
     
     if(selection->count > 0) {
         free(selection->rows);
@@ -427,7 +514,7 @@
     e.document = event->obj->ctx->document;
     e.eventdata = selection;
     e.intval = selection->count > 0 ? selection->rows[0] : -1;
-    event->selection(&e, event->userdata);
+    event->selection(&e, event->selectiondata);
     
     if(selection->count > 0) {
         free(selection->rows);
@@ -468,42 +555,37 @@
 
 /* --------------------------- ComboBox ---------------------------  */
 
-UIWIDGET ui_combobox_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
-    UiVar *var = malloc(sizeof(UiVar));
-    var->value = list;
-    var->type = UI_VAR_SPECIAL;
-    return ui_combobox_var(obj, var, getvalue, f, udata);
-}
-
-UIWIDGET ui_combobox_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
-    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
-    if(var) {
-        return ui_combobox_var(obj, var, getvalue, f, udata);
-    } else {
-        // TODO: error
-    }
-    return NULL;
-}
-
-UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
+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 = getvalue;
-    UiListModel *listmodel = ui_list_model_new(obj, var, model);
+    model->getvalue = args.getvalue;
+    
+    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
     
-    GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata);
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, combobox, FALSE);
+    GtkWidget *combobox = ui_create_combobox(obj, model, var, args.onactivate, args.onactivatedata);
+    UI_APPLY_LAYOUT1(current, args);
+    current->container->add(current->container, combobox, FALSE);
+    current->container->current = combobox;
     return combobox;
 }
 
-GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata) {
-    GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
-    
+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;
-    uicbox->var = model->var;
-    uicbox->model = model->model;
+    
+    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));
+    }
+    
+    uicbox->var = var;
+    uicbox->model = model;
     
     g_signal_connect(
                 combobox,
@@ -512,9 +594,10 @@
                 uicbox);
     
     // bind var
-    UiList *list = model->var->value;
-    list->update = ui_combobox_modelupdate;
-    list->obj = uicbox;
+    if(list) {
+        list->update = ui_combobox_modelupdate;
+        list->obj = uicbox;
+    }
     
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
     gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
@@ -533,6 +616,7 @@
         event->userdata = udata;
         event->callback = f;
         event->value = 0;
+        event->customdata = NULL;
 
         g_signal_connect(
                 combobox,
@@ -556,7 +640,7 @@
 
 void ui_combobox_modelupdate(UiList *list, int i) {
     UiListView *view = list->obj;
-    UiListModel *model = ui_list_model_new(view->obj, view->var, view->model);
-    gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(model));
+    GtkListStore *store = create_list_store(view->var->value, view->model);
+    gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store));
 }
 

mercurial