Thu, 16 Nov 2017 12:04:10 +0100
new icon/image api and pixbuf support in treeview (GTK)
--- a/application/main.c Sun Nov 12 12:03:50 2017 +0100 +++ b/application/main.c Thu Nov 16 12:04:10 2017 +0100 @@ -41,13 +41,21 @@ UiInteger *i; UiDouble *d; UiRange *r; + UiList *list; } Document; +typedef struct Entry { + char *name; + char *desc; +} Entry; + Document *d1; Document *d2; int n = 1; -Document* create_doc(); +UiImage *img; + +Document* create_doc(char *str); Document* next_doc(void) { Document *doc = d1; @@ -74,7 +82,7 @@ fflush(stdout); } -Document* create_doc() { +Document* create_doc(char *str) { Document *doc = ui_document_new(sizeof(Document)); UiContext *ctx = ui_document_context(doc); @@ -86,9 +94,32 @@ doc->i = ui_int_new(ctx, "int"); doc->d = ui_double_new(ctx, "d"); doc->r = ui_range_new(ctx, "r"); + + doc->list = ui_list_new(ctx, "list"); + printf("doc list: %d\n", doc->list); + Entry *e1 = malloc(sizeof(Entry)); + e1->name = "test"; + e1->desc = "test file"; + Entry *e2 = malloc(sizeof(Entry)); + e2->name = str; + e2->desc = "important document"; + ui_list_append(doc->list, e1); + ui_list_append(doc->list, e2); + return doc; } +void* model_get(Entry *e, int col) { + if(col == 0) { + return img; + } else if(col == 1) { + return e->name; + } else if(col == 2) { + return e->desc; + } + return NULL; +} + void action_newdoc(UiEvent *event, void *data) { printf("new doc\n"); @@ -107,9 +138,15 @@ } void application_startup(UiEvent *event, void *data) { + UiIcon *icon = ui_icon("folder", 16); + img = ui_icon_image(icon); + if(!img) { + fprintf(stderr, "Cannot load folder icon\n"); + } + //Document *doc = create_doc(); - d1 = create_doc(); - d2 = create_doc(); + d1 = create_doc("doc1"); + d2 = create_doc("doc2"); UiObject *obj = ui_window("Test", NULL); ui_set_document(obj, d1); @@ -120,9 +157,14 @@ ui_radiobutton_nv(obj, "3", "int"); ui_textfield_nv(obj, "t1"); - ui_textarea_nv(obj, "text"); + //ui_textarea_nv(obj, "text"); d1->t1->observers = ui_add_observer(d1->t1->observers, observ, "t1"); - d1->text->observers = ui_add_observer(d1->text->observers, observ, "text"); + //d1->text->observers = ui_add_observer(d1->text->observers, observ, "text"); + + UiModel *model = ui_model(obj->ctx, UI_ICON_TEXT, "name", UI_STRING, "desc", -1); + model->getvalue = (ui_getvaluefunc)model_get; + UiListCallbacks cb = {NULL, NULL, NULL}; + ui_table_nv(obj, "list", model, cb); //ui_spinner_setrange(ui_spinnerf_nv(obj, 1, 0, "d"), 0, 1000); ui_spinnerr_nv(obj, "r");
--- a/ui/common/context.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/common/context.c Thu Nov 16 12:04:10 2017 +0100 @@ -218,7 +218,7 @@ break; } case UI_VAR_LIST: { - val = NULL; // TODO + val = ui_list_new(ctx, NULL); break; } case UI_VAR_RANGE: { @@ -241,13 +241,22 @@ return; } + void *fromvalue = from->value; + // update var + if(copytodoc) { + to->from = from; + + from->orig_val = from->value; + from->value = to->value; + } + // copy binding // we don't copy the observer, because the from var has never one switch(from->type) { default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break; case UI_VAR_SPECIAL: break; case UI_VAR_INTEGER: { - UiInteger *f = from->value; + UiInteger *f = fromvalue; UiInteger *t = to->value; if(!f->obj) break; uic_int_copy(f, t); @@ -255,7 +264,7 @@ break; } case UI_VAR_DOUBLE: { - UiDouble *f = from->value; + UiDouble *f = fromvalue; UiDouble *t = to->value; if(!f->obj) break; uic_double_copy(f, t); @@ -263,7 +272,7 @@ break; } case UI_VAR_STRING: { - UiString *f = from->value; + UiString *f = fromvalue; UiString *t = to->value; if(!f->obj) break; uic_string_copy(f, t); @@ -272,7 +281,7 @@ break; } case UI_VAR_TEXT: { - UiText *f = from->value; + UiText *f = fromvalue; UiText *t = to->value; if(!f->obj) break; uic_text_copy(f, t); @@ -282,14 +291,14 @@ break; } case UI_VAR_LIST: { - UiList *f = from->value; + UiList *f = fromvalue; UiList *t = to->value; if(!f->obj) break; uic_list_copy(f, t); t->update(t, -1); } case UI_VAR_RANGE: { - UiRange *f = from->value; + UiRange *f = fromvalue; UiRange *t = to->value; if(!f->obj) break; uic_range_copy(f, t); @@ -298,13 +307,6 @@ t->set(t, t->value); } } - - if(copytodoc) { - to->from = from; - - from->orig_val = from->value; - from->value = to->value; - } } void uic_save_var(UiVar *var) {
--- a/ui/common/properties.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/common/properties.c Thu Nov 16 12:04:10 2017 +0100 @@ -183,7 +183,7 @@ -static char* uic_concat_path(char *base, char *p, char *ext) { +static char* uic_concat_path(const char *base, const char *p, const char *ext) { size_t baselen = strlen(base); UcxBuffer *buf = ucx_buffer_new(NULL, 32, UCX_BUFFER_AUTOEXTEND); @@ -213,7 +213,7 @@ pixmaps_dir = path; } -char* uic_get_image_path(char *imgfilename) { +char* uic_get_image_path(const char *imgfilename) { if(pixmaps_dir) { return uic_concat_path(pixmaps_dir, imgfilename, NULL); } else { @@ -262,7 +262,7 @@ #endif -int uic_load_language_file(char *path) { +int uic_load_language_file(const char *path) { UcxMap *lang = ucx_map_new(256); FILE *file = fopen(path, "r");
--- a/ui/common/properties.h Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/common/properties.h Thu Nov 16 12:04:10 2017 +0100 @@ -46,8 +46,8 @@ void uic_load_app_properties(); void uic_store_app_properties(); -int uic_load_language_file(char *path); -char* uic_get_image_path(char *imgfilename); +int uic_load_language_file(const char *path); +char* uic_get_image_path(const char *imgfilename); #ifdef __cplusplus }
--- a/ui/common/types.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/common/types.c Thu Nov 16 12:04:10 2017 +0100 @@ -90,7 +90,7 @@ /* --------------------------- UiList --------------------------- */ -UiList* ui_list_new(void) { +UiList* ui_list_new(UiContext *ctx, char *name) { UiList *list = malloc(sizeof(UiList)); list->first = ui_list_first; list->next = ui_list_next; @@ -104,6 +104,10 @@ list->update = NULL; list->obj = NULL; + if(name) { + uic_reg_var(ctx, name, UI_VAR_LIST, list); + } + return list; } @@ -167,7 +171,7 @@ char *name; } UiColumn; -UiModel* ui_model_info(UiContext *ctx, ...) { +UiModel* ui_model(UiContext *ctx, ...) { UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel)); va_list ap; @@ -205,7 +209,7 @@ return info; } -void ui_model_info_free(UiContext *ctx, UiModel *mi) { +void ui_model_free(UiContext *ctx, UiModel *mi) { ucx_mempool_free(ctx->mempool, mi->types); ucx_mempool_free(ctx->mempool, mi->titles); ucx_mempool_free(ctx->mempool, mi);
--- a/ui/gtk/image.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/image.c Thu Nov 16 12:04:10 2017 +0100 @@ -31,43 +31,106 @@ #include <string.h> #include "../../ucx/map.h" +#include "toolkit.h" #include "image.h" #include "../common/properties.h" - static UcxMap *image_map; -void ui_image_init() { +static GtkIconTheme *icon_theme; + +void ui_image_init(void) { image_map = ucx_map_new(8); + + icon_theme = gtk_icon_theme_get_default(); +} + +// **** deprecated functions **** + +GdkPixbuf* ui_get_image(char *name) { + UiImage *img = ucx_map_cstr_get(image_map, name); + if(img) { + return img->pixbuf; + } else { + //ui_add_image(name, name); + //return ucx_map_cstr_get(image_map, name); + // TODO + return NULL; + } +} + +// **** new functions **** + +static UiIcon* get_icon(const char *name, int size, int scale) { +#ifdef UI_SUPPORTS_SCALE + GtkIconInfo *info = gtk_icon_theme_lookup_icon_for_scale(icon_theme, name, size, scale, 0); +#else + GtkIconInfo *info = gtk_icon_theme_lookup_icon(icon_theme, name, size, 0); +#endif + if(info) { + UiIcon *icon = malloc(sizeof(UiIcon)); + icon->info = info; + return icon; + } + return NULL; +} + +UiIcon* ui_icon(const char *name, int size) { + return get_icon(name, size, ui_get_scalefactor()); } -void ui_add_image(char *imgname, char *filename) { - // create file path +UiIcon* ui_icon_unscaled(const char *name, int size) { + return get_icon(name, size, 1); +} + +void ui_free_icon(UiIcon *icon) { + g_object_unref(icon->info); + free(icon); +} + +UiImage* ui_icon_image(UiIcon *icon) { + GError *error = NULL; + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); + if(pixbuf) { + UiImage *img = malloc(sizeof(UiImage)); + img->pixbuf = pixbuf; + return img; + } + return NULL; +} + +UiImage* ui_image(const char *filename) { + return ui_named_image(filename, NULL); +} + +UiImage* ui_named_image(const char *filename, const char *name) { char *path = uic_get_image_path(filename); if(!path) { - // TODO: error fprintf(stderr, "UiError: pixmaps directory not set\n"); - return; + return NULL; + } + UiImage *img = ui_load_image_from_path(path, name); + free(path); + return img; +} + +UiImage* ui_load_image_from_path(const char *path, const char *name) { + GError *error = NULL; + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &error); + if(!pixbuf) { + fprintf(stderr, "UiError: Cannot load image: %s\n", path); + return NULL; } - GError *error = NULL; - GdkPixbuf *image = gdk_pixbuf_new_from_file(path, &error); - if(!image) { - // TODO: error - fprintf(stderr, "UiError: Cannot load image: %s\n", path); - } else { - ucx_map_cstr_put(image_map, imgname, image); + UiImage *img = malloc(sizeof(UiImage)); + img->pixbuf = pixbuf; + if(name) { + ucx_map_cstr_put(image_map, name, img); } - - free(path); + return img; } -GdkPixbuf* ui_get_image(char *name) { - GdkPixbuf *pixbuf = ucx_map_cstr_get(image_map, name); - if(pixbuf) { - return pixbuf; - } else { - ui_add_image(name, name); - return ucx_map_cstr_get(image_map, name); - } +void ui_free_image(UiImage *img) { + g_object_unref(img->pixbuf); + free(img); }
--- a/ui/gtk/image.h Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/image.h Thu Nov 16 12:04:10 2017 +0100 @@ -29,13 +29,26 @@ #ifndef IMAGE_H #define IMAGE_H -#include "../ui/toolkit.h" +#include "../ui/image.h" #ifdef __cplusplus extern "C" { #endif -void ui_image_init(); +#if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 10 +#define UI_SUPPORTS_SCALE +#endif + + +struct UiIcon { + GtkIconInfo *info; +}; + +struct UiImage { + GdkPixbuf *pixbuf; +}; + +void ui_image_init(void); GdkPixbuf* ui_get_image(char *name);
--- a/ui/gtk/model.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/model.c Thu Nov 16 12:04:10 2017 +0100 @@ -30,6 +30,7 @@ #include <stdlib.h> #include "model.h" +#include "image.h" #define IS_UI_LIST_MODEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), list_model_type)) @@ -107,6 +108,11 @@ static void ui_model_set_value(GType type, void *data, GValue *value) { switch(type) { + case G_TYPE_OBJECT: { + value->g_type = G_TYPE_OBJECT; + g_value_set_object(value, data); + return; + } case G_TYPE_STRING: { value->g_type = G_TYPE_STRING; g_value_set_string(value, data); @@ -131,7 +137,7 @@ for(int i=0;i<info->columns;i++) { UiModelType type = info->types[i]; if(type == UI_ICON_TEXT) { - model->columntypes[ncol] = G_TYPE_STRING; + model->columntypes[ncol] = G_TYPE_OBJECT; ncol++; model->columntypes[ncol] = G_TYPE_STRING; } else { @@ -245,7 +251,12 @@ //list->current = iter->user_data3; if(model->info->getvalue) { void *data = model->info->getvalue(iter->user_data3, column); - ui_model_set_value(model->columntypes[column], data, value); + if(model->columntypes[column] == G_TYPE_OBJECT) { + UiImage *img = data; + ui_model_set_value(model->columntypes[column], img->pixbuf, value); + } else { + ui_model_set_value(model->columntypes[column], data, value); + } } else { value->g_type = G_TYPE_INVALID; } @@ -257,7 +268,11 @@ { g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); - g_return_val_if_fail(iter->user_data != NULL, FALSE); + //g_return_val_if_fail(iter->user_data != NULL, FALSE); + + if(!iter->user_data) { + return FALSE; + } UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->var->value;
--- a/ui/gtk/model.h Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/model.h Thu Nov 16 12:04:10 2017 +0100 @@ -43,12 +43,12 @@ * UiList to GtkTreeModel wrapper */ struct UiListModel { - GObject object; + GObject object; UiModel *info; - UiVar *var; - GType *columntypes; - int numcolumns; - int stamp; + UiVar *var; + GType *columntypes; + int numcolumns; + int stamp; }; /*
--- a/ui/gtk/toolbar.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/toolbar.c Thu Nov 16 12:04:10 2017 +0100 @@ -358,7 +358,7 @@ } void add_toolbar_combobox(GtkToolbar *tb, UiToolbarComboBox *cb, UiObject *obj) { - UiModel *modelinfo = ui_model_info(obj->ctx, UI_STRING, "", -1); + UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1); modelinfo->getvalue = cb->getvalue; UiListModel *model = ui_list_model_new(cb->var, modelinfo); @@ -371,7 +371,7 @@ void add_toolbar_combobox_nv(GtkToolbar *tb, UiToolbarComboBoxNV *cb, UiObject *obj) { UiVar *var = uic_create_var(obj->ctx, cb->listname, UI_VAR_LIST); if(var) { - UiModel *modelinfo = ui_model_info(obj->ctx, UI_STRING, "", -1); + UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1); modelinfo->getvalue = cb->getvalue; UiListModel *model = ui_list_model_new(var, modelinfo);
--- a/ui/gtk/toolkit.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/toolkit.c Thu Nov 16 12:04:10 2017 +0100 @@ -60,6 +60,8 @@ static UiObject *active_window; +static int scale_factor = 1; + void ui_init(char *appname, int argc, char **argv) { gtk_init(&argc, &argv); application_name = appname; @@ -73,6 +75,11 @@ ui_image_init(); uic_load_app_properties(); + +#ifdef UI_SUPPORTS_SCALE + scale_factor = gdk_monitor_get_scale_factor( + gdk_display_get_primary_monitor(gdk_display_get_default())); +#endif } char* ui_appname() { @@ -222,6 +229,10 @@ } } +int ui_get_scalefactor() { + return scale_factor; +} + void ui_destroy_userdata(GtkWidget *object, void *userdata) { free(userdata); }
--- a/ui/gtk/toolkit.h Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/toolkit.h Thu Nov 16 12:04:10 2017 +0100 @@ -67,6 +67,8 @@ GtkApplication* ui_get_application(); #endif +int ui_get_scalefactor(); + void ui_destroy_userdata(GtkWidget *object, void *userdata); void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data); void ui_destroy_boundvar(UiContext *ctx, UiVar *var);
--- a/ui/gtk/tree.c Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/gtk/tree.c Thu Nov 16 12:04:10 2017 +0100 @@ -64,7 +64,7 @@ // TODO: implement for gtk2 #endif - UiModel *model = ui_model_info(obj->ctx, UI_STRING, "", -1); + UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); model->getvalue = getvalue; UiList *list = var->value; UiListModel *listmodel = ui_list_model_new(var, model); @@ -153,7 +153,7 @@ gtk_tree_view_column_pack_start(column, iconrenderer, FALSE); - gtk_tree_view_column_add_attribute(column, iconrenderer, "icon-name", i); + gtk_tree_view_column_add_attribute(column, iconrenderer, "pixbuf", i); gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1); addi++; @@ -183,7 +183,7 @@ // add TreeView as observer to the UiList to update the TreeView if the // data changes - UiListView *tableview = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListView)); + UiListView *tableview = malloc(sizeof(UiListView)); tableview->ctx = obj->ctx; tableview->widget = view; tableview->var = var; @@ -373,7 +373,7 @@ } UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiModel *model = ui_model_info(obj->ctx, UI_STRING, "", -1); + UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); model->getvalue = getvalue; UiListModel *listmodel = ui_list_model_new(var, model);
--- a/ui/ui/container.h Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/ui/container.h Thu Nov 16 12:04:10 2017 +0100 @@ -35,6 +35,8 @@ extern "C" { #endif +void ui_end(UiObject *obj); + UIWIDGET ui_vbox(UiObject *obj); UIWIDGET ui_hbox(UiObject *obj); UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing); @@ -46,7 +48,6 @@ UIWIDGET ui_scrolledwindow(UiObject *obj); UIWIDGET ui_sidebar(UiObject *obj); -void ui_end(UiObject *obj); UIWIDGET ui_tabview(UiObject *obj); void ui_tab(UiObject *obj, char *title);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/ui/image.h Thu Nov 16 12:04:10 2017 +0100 @@ -0,0 +1,54 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UI_IMAGE_H +#define UI_IMAGE_H + +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UiIcon* ui_icon(const char *name, int size); +UiIcon* ui_icon_unscaled(const char *name, int size); +void ui_free_icon(UiIcon *icon); + +UiImage* ui_icon_image(UiIcon *icon); +UiImage* ui_image(const char *filename); +UiImage* ui_named_image(const char *filename, const char *name); +UiImage* ui_load_image_from_path(const char *path, const char *name); +void ui_free_image(UiImage *img); + + +#ifdef __cplusplus +} +#endif + +#endif /* UI_IMAGE_H */ +
--- a/ui/ui/toolkit.h Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/ui/toolkit.h Thu Nov 16 12:04:10 2017 +0100 @@ -105,6 +105,9 @@ /* begin opaque types */ typedef struct UiContext UiContext; typedef struct UiContainer UiContainer; + +typedef struct UiIcon UiIcon; +typedef struct UiImage UiImage; /* end opaque types */ typedef struct UiTabbedPane UiTabbedPane; @@ -331,7 +334,7 @@ void ui_notify_evt(UiObserver *observer, UiEvent *event); -UiList* ui_list_new(void); +UiList* ui_list_new(UiContext *ctx, char *name); void* ui_list_first(UiList *list); void* ui_list_next(UiList *list); void* ui_list_get(UiList *list, int i); @@ -344,7 +347,7 @@ void ui_clipboard_set(char *str); char* ui_clipboard_get(); -void ui_add_image(char *imgname, char *filename); +void ui_add_image(char *imgname, char *filename); // TODO: remove? // general widget functions void ui_set_enabled(UIWIDGET widget, int enabled);
--- a/ui/ui/tree.h Sun Nov 12 12:03:50 2017 +0100 +++ b/ui/ui/tree.h Thu Nov 16 12:04:10 2017 +0100 @@ -39,6 +39,7 @@ typedef struct UiListCallbacks UiListCallbacks; typedef struct UiListSelection UiListSelection; +typedef void*(*ui_getvaluefunc)(void*,int); typedef enum UiModelType { UI_STRING = 0, @@ -103,8 +104,8 @@ int *rows; }; -UiModel* ui_model_info(UiContext *ctx, ...); -void ui_model_info_free(UiContext *ctx, UiModel *mi); +UiModel* ui_model(UiContext *ctx, ...); +void ui_model_free(UiContext *ctx, UiModel *mi); UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata); UIWIDGET ui_listview_str(UiObject *obj, UiList *list, ui_callback f, void *udata);