--- 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)); }