# HG changeset patch # User Olaf Wintermann # Date 1729452253 -7200 # Node ID e324291ca9f83ef31b8feb5e7e087433a95a1c16 # Parent 9c25e2616bfae4cb9a921a7ffff0d6af01a487ec add resource preview window diff -r 9c25e2616bfa -r e324291ca9f8 application/application.h --- a/application/application.h Sun Oct 06 18:43:06 2024 +0200 +++ b/application/application.h Sun Oct 20 21:24:13 2024 +0200 @@ -50,6 +50,15 @@ UiList *repos; } DavApp; + +typedef enum DavResourceViewType { + DAV_RESOURCE_VIEW_PROPERTIES = 0, + DAV_RESOURCE_VIEW_TEXT, + DAV_RESOURCE_VIEW_IMAGE +} DavResourceViewType; + +#define DAV_RESOURCEVIEWER_PREVIEW_MAX_SIZE 0x1000000 + /* * main window document object */ @@ -57,6 +66,8 @@ UiContext *ctx; DavSession *sn; UiThreadpool *dav_queue; + + CxMap *res_open_inprogress; char *repo_base; @@ -82,6 +93,38 @@ UiList *resources; } DavBrowser; +/* + * resource view window document object + */ +typedef struct DavResourceViewer { + UiContext *ctx; + DavSession *sn; + DavResource *current; + char *path; + DavResourceViewType type; + + UiInteger *tabview; + UiInteger *loading; + UiString *message; + + UiList *properties; + UiText *text; + UiGeneric *image; + + int error; + char *message_str; + + CxBuffer *text_content; + char *tmp_file; +} DavResourceViewer; + +typedef struct DavPropertyList { + char *ns; + char *name; + char *value_simplified; + char *value_full; +} DavPropertyList; + void application_init(void); /* diff -r 9c25e2616bfa -r e324291ca9f8 application/davcontroller.c --- a/application/davcontroller.c Sun Oct 06 18:43:06 2024 +0200 +++ b/application/davcontroller.c Sun Oct 20 21:24:13 2024 +0200 @@ -34,6 +34,7 @@ #include "config.h" #include "system.h" +#include "common/context.h" #include #include @@ -48,6 +49,8 @@ doc->navstack_pos = 0; doc->dav_queue = ui_threadpool_create(1); + + doc->res_open_inprogress = cxHashMapCreate(ctx->allocator, CX_STORE_POINTERS, 4); doc->path = ui_string_new(ctx, "path"); doc->resources = ui_list_new(ctx, "reslist"); @@ -198,6 +201,64 @@ } } +void davbrowser_open_resource(UiObject *ui, DavBrowser *browser, DavResource *res) { + char *url = util_concat_path(browser->sn->base_url, res->path); + void *x = cxMapGet(browser->res_open_inprogress, url); + free(url); + if(x) { + return; // open resource already in progress + } + + DavResourceViewType type = DAV_RESOURCE_VIEW_PROPERTIES; + if(res->iscollection) { + // default type + } else if(res->contenttype) { + cxstring contenttype = cx_str(res->contenttype); + if(cx_strprefix(contenttype, CX_STR("text/"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } else if(cx_strprefix(contenttype, CX_STR("image/"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strprefix(contenttype, CX_STR("application/"))) { + if(cx_strsuffix(contenttype, CX_STR("json"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } else if(cx_strsuffix(contenttype, CX_STR("/xml"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } else if(cx_strsuffix(contenttype, CX_STR("+xml"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } else if(cx_strsuffix(contenttype, CX_STR("/xml"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } + } + } else { + cxstring path = cx_str(res->path); + if(cx_strsuffix(path, CX_STR(".png"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".jpg"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".jpeg"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".tif"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".tiff"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".webp"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".bmp"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".gif"))) { + type = DAV_RESOURCE_VIEW_IMAGE; + } else if(cx_strsuffix(path, CX_STR(".txt"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } else if(cx_strsuffix(path, CX_STR(".md"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } else if(cx_strsuffix(path, CX_STR(".xml"))) { + type = DAV_RESOURCE_VIEW_TEXT; + } + } + + dav_resourceviewer_new(browser, res->path, type); +} + void davbrowser_add2navstack(DavBrowser *browser, const char *base, const char *path) { if (browser->navstack_enabled) { for (int i = 0; i < browser->navstack_pos; i++) { @@ -1152,3 +1213,102 @@ void davbrowser_newfile(UiObject *ui, DavBrowser *browser, const char *name) { davbrowser_create_resource(ui, browser, name, FALSE); } + + + +DavResourceViewer* dav_resourceviewer_create(DavSession *sn, const char *path, DavResourceViewType type) { + DavResourceViewer *doc = ui_document_new(sizeof(DavResourceViewer)); + UiContext *ctx = ui_document_context(doc); + doc->ctx = ctx; + + doc->sn = dav_session_clone(sn); + doc->path = strdup(path); + doc->type = type; + + doc->tabview = ui_int_new(ctx, "tabview"); + doc->loading = ui_int_new(ctx, "loading"); + doc->message = ui_string_new(ctx, "message"); + + doc->text = ui_text_new(ctx, "text"); + doc->image = ui_generic_new(ctx, "image"); + + doc->properties = ui_list_new(ctx, "properties"); + + return doc; +} + +static char* gen_tmp_download_filename(const char *name) { + char *dir = ui_getappdir(); + + unsigned char rd[8]; + memset(rd, 0, 8); + dav_rand_bytes(rd, 8); + char *hex = util_hexstr(rd, 8); + cxmutstr tmp = cx_asprintf("%sdownload-%s-%s", dir, name, hex); + return tmp.ptr; +} + +static int jobthr_resourceviewer_load(void *data) { + DavResourceViewer *doc = data; + + DavResource *res = dav_resource_new(doc->sn, doc->path); + doc->error = dav_load(res); + if(!doc->error) { + doc->current = res; + + if(res->contentlength < DAV_RESOURCEVIEWER_PREVIEW_MAX_SIZE) { + if(doc->type == DAV_RESOURCE_VIEW_TEXT) { + doc->text_content = cxBufferCreate(NULL, res->contentlength, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS); + int err = dav_get_content(res, doc->text_content, (dav_write_func)cxBufferWrite); + cxBufferPut(doc->text_content, 0); + if(err) { + doc->error = err; + doc->message_str = "Cannot load content"; // TODO: better message + } + } else if(doc->type == DAV_RESOURCE_VIEW_IMAGE) { + char *tmp = gen_tmp_download_filename(res->name); + FILE *f = fopen(tmp, "w"); + if(f) { + int err = dav_get_content(res, f, (dav_write_func)fwrite); + if(!err) { + doc->tmp_file = tmp; + } else { + free(tmp); + } + fclose(f); + } else { + free(tmp); + } + } + } else { + // TODO: add file too large message + } + } else { + doc->message_str = "Cannot load properties"; // TODO: better message + dav_resource_free(res); + } + + return 0; +} + +static void resourceviewer_load_finished(UiEvent *event, void *data) { + DavResourceViewer *doc = data; + + if(doc->type == DAV_RESOURCE_VIEW_TEXT) { + ui_set(doc->text, doc->text_content->space); + } else if(doc->type == DAV_RESOURCE_VIEW_IMAGE) { + ui_image_load_file(doc->image, doc->tmp_file); + unlink(doc->tmp_file); + } + + ui_set(doc->tabview, 1); +} + +void dav_resourceviewer_load(UiObject *ui, DavResourceViewer *res) { + ui_set(res->loading, 1); + ui_set(res->message, "Loading..."); + ui_set(res->tabview, 0); + + ui_job(ui, jobthr_resourceviewer_load, res, resourceviewer_load_finished, res); +} + diff -r 9c25e2616bfa -r e324291ca9f8 application/davcontroller.h --- a/application/davcontroller.h Sun Oct 06 18:43:06 2024 +0200 +++ b/application/davcontroller.h Sun Oct 20 21:24:13 2024 +0200 @@ -40,6 +40,8 @@ #endif #define DAVBROWSER_MAX_NAVLIST 128 + + DavBrowser* davbrowser_create(UiObject *toplevel); @@ -51,6 +53,8 @@ void davbrowser_query_url(UiObject *ui, DavBrowser *browser, const char *url); +void davbrowser_open_resource(UiObject *ui, DavBrowser *browser, DavResource *res); + void davbrowser_add2navstack(DavBrowser *browser, const char *base, const char *path); void davbrowser_navigation_back(UiObject *ui, DavBrowser *browser); @@ -67,6 +71,11 @@ void davbrowser_mkcol(UiObject *ui, DavBrowser *browser, const char *name); void davbrowser_newfile(UiObject *ui, DavBrowser *browser, const char *name); + +DavResourceViewer* dav_resourceviewer_create(DavSession *sn, const char *path, DavResourceViewType type); + +void dav_resourceviewer_load(UiObject *ui, DavResourceViewer *res); + #ifdef __cplusplus } #endif diff -r 9c25e2616bfa -r e324291ca9f8 application/window.c --- a/application/window.c Sun Oct 06 18:43:06 2024 +0200 +++ b/application/window.c Sun Oct 20 21:24:13 2024 +0200 @@ -107,6 +107,57 @@ ui_set(win->progress, on); } + + + + +void dav_resourceviewer_new(DavBrowser *browser, const char *path, DavResourceViewType type) { + const char *name = util_resource_name(path); + UiObject *win = ui_simple_window(name, NULL); + + DavResourceViewer *doc = dav_resourceviewer_create(browser->sn, path, type); + ui_attach_document(win->ctx, doc); + + ui_tabview(win, .tabview = UI_TABVIEW_INVISIBLE, .varname = "tabview") { + /* loading / message tab */ + ui_tab(win, NULL) { + ui_hbox(win, .margin = 16, .spacing = 10, .fill = UI_OFF) { + ui_progressspinner(win, .varname = "loading"); + ui_label(win, .varname = "message"); + } + } + + /* preview tab */ + ui_tab(win, NULL) { + ui_tabview0(win) { + if(type == DAV_RESOURCE_VIEW_TEXT) { + ui_tab(win, "Content") { + ui_textarea(win, .varname = "text"); + } + } else if(type == DAV_RESOURCE_VIEW_IMAGE) { + ui_tab(win, "Preview") { + ui_imageviewer(win, .varname = "image"); + } + } + + ui_tab(win, "Properties") { + UiModel* model = ui_model(win->ctx, UI_STRING, "Namespace", UI_STRING, "Name", UI_STRING, "Value", -1); + model->getvalue = (ui_getvaluefunc) resourceviewer_proplist_getvalue; + ui_table(win, .fill = UI_ON, .model = model, .varname = "properties"); + } + } + } + } + + dav_resourceviewer_load(win, doc); + + ui_show(win); +} + +void* resourceviewer_proplist_getvalue(DavPropertyList *property, int col) { + return NULL; +} + static UiPathElm* dav_get_pathelm(const char *full_path, size_t len, size_t *ret_nelm, void* data) { cxstring fpath = cx_strn(full_path, len); int protocol = 0; @@ -212,7 +263,7 @@ if (res->iscollection) { davbrowser_query_path(event->obj, browser, res->path); } else { - // TODO + davbrowser_open_resource(event->obj, browser, res); } } } diff -r 9c25e2616bfa -r e324291ca9f8 application/window.h --- a/application/window.h Sun Oct 06 18:43:06 2024 +0200 +++ b/application/window.h Sun Oct 20 21:24:13 2024 +0200 @@ -38,7 +38,7 @@ #ifdef __cplusplus extern "C" { #endif - + /* * toplevel UiObject* window data */ @@ -55,6 +55,10 @@ void window_progress(MainWindow *win, int on); + +void dav_resourceviewer_new(DavBrowser *browser, const char *path, DavResourceViewType type); +void* resourceviewer_proplist_getvalue(DavPropertyList *property, int col); + void action_go_back(UiEvent *event, void *data); void action_go_forward(UiEvent *event, void *data); diff -r 9c25e2616bfa -r e324291ca9f8 ui/common/context.c --- a/ui/common/context.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/common/context.c Sun Oct 20 21:24:13 2024 +0200 @@ -162,7 +162,7 @@ static UiVar* ctx_getvar(UiContext *ctx, CxHashKey key) { UiVar *var = cxMapGet(ctx->vars, key); - if(!var) { + if(!var && ctx->documents) { CxIterator i = cxListIterator(ctx->documents); cx_foreach(void *, doc, i) { UiContext *subctx = ui_document_context(doc); @@ -243,6 +243,9 @@ val = ui_range_new(ctx, NULL); break; } + case UI_VAR_GENERIC: { + val = ui_generic_new(ctx, NULL); + } } return val; } @@ -343,6 +346,14 @@ t->set(t, t->value); break; } + case UI_VAR_GENERIC: { + UiGeneric *f = fromvalue; + UiGeneric *t = to->value; + if(!f->obj) break; + uic_generic_copy(f, t); + t->set(t, t->value, t->type); + break; + } } } @@ -355,6 +366,7 @@ case UI_VAR_TEXT: uic_text_save(var->value); break; case UI_VAR_LIST: break; case UI_VAR_RANGE: uic_range_save(var->value); break; + case UI_VAR_GENERIC: uic_generic_save(var->value); break; } } @@ -367,6 +379,7 @@ case UI_VAR_TEXT: uic_text_unbind(var->value); break; case UI_VAR_LIST: uic_list_unbind(var->value); break; case UI_VAR_RANGE: uic_range_unbind(var->value); break; + case UI_VAR_GENERIC: uic_generic_unbind(var->value); break; } } @@ -528,6 +541,10 @@ cxListAdd(ctx->group_widgets, &gw); } +UIEXPORT void *ui_ctx_allocator(UiContext *ctx) { + return (void*) ctx ? ctx->allocator : NULL; +} + void* ui_malloc(UiContext *ctx, size_t size) { return ctx ? cxMalloc(ctx->allocator, size) : NULL; } diff -r 9c25e2616bfa -r e324291ca9f8 ui/common/context.h --- a/ui/common/context.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/common/context.h Sun Oct 20 21:24:13 2024 +0200 @@ -54,7 +54,8 @@ UI_VAR_STRING, UI_VAR_TEXT, UI_VAR_LIST, - UI_VAR_RANGE + UI_VAR_RANGE, + UI_VAR_GENERIC }; struct UiContext { diff -r 9c25e2616bfa -r e324291ca9f8 ui/common/object.c --- a/ui/common/object.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/common/object.c Sun Oct 20 21:24:13 2024 +0200 @@ -51,8 +51,10 @@ UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget) { - UiContext *ctx = toplevel->ctx; - + return uic_ctx_object_new(toplevel->ctx, widget); +} + +UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) { UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject)); newobj->ctx = ctx; newobj->widget = widget; diff -r 9c25e2616bfa -r e324291ca9f8 ui/common/object.h --- a/ui/common/object.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/common/object.h Sun Oct 20 21:24:13 2024 +0200 @@ -36,6 +36,7 @@ #endif UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget); +UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget); void uic_obj_add(UiObject *toplevel, UiObject *ctobj); UiObject* uic_current_obj(UiObject *toplevel); diff -r 9c25e2616bfa -r e324291ca9f8 ui/common/types.c --- a/ui/common/types.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/common/types.c Sun Oct 20 21:24:13 2024 +0200 @@ -281,6 +281,15 @@ return r; } +UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, char *name) { + UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric)); + memset(g, 0, sizeof(UiGeneric)); + if(name) { + uic_reg_var(ctx, name, UI_VAR_GENERIC, g); + } + return g; +} + void ui_int_set(UiInteger* i, int64_t value) { if (i && i->set) { @@ -389,6 +398,12 @@ to->obj = from->obj; } +void uic_generic_copy(UiGeneric *from, UiGeneric *to) { + to->get = from->get; + to->get_type = from->get_type; + to->set = from->set; + to->obj = from->obj; +} void uic_int_save(UiInteger *i) { if(!i->obj) return; @@ -416,6 +431,11 @@ r->get(r); } +void uic_generic_save(UiGeneric *g) { + if(!g->obj) return; + g->get(g); +} + void uic_int_unbind(UiInteger *i) { i->get = NULL; @@ -462,6 +482,13 @@ l->obj = NULL; } +void uic_generic_unbind(UiGeneric *g) { + g->get = NULL; + g->get_type = NULL; + g->set = NULL; + g->obj = NULL; +} + UIEXPORT UiListSelection ui_list_getselection(UiList *list) { if (list->getselection) { diff -r 9c25e2616bfa -r e324291ca9f8 ui/common/types.h --- a/ui/common/types.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/common/types.h Sun Oct 20 21:24:13 2024 +0200 @@ -42,12 +42,14 @@ void uic_text_copy(UiText *from, UiText *to); void uic_range_copy(UiRange *from, UiRange *to); void uic_list_copy(UiList *from, UiList *to); +void uic_generic_copy(UiGeneric *from, UiGeneric *to); void uic_int_save(UiInteger *i); void uic_double_save(UiDouble *d); void uic_string_save(UiString *s); void uic_text_save(UiText *t); void uic_range_save(UiRange *r); +void uic_generic_save(UiGeneric *g); void uic_int_unbind(UiInteger *i); void uic_double_unbind(UiDouble *d); @@ -55,6 +57,7 @@ void uic_text_unbind(UiText *t); void uic_range_unbind(UiRange *r); void uic_list_unbind(UiList *l); +void uic_generic_unbind(UiGeneric *g); #ifdef __cplusplus } diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/button.c --- a/ui/gtk/button.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/button.c Sun Oct 20 21:24:13 2024 +0200 @@ -401,8 +401,8 @@ event); } - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, rbutton, FALSE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, rbutton, FALSE); return rbutton; } diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/container.c --- a/ui/gtk/container.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/container.c Sun Oct 20 21:24:13 2024 +0200 @@ -32,6 +32,7 @@ #include "container.h" #include "toolkit.h" +#include "headerbar.h" #include "../common/context.h" #include "../common/object.h" @@ -228,10 +229,12 @@ } void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { - gtk_notebook_append_page( - GTK_NOTEBOOK(ct->widget), - widget, - gtk_label_new(ct->layout.label)); + UiGtkTabView *data = ui_widget_get_tabview_data(ct->widget); + if(!data) { + fprintf(stderr, "UI Error: widget is not a tabview"); + return; + } + data->add_tab(ct->widget, -1, ct->layout.label, widget); ui_reset_layout(ct->layout); ct->current = widget; @@ -330,10 +333,431 @@ } -void ui_select_tab(UIWIDGET tabview, int tab) { +void ui_notebook_tab_select(UIWIDGET tabview, int tab) { gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab); } +void ui_notebook_tab_remove(UIWIDGET tabview, int tab) { + gtk_notebook_remove_page(GTK_NOTEBOOK(tabview), tab); +} + +void ui_notebook_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) { + gtk_notebook_insert_page( + GTK_NOTEBOOK(widget), + child, + gtk_label_new(name), + index); +} + +int64_t ui_notebook_get(UiInteger *i) { + GtkNotebook *nb = i->obj; + i->value = gtk_notebook_get_current_page(nb); + return i->value; +} + +void ui_notebook_set(UiInteger *i, int64_t value) { + GtkNotebook *nb = i->obj; + gtk_notebook_set_current_page(nb, value); + i->value = gtk_notebook_get_current_page(nb); +} + + +#if GTK_MAJOR_VERSION >= 4 +static int stack_set_page(GtkWidget *stack, int index) { + GtkSelectionModel *pages = gtk_stack_get_pages(GTK_STACK(stack)); + GListModel *list = G_LIST_MODEL(pages); + GtkStackPage *page = g_list_model_get_item(list, index); + if(page) { + gtk_stack_set_visible_child(GTK_STACK(stack), gtk_stack_page_get_child(page)); + } else { + fprintf(stderr, "UI Error: ui_stack_set value out of bounds\n"); + return -1; + } + return index; +} + +void ui_stack_tab_select(UIWIDGET tabview, int tab) { + stack_set_page(tabview, tab); +} + +void ui_stack_tab_remove(UIWIDGET tabview, int tab) { + GtkStack *stack = GTK_STACK(tabview); + GtkWidget *current = gtk_stack_get_visible_child(stack); + GtkSelectionModel *pages = gtk_stack_get_pages(stack); + GListModel *list = G_LIST_MODEL(pages); + GtkStackPage *page = g_list_model_get_item(list, tab); + if(page) { + gtk_stack_remove(stack, gtk_stack_page_get_child(page)); + } +} + +void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) { + (void)gtk_stack_add_titled(GTK_STACK(widget), child, name, name); +} + +int64_t ui_stack_get(UiInteger *i) { + GtkStack *stack = GTK_STACK(i->obj); + GtkWidget *current = gtk_stack_get_visible_child(stack); + GtkSelectionModel *pages = gtk_stack_get_pages(stack); + GListModel *list = G_LIST_MODEL(pages); + int nitems = g_list_model_get_n_items(list); + for(int p=0;pvalue = p; + break; + } + } + return i->value; +} + +void ui_stack_set(UiInteger *i, int64_t value) { + GtkWidget *widget = i->obj; + if(stack_set_page(widget, value) >= 0) { + i->value = value; + } +} +#elif GTK_MAJOR_VERSION >= 3 +static GtkWidget* stack_get_child(GtkWidget *stack, int index) { + GList *children = gtk_container_get_children(GTK_CONTAINER(stack)); + if(children) { + return g_list_nth_data(children, index); + } + return NULL; +} + +void ui_stack_tab_select(UIWIDGET tabview, int tab) { + GtkWidget *child = stack_get_child(tabview, tab); + if(child) { + gtk_stack_set_visible_child(GTK_STACK(tabview), child); + } +} + +void ui_stack_tab_remove(UIWIDGET tabview, int tab) { + GtkWidget *child = stack_get_child(tabview, tab); + if(child) { + gtk_container_remove(GTK_CONTAINER(tabview), child); + } +} + +void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) { + gtk_stack_add_titled(GTK_STACK(widget), child, name, name); +} + +int64_t ui_stack_get(UiInteger *i) { + GtkWidget *visible = gtk_stack_get_visible_child(GTK_STACK(i->obj)); + GList *children = gtk_container_get_children(GTK_CONTAINER(i->obj)); + GList *elm = children; + int n = 0; + int64_t v = -1; + while(elm) { + GtkWidget *child = elm->data; + if(child == visible) { + v = n; + break; + } + + elm = elm->next; + n++; + } + g_list_free(children); + i->value = v; + return v; +} + +void ui_stack_set(UiInteger *i, int64_t value) { + GtkWidget *child = stack_get_child(i->obj, value); + if(child) { + gtk_stack_set_visible_child(GTK_STACK(i->obj), child); + i->value = value; + } +} + +#endif + + + + +UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview) { + return g_object_get_data(G_OBJECT(tabview), "ui_tabview"); +} + +typedef int64_t(*ui_tabview_get_func)(UiInteger*); +typedef void (*ui_tabview_set_func)(UiInteger*, int64_t); + +UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) { + UiGtkTabView *data = malloc(sizeof(UiGtkTabView)); + data->margin = args.margin; + data->spacing = args.spacing; + data->columnspacing = args.columnspacing; + data->rowspacing = args.rowspacing; + + ui_tabview_get_func getfunc = NULL; + ui_tabview_set_func setfunc = NULL; + + GtkWidget *widget = NULL; + GtkWidget *data_widget = NULL; + switch(args.tabview) { + case UI_TABVIEW_DOC: { + // TODO + break; + } + case UI_TABVIEW_NAVIGATION_SIDE: { +#if GTK_CHECK_VERSION(3, 10, 0) + widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + GtkWidget *sidebar = gtk_stack_sidebar_new(); + BOX_ADD(widget, sidebar); + GtkWidget *stack = gtk_stack_new(); + gtk_stack_set_transition_type (GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN); + gtk_stack_sidebar_set_stack(GTK_STACK_SIDEBAR(sidebar), GTK_STACK(stack)); + BOX_ADD_EXPAND(widget, stack); + data->select_tab = ui_stack_tab_select; + data->remove_tab = ui_stack_tab_remove; + data->add_tab = ui_stack_tab_add; + getfunc = ui_stack_get; + setfunc = ui_stack_set; + data_widget = stack; +#else + // TODO +#endif + break; + } + case UI_TABVIEW_DEFAULT: /* fall through */ + case UI_TABVIEW_NAVIGATION_TOP: /* fall through */ + case UI_TABVIEW_INVISIBLE: /* fall through */ + case UI_TABVIEW_NAVIGATION_TOP2: { + widget = gtk_notebook_new(); + data_widget = widget; + data->select_tab = ui_notebook_tab_select; + data->remove_tab = ui_notebook_tab_remove; + data->add_tab = ui_notebook_tab_add; + getfunc = ui_notebook_get; + setfunc = ui_notebook_set; + if(args.tabview == UI_TABVIEW_INVISIBLE) { + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(widget), FALSE); + gtk_notebook_set_show_border(GTK_NOTEBOOK(widget), FALSE); + } + break; + } + } + + UiObject* current = uic_current_obj(obj); + if(args.value || args.varname) { + UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER); + UiInteger *i = var->value; + i->get = getfunc; + i->set = setfunc; + i->obj = data_widget; + } + + g_object_set_data(G_OBJECT(widget), "ui_tabview", data); + data->widget = data_widget; + data->subcontainer = args.subcontainer; + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, widget, TRUE); + + UiObject *newobj = uic_object_new(obj, widget); + newobj->container = ui_tabview_container(obj, widget); + uic_obj_add(obj, newobj); + data->obj = newobj; + + return widget; +} + +void ui_tab_create(UiObject* obj, const char* title) { + UiObject* current = uic_current_obj(obj); + UiGtkTabView *data = ui_widget_get_tabview_data(current->widget); + if(!data) { + fprintf(stderr, "UI Error: widget is not a tabview\n"); + return; + } + + UiObject *newobj = ui_tabview_add(current->widget, title, -1); + current->next = newobj; +} + + + +void ui_tabview_select(UIWIDGET tabview, int tab) { + UiGtkTabView *data = ui_widget_get_tabview_data(tabview); + if(!data) { + fprintf(stderr, "UI Error: widget is not a tabview\n"); + return; + } + data->select_tab(tabview, tab); +} + +void ui_tabview_remove(UIWIDGET tabview, int tab) { + UiGtkTabView *data = ui_widget_get_tabview_data(tabview); + if(!data) { + fprintf(stderr, "UI Error: widget is not a tabview\n"); + return; + } + data->remove_tab(tabview, tab); +} + +UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) { + UiGtkTabView *data = ui_widget_get_tabview_data(tabview); + if(!data) { + fprintf(stderr, "UI Error: widget is not a tabview\n"); + return NULL; + } + + UiObject *newobj = cxCalloc(data->obj->ctx->allocator, 1, sizeof(UiObject)); + newobj->ctx = data->obj->ctx; + + GtkWidget *sub; + switch(data->subcontainer) { + default: { + sub = ui_gtk_vbox_new(data->spacing); + newobj->container = ui_box_container(newobj, sub, data->subcontainer); + break; + } + case UI_CONTAINER_HBOX: { + sub = ui_gtk_hbox_new(data->spacing); + newobj->container = ui_box_container(newobj, sub, data->subcontainer); + break; + } + case UI_CONTAINER_GRID: { + sub = create_grid(data->columnspacing, data->rowspacing); + newobj->container = ui_grid_container(newobj, sub); + break; + } + } + newobj->widget = sub; + GtkWidget *widget = box_set_margin(sub, data->margin); + + data->add_tab(data->widget, tab_index, name, widget); + + return newobj; +} + + +/* -------------------- Headerbar -------------------- */ + +static void hb_set_part(UiObject *obj, int part) { + UiObject* current = uic_current_obj(obj); + GtkWidget *headerbar = current->widget; + + UiHeaderbarContainer *hb = cxCalloc( + obj->ctx->allocator, + 1, + sizeof(UiHeaderbarContainer)); + memcpy(hb, current->container, sizeof(UiHeaderbarContainer)); + + UiObject *newobj = uic_object_new(obj, headerbar); + newobj->container = (UiContainer*)hb; + uic_obj_add(obj, newobj); + + hb->part = part; +} + +void ui_headerbar_start_create(UiObject *obj) { + hb_set_part(obj, 0); +} + +void ui_headerbar_center_create(UiObject *obj) { + hb_set_part(obj, 2); +} + +void ui_headerbar_end_create(UiObject *obj) { + hb_set_part(obj, 1); +} + +UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs args) { + UiObject *current = uic_current_obj(obj); + UiContainer *ct = current->container; + UI_APPLY_LAYOUT1(current, args); + + GtkWidget *box = ui_gtk_hbox_new(args.alt_spacing); + ui_set_name_and_style(box, args.name, args.style_class); + ct->add(ct, box, FALSE); + + UiObject *newobj = uic_object_new(obj, box); + newobj->container = ui_headerbar_fallback_container(obj, box); + uic_obj_add(obj, newobj); + + return box; +} + +static void hb_fallback_set_part(UiObject *obj, int part) { + UiObject* current = uic_current_obj(obj); + GtkWidget *headerbar = current->widget; + + UiObject *newobj = uic_object_new(obj, headerbar); + newobj->container = ui_headerbar_container(obj, headerbar); + uic_obj_add(obj, newobj); + + UiHeaderbarContainer *hb = (UiHeaderbarContainer*)newobj->container; + hb->part = part; +} + +UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) { + UiHeaderbarContainer *ct = cxCalloc( + obj->ctx->allocator, + 1, + sizeof(UiHeaderbarContainer)); + ct->container.widget = headerbar; + ct->container.add = ui_headerbar_fallback_container_add; + return (UiContainer*)ct; +} + +void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { + UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct; + BOX_ADD(ct->widget, widget); +} + +#if GTK_CHECK_VERSION(3, 10, 0) + +UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) { + GtkWidget *headerbar = g_object_get_data(G_OBJECT(obj->widget), "ui_headerbar"); + if(!headerbar) { + return ui_headerbar_fallback_create(obj, args); + } + + UiObject *newobj = uic_object_new(obj, headerbar); + newobj->container = ui_headerbar_container(obj, headerbar); + uic_obj_add(obj, newobj); + + return headerbar; +} + +UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) { + UiHeaderbarContainer *ct = cxCalloc( + obj->ctx->allocator, + 1, + sizeof(UiHeaderbarContainer)); + ct->container.widget = headerbar; + ct->container.add = ui_headerbar_container_add; + return (UiContainer*)ct; +} + +void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { + UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct; + if(hb->part == 0) { + UI_HEADERBAR_PACK_START(ct->widget, widget); + } else if(hb->part == 1) { + UI_HEADERBAR_PACK_END(ct->widget, widget); + } else if(hb->part == 2) { + if(!hb->centerbox) { + GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); + hb->centerbox = box; + UI_HEADERBAR_SET_TITLE_WIDGET(ct->widget, box); + } + BOX_ADD(hb->centerbox, widget); + } +} + +#else + +UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) { + return ui_headerbar_fallback_create(obj, args); +} + +#endif + /* -------------------- Splitpane -------------------- */ static GtkWidget* create_paned(UiOrientation orientation) { diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/container.h --- a/ui/gtk/container.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/container.h Sun Oct 20 21:24:13 2024 +0200 @@ -33,6 +33,8 @@ #include "../ui/container.h" #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -92,6 +94,7 @@ #endif } UiGridContainer; +/* typedef struct UiPanedContainer { UiContainer container; GtkWidget *current_pane; @@ -99,11 +102,35 @@ int max; int cur; } UiPanedContainer; +*/ typedef struct UiTabViewContainer { UiContainer container; } UiTabViewContainer; +typedef void (*ui_select_tab_func)(UIWIDGET widget, int tab); +typedef void (*ui_add_tab_func)(UIWIDGET widget, int index, const char *name, UIWIDGET child); + +typedef struct UiGtkTabView { + UiObject *obj; + GtkWidget *widget; + ui_select_tab_func select_tab; + ui_select_tab_func remove_tab; + ui_add_tab_func add_tab; + UiSubContainerType subcontainer; + int margin; + int spacing; + int columnspacing; + int rowspacing; +} UiGtkTabView; + +typedef struct UiHeaderbarContainer { + UiContainer container; + GtkWidget *centerbox; + int part; + UiHeaderbarAlternative alternative; /* only used by fallback headerbar */ +} UiHeaderbarContainer; + GtkWidget* ui_gtk_vbox_new(int spacing); GtkWidget* ui_gtk_hbox_new(int spacing); @@ -129,10 +156,17 @@ void ui_split_container_add1(UiContainer *ct, GtkWidget *widget, UiBool fill); void ui_split_container_add2(UiContainer *ct, GtkWidget *widget, UiBool fill); +UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview); -UiObject* ui_add_document_tab(UiDocumentView *view); -void ui_tab_set_document(UiContext *ctx, void *document); -void ui_tab_detach_document(UiContext *ctx); +void ui_gtk_notebook_select_tab(GtkWidget *widget, int tab); + +#if GTK_CHECK_VERSION(3, 10, 0) +UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar); +void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill); +#endif + +UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar); +void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill); #ifdef __cplusplus } diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/headerbar.c --- a/ui/gtk/headerbar.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/headerbar.c Sun Oct 20 21:24:13 2024 +0200 @@ -31,25 +31,7 @@ #include "button.h" #include "menu.h" -#if GTK_MAJOR_VERSION >= 3 - -#ifdef UI_LIBADWAITA -#define UI_HEADERBAR AdwHeaderBar* -#define UI_HEADERBAR_CAST(h) ADW_HEADER_BAR(h) -#define UI_HEADERBAR_PACK_START(h, w) adw_header_bar_pack_start(ADW_HEADER_BAR(h), w) -#define UI_HEADERBAR_PACK_END(h, w) adw_header_bar_pack_end(ADW_HEADER_BAR(h), w) -#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) adw_header_bar_set_title_widget(ADW_HEADER_BAR(h), w) -#else -#define UI_HEADERBAR GtkHeaderBar* -#define UI_HEADERBAR_CAST(h) GTK_HEADER_BAR(h) -#define UI_HEADERBAR_PACK_START(h, w) gtk_header_bar_pack_start(GTK_HEADER_BAR(h), w) -#define UI_HEADERBAR_PACK_END(h, w) gtk_header_bar_pack_end(GTK_HEADER_BAR(h), w) -#if GTK_MAJOR_VERSION >= 4 -#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_title_widget(GTK_HEADER_BAR(h), w) -#else -#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_custom_title(GTK_HEADER_BAR(h), w) -#endif -#endif +#if GTK_CHECK_VERSION(3, 10, 0) void ui_fill_headerbar(UiObject *obj, GtkWidget *headerbar) { CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/headerbar.h --- a/ui/gtk/headerbar.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/headerbar.h Sun Oct 20 21:24:13 2024 +0200 @@ -38,7 +38,25 @@ extern "C" { #endif -#if GTK_MAJOR_VERSION >= 3 +#if GTK_CHECK_VERSION(3, 10, 0) + +#ifdef UI_LIBADWAITA +#define UI_HEADERBAR AdwHeaderBar* +#define UI_HEADERBAR_CAST(h) ADW_HEADER_BAR(h) +#define UI_HEADERBAR_PACK_START(h, w) adw_header_bar_pack_start(ADW_HEADER_BAR(h), w) +#define UI_HEADERBAR_PACK_END(h, w) adw_header_bar_pack_end(ADW_HEADER_BAR(h), w) +#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) adw_header_bar_set_title_widget(ADW_HEADER_BAR(h), w) +#else +#define UI_HEADERBAR GtkHeaderBar* +#define UI_HEADERBAR_CAST(h) GTK_HEADER_BAR(h) +#define UI_HEADERBAR_PACK_START(h, w) gtk_header_bar_pack_start(GTK_HEADER_BAR(h), w) +#define UI_HEADERBAR_PACK_END(h, w) gtk_header_bar_pack_end(GTK_HEADER_BAR(h), w) +#if GTK_MAJOR_VERSION >= 4 +#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_title_widget(GTK_HEADER_BAR(h), w) +#else +#define UI_HEADERBAR_SET_TITLE_WIDGET(h, w) gtk_header_bar_set_custom_title(GTK_HEADER_BAR(h), w) +#endif +#endif void ui_fill_headerbar(UiObject *obj, GtkWidget *headerbar); diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/icon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/gtk/icon.c Sun Oct 20 21:24:13 2024 +0200 @@ -0,0 +1,204 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include "toolkit.h" +#include "icon.h" +#include "../common/properties.h" + +static CxMap *image_map; + +static GtkIconTheme *icon_theme; + +#if GTK_MAJOR_VERSION >= 4 +#define ICONTHEME_GET_DEFAULT() gtk_icon_theme_get_for_display(gdk_display_get_default()) +#else +#define ICONTHEME_GET_DEFAULT() gtk_icon_theme_get_default() +#endif + +void ui_image_init(void) { + image_map = cxHashMapCreateSimple(CX_STORE_POINTERS); + + icon_theme = ICONTHEME_GET_DEFAULT(); +} + +// **** deprecated functions **** + +GdkPixbuf* ui_get_image(const char *name) { + UiImage *img = cxMapGet(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; + } +} + +// **** deprecated2**** + +static UiIcon* get_icon(const char *name, int size, int scale) { +#if GTK_MAJOR_VERSION >= 4 + GtkIconPaintable *info = gtk_icon_theme_lookup_icon(icon_theme, name, NULL, size, scale, GTK_TEXT_DIR_LTR, GTK_ICON_LOOKUP_FORCE_REGULAR); +#elif defined(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; + icon->pixbuf = NULL; + return icon; + } + return NULL; +} + +UiIcon* ui_icon(const char* name, size_t size) { + return get_icon(name, size, ui_get_scalefactor()); +} + +UiIcon* ui_imageicon(const char* file) { + GError *error = NULL; + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(file, &error); + if(!pixbuf) { + fprintf(stderr, "UiError: Cannot load image: %s\n", file); + return NULL; + } + + UiIcon *icon = malloc(sizeof(UiIcon)); + icon->info = NULL; + icon->pixbuf = pixbuf; + return icon; +} + +void ui_icon_free(UiIcon* icon) { + if(icon->info) { + g_object_unref(icon->info); + } + if(icon->pixbuf) { + g_object_unref(icon->pixbuf); + } + free(icon); +} + +UiIcon* ui_foldericon(size_t size) { + return ui_icon("folder", size); +} + +UiIcon* ui_fileicon(size_t size) { + UiIcon *icon = ui_icon("file", size); +#if GTK_MAJOR_VERSION >= 4 + GFile *file = gtk_icon_paintable_get_file(icon->info); + char *path = g_file_get_path(file); + if(!path) { + icon = ui_icon("application-x-generic", size); + } +#endif + return icon; +} + +UiIcon* ui_icon_unscaled(const char *name, int size) { + return get_icon(name, size, 1); +} + +#if GTK_MAJOR_VERSION >= 4 +GdkPixbuf* ui_icon_pixbuf(UiIcon *icon) { + if(!icon->pixbuf) { + GFile *file = gtk_icon_paintable_get_file(icon->info); + GError *error = NULL; + char *path = g_file_get_path(file); + icon->pixbuf = gdk_pixbuf_new_from_file(path, &error); + } + return icon->pixbuf; +} +#else +GdkPixbuf* ui_icon_pixbuf(UiIcon *icon) { + if(!icon->pixbuf) { + GError *error = NULL; + icon->pixbuf = gtk_icon_info_load_icon(icon->info, &error); + } + return icon->pixbuf; +} +#endif + +/* +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) { + fprintf(stderr, "UiError: pixmaps directory not set\n"); + 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; + } + + UiImage *img = malloc(sizeof(UiImage)); + img->pixbuf = pixbuf; + if(name) { + cxMapPut(image_map, name, img); + } + return img; +} +*/ + +void ui_free_image(UiImage *img) { + g_object_unref(img->pixbuf); + free(img); +} diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/icon.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/gtk/icon.h Sun Oct 20 21:24:13 2024 +0200 @@ -0,0 +1,67 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 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 ICON_H +#define ICON_H + +#include "../ui/icons.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 10 +#define UI_SUPPORTS_SCALE +#endif + + +struct UiIcon { +#if GTK_MAJOR_VERSION >= 4 + GtkIconPaintable *info; +#else + GtkIconInfo *info; +#endif + GdkPixbuf *pixbuf; +}; + +struct UiImage { + GdkPixbuf *pixbuf; +}; + +void ui_image_init(void); + +GdkPixbuf* ui_get_image(const char *name); + +GdkPixbuf* ui_icon_pixbuf(UiIcon *icon); + +#ifdef __cplusplus +} +#endif + +#endif /* ICON_H */ + diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/image.c --- a/ui/gtk/image.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/image.c Sun Oct 20 21:24:13 2024 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2017 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -26,170 +26,103 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include - -#include "toolkit.h" #include "image.h" -#include "../common/properties.h" - -static CxMap *image_map; - -static GtkIconTheme *icon_theme; -#if GTK_MAJOR_VERSION >= 4 -#define ICONTHEME_GET_DEFAULT() gtk_icon_theme_get_for_display(gdk_display_get_default()) -#else -#define ICONTHEME_GET_DEFAULT() gtk_icon_theme_get_default() -#endif +#include "container.h" +#include "../common/context.h" +#include "../common/object.h" -void ui_image_init(void) { - image_map = cxHashMapCreateSimple(CX_STORE_POINTERS); - - icon_theme = ICONTHEME_GET_DEFAULT(); -} - -// **** deprecated functions **** -GdkPixbuf* ui_get_image(const char *name) { - UiImage *img = cxMapGet(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; - } -} - -// **** deprecated2**** - -static UiIcon* get_icon(const char *name, int size, int scale) { -#if GTK_MAJOR_VERSION >= 4 - GtkIconPaintable *info = gtk_icon_theme_lookup_icon(icon_theme, name, NULL, size, scale, GTK_TEXT_DIR_LTR, GTK_ICON_LOOKUP_FORCE_REGULAR); -#elif defined(UI_SUPPORTS_SCALE) - GtkIconInfo *info = gtk_icon_theme_lookup_icon_for_scale(icon_theme, name, size, scale, 0); +UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) { + UiObject *current = uic_current_obj(obj); + + GtkWidget *scrolledwindow = SCROLLEDWINDOW_NEW(); +#if GTK_CHECK_VERSION(4, 0, 0) + GtkWidget *image = gtk_picture_new(); +#else + GtkWidget *image = gtk_image_new(); +#endif + + ui_set_name_and_style(image, args.name, args.style_class); + +#if GTK_MAJOR_VERSION < 4 + GtkWidget *eventbox = gtk_event_box_new(); + SCROLLEDWINDOW_SET_CHILD(scrolledwindow, eventbox); + gtk_container_add(GTK_CONTAINER(eventbox), image); #else - GtkIconInfo *info = gtk_icon_theme_lookup_icon(icon_theme, name, size, 0); + SCROLLEDWINDOW_SET_CHILD(scrolledwindow, image); #endif - if(info) { - UiIcon *icon = malloc(sizeof(UiIcon)); - icon->info = info; - icon->pixbuf = NULL; - return icon; - } - return NULL; -} - -UiIcon* ui_icon(const char* name, size_t size) { - return get_icon(name, size, ui_get_scalefactor()); -} - -UiIcon* ui_imageicon(const char* file) { - GError *error = NULL; - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(file, &error); - if(!pixbuf) { - fprintf(stderr, "UiError: Cannot load image: %s\n", file); - return NULL; + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, scrolledwindow, TRUE); + + UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_GENERIC); + if(var) { + UiGeneric *value = var->value; + value->get = ui_imageviewer_get; + value->get_type = ui_imageviewer_get_type; + value->set = ui_imageviewer_set; + value->obj = image; + if(value->value && value->type && !strcmp(value->type, UI_IMAGE_OBJECT_TYPE)) { + GdkPixbuf *pixbuf = value->value; + value->value = NULL; + ui_imageviewer_set(value, pixbuf, UI_IMAGE_OBJECT_TYPE); + } } - UiIcon *icon = malloc(sizeof(UiIcon)); - icon->info = NULL; - icon->pixbuf = pixbuf; - return icon; + return scrolledwindow; } -void ui_icon_free(UiIcon* icon) { - if(icon->info) { - g_object_unref(icon->info); - } - if(icon->pixbuf) { - g_object_unref(icon->pixbuf); - } - free(icon); +void* ui_imageviewer_get(UiGeneric *g) { + return g->value; } -UiIcon* ui_foldericon(size_t size) { - return ui_icon("folder", size); -} - -UiIcon* ui_fileicon(size_t size) { - return ui_icon("file", size); -} - -UiIcon* ui_icon_unscaled(const char *name, int size) { - return get_icon(name, size, 1); +const char* ui_imageviewer_get_type(UiGeneric *g) { + } -#if GTK_MAJOR_VERSION >= 4 -GdkPixbuf* ui_icon_pixbuf(UiIcon *icon) { - if(!icon->pixbuf) { - GFile *file = gtk_icon_paintable_get_file(icon->info); - GError *error = NULL; - icon->pixbuf = gdk_pixbuf_new_from_file(g_file_get_path(file), &error); +int ui_imageviewer_set(UiGeneric *g, void *value, const char *type) { + if(!type || strcmp(type, UI_IMAGE_OBJECT_TYPE)) { + return 1; } - return icon->pixbuf; -} + + // TODO: do we need to free the previous value here? + + g->value = value; + g->type = type; + GdkPixbuf *pixbuf = value; + + if(pixbuf) { + int width, height; +#if GTK_CHECK_VERSION(4, 12, 0) + GdkTexture *texture = gdk_texture_new_for_pixbuf(pixbuf); + gtk_picture_set_paintable(GTK_PICTURE(g->obj), GDK_PAINTABLE(texture)); + width = gdk_texture_get_width(texture); + height = gdk_texture_get_height(texture); #else -GdkPixbuf* ui_icon_pixbuf(UiIcon *icon) { - if(!icon->pixbuf) { - GError *error = NULL; - icon->pixbuf = gtk_icon_info_load_icon(icon->info, &error); - } - return icon->pixbuf; -} + gtk_image_set_from_pixbuf(GTK_IMAGE(g->obj), pixbuf); #endif + gtk_widget_set_size_request(g->obj, width, height); + } -/* -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); + + return 0; } -UiImage* ui_named_image(const char *filename, const char *name) { - char *path = uic_get_image_path(filename); - if(!path) { - fprintf(stderr, "UiError: pixmaps directory not set\n"); - 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) { +int ui_image_load_file(UiGeneric *obj, const char *path) { 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; + return 1; } - UiImage *img = malloc(sizeof(UiImage)); - img->pixbuf = pixbuf; - if(name) { - cxMapPut(image_map, name, img); + if(obj->set) { + obj->set(obj, pixbuf, UI_IMAGE_OBJECT_TYPE); + } else { + obj->value = pixbuf; } - return img; + + return 0; } -*/ - -void ui_free_image(UiImage *img) { - g_object_unref(img->pixbuf); - free(img); -} diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/image.h --- a/ui/gtk/image.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/image.h Sun Oct 20 21:24:13 2024 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2017 Olaf Wintermann. All rights reserved. + * Copyright 2024 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: @@ -27,41 +27,23 @@ */ #ifndef IMAGE_H -#define IMAGE_H +#define IMAGE_H #include "../ui/image.h" +#include "toolkit.h" -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif -#if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 10 -#define UI_SUPPORTS_SCALE -#endif - -struct UiIcon { -#if GTK_MAJOR_VERSION >= 4 - GtkIconPaintable *info; -#else - GtkIconInfo *info; -#endif - GdkPixbuf *pixbuf; -}; +void* ui_imageviewer_get(UiGeneric *g); +const char* ui_imageviewer_get_type(UiGeneric *g); +int ui_imageviewer_set(UiGeneric *g, void *value, const char *type); -struct UiImage { - GdkPixbuf *pixbuf; -}; - -void ui_image_init(void); - -GdkPixbuf* ui_get_image(const char *name); - -GdkPixbuf* ui_icon_pixbuf(UiIcon *icon); - -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#endif /* IMAGE_H */ +#endif /* IMAGE_H */ diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/list.c --- a/ui/gtk/list.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/list.c Sun Oct 20 21:24:13 2024 +0200 @@ -36,7 +36,7 @@ #include "container.h" #include "list.h" -#include "image.h" +#include "icon.h" void* ui_strmodel_getvalue(void *elm, int column) { diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/objs.mk --- a/ui/gtk/objs.mk Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/objs.mk Sun Oct 20 21:24:13 2024 +0200 @@ -40,6 +40,7 @@ GTKOBJ += text.o GTKOBJ += list.o GTKOBJ += image.o +GTKOBJ += icon.o GTKOBJ += graphics.o GTKOBJ += range.o GTKOBJ += entry.o diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/text.c --- a/ui/gtk/text.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/text.c Sun Oct 20 21:24:13 2024 +0200 @@ -62,8 +62,13 @@ } } -UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var) { +UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) { + UiObject* current = uic_current_obj(obj); + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_TEXT); + GtkWidget *text_area = gtk_text_view_new(); + ui_set_name_and_style(text_area, args.name, args.style_class); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_area), GTK_WRAP_WORD_CHAR); g_signal_connect( text_area, @@ -90,17 +95,17 @@ SCROLLEDWINDOW_SET_CHILD(scroll_area, text_area); // font and padding - PangoFontDescription *font; - font = pango_font_description_from_string("Monospace"); + //PangoFontDescription *font; + //font = pango_font_description_from_string("Monospace"); //gtk_widget_modify_font(text_area, font); // TODO - pango_font_description_free(font); + //pango_font_description_free(font); gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_area), 2); gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_area), 2); // add - 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, TRUE); // bind value UiText *value = var->value; @@ -160,25 +165,6 @@ free(textarea); } -UIWIDGET ui_textarea(UiObject *obj, UiText *value) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = value; - var->type = UI_VAR_SPECIAL; - var->from = NULL; - var->from_ctx = NULL; - return ui_textarea_var(obj, var); -} - -UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_TEXT); - if(var) { - return ui_textarea_var(obj, var); - } else { - // TODO: error - } - return NULL; -} - UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea) { return SCROLLEDWINDOW_GET_CHILD(textarea); } @@ -571,8 +557,8 @@ gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE); } - UiContainer *ct = uic_get_current_container(obj); - ct->add(ct, textfield, FALSE); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, textfield, FALSE); if(var) { UiString *value = var->value; diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/toolbar.c --- a/ui/gtk/toolbar.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/toolbar.c Sun Oct 20 21:24:13 2024 +0200 @@ -33,7 +33,7 @@ #include "toolbar.h" #include "menu.h" #include "button.h" -#include "image.h" +#include "icon.h" #include "list.h" #include #include diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/toolkit.c --- a/ui/gtk/toolkit.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/toolkit.c Sun Oct 20 21:24:13 2024 +0200 @@ -33,7 +33,7 @@ #include "toolkit.h" #include "toolbar.h" -#include "image.h" +#include "icon.h" #include "../common/document.h" #include "../common/properties.h" #include "../common/menu.h" diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/toolkit.h --- a/ui/gtk/toolkit.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/toolkit.h Sun Oct 20 21:24:13 2024 +0200 @@ -59,6 +59,8 @@ #define WINDOW_DESTROY(window) gtk_window_destroy(GTK_WINDOW(window)) #define WINDOW_SET_CONTENT(window, child) gtk_window_set_child(GTK_WINDOW(window), child) #define BOX_ADD(box, child) gtk_box_append(GTK_BOX(box), child) +#define BOX_ADD_EXPAND(box, child) gtk_widget_set_hexpand(child, TRUE); gtk_box_append(GTK_BOX(box), child) +#define BOX_ADD_NO_EXPAND(box, child) gtk_box_append(GTK_BOX(box), child) #define ENTRY_SET_TEXT(entry, text) gtk_editable_set_text(GTK_EDITABLE(entry), text) #define ENTRY_GET_TEXT(entry) gtk_editable_get_text(GTK_EDITABLE(entry)) #define SCROLLEDWINDOW_NEW() gtk_scrolled_window_new() @@ -70,7 +72,9 @@ #define WINDOW_SHOW(window) gtk_widget_show_all(window) #define WINDOW_DESTROY(window) gtk_widget_destroy(window) #define WINDOW_SET_CONTENT(window, child) gtk_container_add(GTK_CONTAINER(window), child) -#define BOX_ADD(box, child) gtk_box_pack_end(GTK_BOX(box), child, TRUE, TRUE, 0) +#define BOX_ADD(box, child) gtk_container_add(GTK_CONTAINER(box), child) +#define BOX_ADD_EXPAND(box, child) gtk_box_pack_end(GTK_BOX(box), child, TRUE, TRUE, 0) +#define BOX_ADD_NO_EXPAND(box, child) gtk_box_pack_end(GTK_BOX(box), child, TRUE, FALSE, 0) #define ENTRY_SET_TEXT(entry, text) gtk_entry_set_text(GTK_ENTRY(entry), text) #define ENTRY_GET_TEXT(entry) gtk_entry_get_text(GTK_ENTRY(entry)) #define SCROLLEDWINDOW_NEW() gtk_scrolled_window_new(NULL, NULL) diff -r 9c25e2616bfa -r e324291ca9f8 ui/gtk/window.c --- a/ui/gtk/window.c Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/gtk/window.c Sun Oct 20 21:24:13 2024 +0200 @@ -122,6 +122,7 @@ GtkWidget *headerbar = adw_header_bar_new(); adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar_view), headerbar); + g_object_set_data(G_OBJECT(obj->widget), "ui_headerbar", headerbar); if(!simple) { ui_fill_headerbar(obj, headerbar); @@ -167,7 +168,7 @@ obj->container = ui_box_container(obj, content_box); */ GtkWidget *content_box = ui_gtk_vbox_new(0); - BOX_ADD(GTK_BOX(vbox), content_box); + BOX_ADD_EXPAND(GTK_BOX(vbox), content_box); obj->container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX); nwindows++; diff -r 9c25e2616bfa -r e324291ca9f8 ui/ui/container.h --- a/ui/ui/container.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/ui/container.h Sun Oct 20 21:24:13 2024 +0200 @@ -50,6 +50,12 @@ UI_TABVIEW_INVISIBLE } UiTabViewType; +typedef enum UiHeaderbarAlternative { + UI_HEADERBAR_ALTERNATIVE_DEFAULT = 0, + UI_HEADERBAR_ALTERNATIVE_TOOLBAR, + UI_HEADERBAR_ALTERNATIVE_BOX +} UiHeaderbarAlternative; + typedef struct UiContainerArgs { UiTri fill; UiBool hexpand; @@ -97,6 +103,9 @@ UiTabViewType tabview; UiSubContainerType subcontainer; + + UiInteger *value; + const char* varname; int margin; int spacing; @@ -107,6 +116,22 @@ UiBool isexpanded; } UiTabViewArgs; +typedef struct UiHeaderbarArgs { + UiTri fill; + UiBool hexpand; + UiBool vexpand; + int colspan; + int rowspan; + const char *name; + const char *style_class; + + UiBool showtitle; + UiBool showwindowbuttons; + + UiHeaderbarAlternative alternative; + int alt_spacing; +} UiHeaderbarArgs; + #define UI_CTN(obj, ctn) for(ctn;ui_container_finish(obj);ui_container_begin_close(obj)) @@ -118,6 +143,7 @@ #define ui_expander(obj, ...) for(ui_expander_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_scrolledwindow(obj, ...) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_tabview(obj, ...) for(ui_tabview_create(obj, (UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_headerbar(obj, ...) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_vbox0(obj) for(ui_vbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_hbox0(obj) for(ui_hbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) @@ -126,31 +152,42 @@ #define ui_expander0(obj) for(ui_expande_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_scrolledwindow0(obj) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_tabview0(obj) for(ui_tabview_create(obj, (UiTabViewArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_headerbar0(obj) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_tab(obj, label) for(ui_tab_create(obj, label);ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_headerbar_start(obj) for(ui_headerbar_start_create(obj);ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_headerbar_center(obj) for(ui_headerbar_center_create(obj);ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_headerbar_end(obj) for(ui_headerbar_end_create(obj);ui_container_finish(obj);ui_container_begin_close(obj)) + UIEXPORT void ui_end(UiObject *obj); UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args); UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args); UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args); -UIEXPORT UIWIDGET ui_frame_create(UiObject* obj, UiFrameArgs args); -UIEXPORT UIWIDGET ui_expander_create(UiObject* obj, UiFrameArgs args); -UIEXPORT UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args); -UIEXPORT UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args); +UIEXPORT UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args); +UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args); +UIEXPORT UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs args); -UIEXPORT void ui_tab_create(UiObject* obj, const char* title); - -UIEXPORT UIWIDGET ui_scrolledwindow_deprecated(UiObject *obj); +UIEXPORT UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs args); +UIEXPORT void ui_tab_create(UiObject *obj, const char* title); +UIEXPORT void ui_tabview_select(UIWIDGET tabview, int tab); +UIEXPORT void ui_tabview_remove(UIWIDGET tabview, int tab); +UIEXPORT UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index); -UIEXPORT UIWIDGET ui_sidebar(UiObject *obj); +UIEXPORT UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args); +UIEXPORT void ui_headerbar_start_create(UiObject *obj); +UIEXPORT void ui_headerbar_center_create(UiObject *obj); +UIEXPORT void ui_headerbar_end_create(UiObject *obj); + -UIEXPORT UIWIDGET ui_hsplitpane(UiObject *obj, int max); -UIEXPORT UIWIDGET ui_vsplitpane(UiObject *obj, int max); +UIEXPORT UIWIDGET ui_scrolledwindow_deprecated(UiObject *obj); // TODO + +UIEXPORT UIWIDGET ui_sidebar(UiObject *obj); // TODO -UIEXPORT UIWIDGET ui_tabview_deprecated(UiObject *obj); +UIEXPORT UIWIDGET ui_hsplitpane(UiObject *obj, int max); // TODO +UIEXPORT UIWIDGET ui_vsplitpane(UiObject *obj, int max); // TODO -UIEXPORT void ui_select_tab(UIWIDGET tabview, int tab); // box container layout functions UIEXPORT void ui_layout_fill(UiObject *obj, UiBool fill); @@ -163,9 +200,8 @@ UIEXPORT void ui_layout_rowspan(UiObject* obj, int rows); UIEXPORT void ui_newline(UiObject *obj); - +// TODO UIEXPORT UiTabbedPane* ui_tabbed_document_view(UiObject *obj); - UIEXPORT UiObject* ui_document_tab(UiTabbedPane *view); diff -r 9c25e2616bfa -r e324291ca9f8 ui/ui/icons.h --- a/ui/ui/icons.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/ui/icons.h Sun Oct 20 21:24:13 2024 +0200 @@ -70,6 +70,15 @@ #define UI_ICON_GO_FORWARD "Forward" #endif /* UI_WINUI */ + + +UIEXPORT UiIcon* ui_icon(const char* name, size_t size); +UIEXPORT UiIcon* ui_icon_unscaled(const char *name, int size); +UIEXPORT UiIcon* ui_imageicon(const char* file); +UIEXPORT void ui_icon_free(UiIcon* icon); + +UIEXPORT UiIcon* ui_foldericon(size_t size); +UIEXPORT UiIcon* ui_fileicon(size_t size); #ifdef __cplusplus diff -r 9c25e2616bfa -r e324291ca9f8 ui/ui/image.h --- a/ui/ui/image.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/ui/image.h Sun Oct 20 21:24:13 2024 +0200 @@ -35,24 +35,28 @@ extern "C" { #endif - /* -UIEXPORT UiIcon* ui_icon(const char* name, size_t size); -UIEXPORT UiIcon* ui_imageicon(const char* file); -UIEXPORT void ui_icon_free(UiIcon* icon); -*/ +#define UI_IMAGE_OBJECT_TYPE "image" + +typedef struct UiImageViewerArgs { + UiTri fill; + UiBool hexpand; + UiBool vexpand; + int colspan; + int rowspan; + const char *name; + const char *style_class; -/* -UiIcon* ui_icon(const char *name, int size); -UiIcon* ui_icon_unscaled(const char *name, int size); -void ui_free_icon(UiIcon *icon); + UiBool scrollarea; + UiBool autoscale; + UiGeneric *value; + const char *varname; +} UiImageViewerArgs; + +#define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, (UiImageViewerArgs){ __VA_ARGS__ } ) + +UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args); -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); -*/ - +int ui_image_load_file(UiGeneric *obj, const char *path); #ifdef __cplusplus } diff -r 9c25e2616bfa -r e324291ca9f8 ui/ui/properties.h --- a/ui/ui/properties.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/ui/properties.h Sun Oct 20 21:24:13 2024 +0200 @@ -36,9 +36,6 @@ #endif typedef struct CxMap UiProperties; - -char* ui_getappdir(); -char* ui_configfile(char *name); char* ui_get_property(char *name); void ui_set_property(char *name, char *value); diff -r 9c25e2616bfa -r e324291ca9f8 ui/ui/text.h --- a/ui/ui/text.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/ui/text.h Sun Oct 20 21:24:13 2024 +0200 @@ -35,6 +35,22 @@ extern "C" { #endif +typedef struct UiTextAreaArgs { + UiTri fill; + UiBool hexpand; + UiBool vexpand; + int colspan; + int rowspan; + int width; + const char *name; + const char *style_class; + + UiText *value; + const char *varname; + ui_callback onchange; + void *onchangedata; +} UiTextAreaArgs; + typedef struct UiTextFieldArgs { UiTri fill; UiBool hexpand; @@ -46,19 +62,19 @@ const char *style_class; UiString* value; - const char* varname; + const char *varname; ui_callback onchange; - void* onchangedata; + void *onchangedata; } UiTextFieldArgs; typedef struct UiPathElmRet { - char* name; + char *name; size_t name_len; - char* path; + char *path; size_t path_len; } UiPathElm; -typedef UiPathElm*(*ui_pathelm_func)(const char *full_path, size_t len, size_t *ret_nelm, void* data); +typedef UiPathElm*(*ui_pathelm_func)(const char *full_path, size_t len, size_t *ret_nelm, void *data); @@ -72,24 +88,25 @@ const char *style_class; UiString *value; - const char* varname; + const char *varname; ui_pathelm_func getpathelm; - void* getpathelmdata; + void *getpathelmdata; ui_callback onactivate; - void* onactivatedata; + void *onactivatedata; ui_callback ondragstart; - void* ondragstartdata; + void *ondragstartdata; ui_callback ondragcomplete; - void* ondragcompletedata; + void *ondragcompletedata; ui_callback ondrop; - void* ondropsdata; + void *ondropsdata; } UiPathTextFieldArgs; -UIWIDGET ui_textarea_deprecated(UiObject *obj, UiText *value); -UIWIDGET ui_textarea_nv_deprecated(UiObject *obj, char *varname); +#define ui_textarea(obj, ...) ui_textarea_create(obj, (UiTextAreaArgs) { __VA_ARGS__ }) + +UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args); UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea); diff -r 9c25e2616bfa -r e324291ca9f8 ui/ui/toolkit.h --- a/ui/ui/toolkit.h Sun Oct 06 18:43:06 2024 +0200 +++ b/ui/ui/toolkit.h Sun Oct 20 21:24:13 2024 +0200 @@ -163,6 +163,7 @@ typedef struct UiText UiText; typedef struct UiList UiList; typedef struct UiRange UiRange; +typedef struct UiGeneric UiGeneric; typedef struct UiStr UiStr; @@ -324,6 +325,17 @@ // TODO: replacefunc, ... UiObserver *observers; }; + +struct UiGeneric { + void* (*get)(UiGeneric*); + const char* (*get_type)(UiGeneric*); + int (*set)(UiGeneric*, void *, const char *type); + void *obj; + + void *value; + const char *type; + UiObserver *observers; +}; /* * abstract list @@ -435,6 +447,7 @@ UIEXPORT void ui_unset_group(UiContext *ctx, int group); UIEXPORT int* ui_active_groups(UiContext *ctx, int *ngroups); +UIEXPORT void *ui_ctx_allocator(UiContext *ctx); UIEXPORT void* ui_malloc(UiContext *ctx, size_t size); UIEXPORT void* ui_calloc(UiContext *ctx, size_t nelem, size_t elsize); UIEXPORT void ui_free(UiContext *ctx, void *ptr); @@ -447,6 +460,7 @@ UIEXPORT UiString* ui_string_new(UiContext *ctx, char *name); UIEXPORT UiText* ui_text_new(UiContext *ctx, char *name); UIEXPORT UiRange* ui_range_new(UiContext *ctx, char *name); +UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, char *name); #define ui_get(v) _Generic(v, \ UiInteger*: ui_int_get, \ @@ -469,6 +483,12 @@ UIEXPORT void ui_text_set(UiText *s, const char* value); UIEXPORT char* ui_text_get(UiText *s); +UIEXPORT void ui_var_set_int(UiContext *ctx, const char *name, int64_t value); +UIEXPORT int64_t ui_var_get_int(UiContext *ctx, const char *name); +UIEXPORT void ui_var_set_double(UiContext *ctx, const char *name, double value); +UIEXPORT double ui_var_get_double(UiContext *ctx, const char *name); +UIEXPORT void ui_var_set_string(UiContext *ctx, const char *name, char *value); +UIEXPORT char* ui_var_get_string(UiContext *ctx, const char *name); UIEXPORT UiObserver* ui_observer_new(ui_callback f, void *data); UIEXPORT UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer); @@ -509,18 +529,14 @@ UIEXPORT void ui_listselection_free(UiListSelection selection); -UIEXPORT UiIcon* ui_icon(const char* name, size_t size); -UIEXPORT UiIcon* ui_icon_unscaled(const char *name, int size); -UIEXPORT UiIcon* ui_imageicon(const char* file); -UIEXPORT void ui_icon_free(UiIcon* icon); - -UIEXPORT UiIcon* ui_foldericon(size_t size); -UIEXPORT UiIcon* ui_fileicon(size_t size); - UIEXPORT UiStr ui_str(char *cstr); UIEXPORT UiStr ui_str_free(char *str, void (*free)(void *v)); + +UIEXPORT char* ui_getappdir(); +UIEXPORT char* ui_configfile(char *name); + #ifdef __cplusplus } #endif