# HG changeset patch # User Olaf Wintermann # Date 1395404453 -3600 # Node ID eeb50c53449718f767a9fa98529abaa8c83e0945 # Parent eb5269000bc88604ebf2ae6a40424ba94efd6ad1 added support for replaceable documents diff -r eb5269000bc8 -r eeb50c534497 application/main.c --- a/application/main.c Sun Dec 08 11:20:41 2013 +0000 +++ b/application/main.c Fri Mar 21 13:20:53 2014 +0100 @@ -31,6 +31,15 @@ #include +typedef struct TestDocument { + UiInteger check1; +} TestDocument; + +typedef struct TestWindowData { + TestDocument *doc1; + TestDocument *doc2; +} TestWindowData; + UiInteger check1; void action_new(UiEvent *event, void *data) { @@ -40,13 +49,29 @@ } void action_open(UiEvent *event, void *data) { - printf("check1: %s\n", ui_window_getint(event->obj, "check1") ? "true" : "false"); + //printf("check1: %s\n", ui_getint(event->obj, "check1") ? "true" : "false"); + TestDocument *doc = event->document; + printf("check1: %s\n", ui_getval(doc->check1) ? "true" : "false"); } void action_close(UiEvent *event, void *data) { exit(0); } +void action_doc1(UiEvent *event, void *data) { + TestWindowData *wdata = event->window; + if(event->obj->document != wdata->doc1) { + ui_set_document(event->obj, wdata->doc1); + } +} + +void action_doc2(UiEvent *event, void *data) { + TestWindowData *wdata = event->window; + if(event->obj->document != wdata->doc2) { + ui_set_document(event->obj, wdata->doc2); + } +} + int main(int argc, char** argv) { ui_init("app1", argc, argv); @@ -54,12 +79,24 @@ ui_menuitem("New", action_new, NULL); ui_menuitem("Open", action_open, NULL); ui_menuseparator(); + ui_menuitem("Dokument 1", action_doc1, NULL); + ui_menuitem("Dokument 2", action_doc2, NULL); + ui_menuseparator(); ui_checkitem_nv("Check", "check1"); ui_menuitem("Close", action_close, NULL); UiObject *window = ui_window("Mod0", NULL); + TestWindowData *wdata = malloc(sizeof(TestWindowData)); + window->window = wdata; + TestDocument *doc1 = ui_document_new(sizeof(TestDocument)); + TestDocument *doc2 = ui_document_new(sizeof(TestDocument)); + ui_document_regint(doc1, "check1", &doc1->check1); + ui_document_regint(doc2, "check1", &doc2->check1); + wdata->doc1 = doc1; + wdata->doc2 = doc2; + ui_set_document(window, doc1); //ui_window_addint(window, "check1"); ui_show(window); diff -r eb5269000bc8 -r eeb50c534497 ucx/mempool.c --- a/ucx/mempool.c Sun Dec 08 11:20:41 2013 +0000 +++ b/ucx/mempool.c Fri Mar 21 13:20:53 2014 +0100 @@ -75,6 +75,20 @@ pool->ndata = 0; pool->size = n; + + UcxAllocator *allocator = (UcxAllocator*)malloc(sizeof(UcxAllocator)); + if(!allocator) { + free(pool->data); + free(pool); + return NULL; + } + allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; + allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; + allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; + allocator->free = (ucx_allocator_free)ucx_mempool_free; + allocator->pool = pool; + pool->allocator = allocator; + return pool; } @@ -173,6 +187,7 @@ } } free(pool->data); + free(pool->allocator); free(pool); } @@ -189,16 +204,3 @@ ucx_mempool_set_destr(rd, ucx_mempool_shared_destr); } -UcxAllocator* ucx_mempool_allocator(UcxMempool *pool) { - UcxAllocator *allocator = (UcxAllocator*)ucx_mempool_malloc( - pool, sizeof(UcxAllocator)); - if(!allocator) { - return NULL; - } - allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; - allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; - allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; - allocator->free = (ucx_allocator_free)ucx_mempool_free; - allocator->pool = pool; - return allocator; -} diff -r eb5269000bc8 -r eeb50c534497 ucx/mempool.h --- a/ucx/mempool.h Sun Dec 08 11:20:41 2013 +0000 +++ b/ucx/mempool.h Fri Mar 21 13:20:53 2014 +0100 @@ -57,14 +57,17 @@ * UCX mempool structure. */ typedef struct { + /** UcxAllocator based on this pool */ + UcxAllocator *allocator; + /** List of pointers to pooled memory. */ - void **data; + void **data; /** Count of pooled memory items. */ - size_t ndata; + size_t ndata; /** Memory pool size. */ - size_t size; + size_t size; } UcxMempool; /** Shorthand for a new default memory pool with a capacity of 16 elements. */ @@ -210,14 +213,6 @@ */ void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); -/** - * Creates an UcxAllocator based on an UcxMempool. - * - * @param pool the mempool to create the UcxAllocator for - * @return a new UcxAllocator based on the specified pool - */ -UcxAllocator* ucx_mempool_allocator(UcxMempool *pool); - #ifdef __cplusplus } #endif diff -r eb5269000bc8 -r eeb50c534497 ui/common/context.c --- a/ui/common/context.c Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/common/context.c Fri Mar 21 13:20:53 2014 +0100 @@ -32,80 +32,117 @@ #include "context.h" #include "../ui/window.h" +#include "document.h" UiContext* uic_context(UiObject *toplevel, UcxMempool *mp) { UiContext *ctx = ucx_mempool_malloc(mp, sizeof(UiContext)); - UcxAllocator *allocator = ucx_mempool_allocator(mp); ctx->mempool = mp; - ctx->allocator = allocator; ctx->toplevel = toplevel; - ctx->vars = ucx_map_new_a(allocator, 16); + ctx->vars = ucx_map_new_a(mp->allocator, 16); return ctx; } -UiVar* uic_getvar(UiObject *obj, char *name) { - if(!obj) { - return NULL; +UiVar* uic_getvar(UiContext *ctx, char *name) { + // check document variables first + UiVar *var = uic_document_getvar( + uic_getdocument(ctx->toplevel->document), + name); + // check window vars + if(!var) { + var = ucx_map_cstr_get(ctx->vars, name); } - return ucx_map_cstr_get(obj->ctx->vars, name); + + return var; } -void uic_rmvar(UiObject *obj, char *name) { - if(obj) { - UiVar *var = uic_getvar(obj, name); - if(var) { - if(var->isextern) { - ucx_mempool_free(obj->ctx->mempool, var->value); - } - ucx_mempool_free(obj->ctx->mempool, var); +UiVar* uic_connect_var(UiContext *ctx, char *name, int type) { + // TODO: get current map + UcxMap *from = ctx->vars; + + UiVar *var = uic_getvar(ctx, name); + if(var) { + // the value is registered + + // a little type check + if(var->type != type) { + fprintf(stderr, "UI Error: var %s has incompatible type.\n", name); + return NULL; + } else { + // register the current document/wdata map + // if the document is closed, the var will be moved to this map + + // TODO: get current map + var->from = from; + + return var; } + } else { + // create an empty value and add it first to the window variables + // it can be moved to the document vars later + void *value = uic_create_value(ctx->mempool->allocator, type); + if(!value) { + fprintf(stderr, "UI Error: Cannot create empty value.\n"); + return NULL; + } + UiVar *var = ucx_mempool_malloc(ctx->mempool, sizeof(UiVar)); + var->value = value; + var->type = type; + var->isextern = 0; + var->from = from; + ucx_map_cstr_put(ctx->vars, name, var); + return var; } } -void ui_window_addint(UiObject *obj, char *name) { - if(uic_getvar(obj, name)) { - // var already exists - return; +void* uic_create_value(UcxAllocator *a, int type) { + switch(type) { + case UI_VAR_INTEGER: { + UiInteger *i = a->calloc( + a->pool, + 1, + sizeof(UiInteger)); + return i; + } + case UI_VAR_STRING: { + UiString *s = a->calloc( + a->pool, + 1, + sizeof(UiInteger)); + return s; + } } - UiInteger *i = ucx_mempool_calloc(obj->ctx->mempool, 1, sizeof(UiInteger)); - UiVar *var = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiVar)); - var->value = i; - var->type = 1; - var->isextern = 0; - ucx_map_cstr_put(obj->ctx->vars, name, var); + return NULL; } -void ui_window_regint(UiObject *obj, char *name, UiInteger *i) { - if(uic_getvar(obj, name)) { - // var already exists - return; + + +// public API + +int ui_getint(UiObject *obj, char *name) { + UiVar *var = uic_getvar(obj->ctx, name); + if(var) { + if(var->type == UI_VAR_INTEGER) { + UiInteger *i = var->value; + if(i->get) { + return i->get(i); + } else { + fprintf( + stderr, + "UI Error: variable %s is not connected.\n", + name); + } + } else { + fprintf( + stderr, + "UI Error: requested variable %s is not an integer.\n", + name); + } + } else { + fprintf(stderr, "UI Error: unkown variable %s.\n", name); } - UiVar *var = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiVar)); - var->value = i; - var->type = 1; - var->isextern = 1; - ucx_map_cstr_put(obj->ctx->vars, name, var); + return 0; } -void ui_window_setint(UiObject *obj, char *name, int val) { - UiVar *var = uic_getvar(obj, name); - if(var && var->type == 1) { - UiInteger *i = var->value; - i->set(i, val); - } else { - // TODO: error message - } -} - -int ui_window_getint(UiObject *obj, char *name) { - UiVar *var = uic_getvar(obj, name); - if(var && var->type == 1) { - UiInteger *i = var->value; - return i->get(i); - } else { - return 0; // TODO: error message - } -} diff -r eb5269000bc8 -r eeb50c534497 ui/common/context.h --- a/ui/common/context.h Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/common/context.h Fri Mar 21 13:20:53 2014 +0100 @@ -42,20 +42,25 @@ struct UiContext { UiObject *toplevel; UcxMempool *mempool; - UcxAllocator *allocator; UcxMap *vars; // key: char* value: UiVar* }; struct UiVar { - void *value; - int type; - int isextern; + void *value; + int type; + int isextern; + UcxMap *from; +}; + +enum UiVarType { + UI_VAR_INTEGER = 0, + UI_VAR_STRING }; UiContext* uic_context(UiObject *toplevel, UcxMempool *mp); - -UiVar* uic_getvar(UiObject *obj, char *name); -void uic_rmvar(UiObject *obj, char *name); +UiVar* uic_getvar(UiContext *ctx, char *name); +UiVar* uic_connect_var(UiContext *ctx, char *name, int type); +void* uic_create_value(UcxAllocator *a, int type); #ifdef __cplusplus diff -r eb5269000bc8 -r eeb50c534497 ui/common/document.c --- a/ui/common/document.c Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/common/document.c Fri Mar 21 13:20:53 2014 +0100 @@ -38,13 +38,82 @@ documents = ucx_map_new(32); } -void* ui_document_create(UiObject *obj, size_t size) { +void ui_set_document(UiObject *obj, void *document) { + UiDocument *doc = ucx_map_get(documents, ucx_key(&document, sizeof(void*))); + if(!doc) { + return; + } + doc->obj = obj; + + if(obj->document) { + ui_detach_document(obj, obj->document); + } + obj->document = document; + + UcxMapIterator i = ucx_map_iterator(doc->vars); + UiVar *var; + UCX_MAP_FOREACH(key, var, i) { + UiVar *v = ucx_map_get(obj->ctx->vars, key); + if(v) { + if(v->isextern) { + fprintf( + stderr, + "UI Error: external variable cannot be moved\n"); + return; + } + // check type + if(var->type != v->type) { + fprintf(stderr, "UI Error: var has incompatible type.\n"); + return; + } + + // copy value + uic_var_move(v, var, 1); + var->from = v->from; + + // TODO: free var struct + ucx_map_remove(obj->ctx->vars, key); + } + } + +} + +void ui_detach_document(UiObject *obj, void *document) { + UiDocument *doc = ucx_map_get(documents, ucx_key(&document, sizeof(void*))); + if(!doc) { + return; + } + + UcxMapIterator i = ucx_map_iterator(doc->vars); + UiVar *var; + UCX_MAP_FOREACH(key, var, i) { + if(var->from && var->from != doc->vars) { + // this var is bind to an outer widget, so we move it + UcxAllocator *a = var->from->allocator; + UiVar *newvar = a->malloc(a->pool, sizeof(UiVar)); + newvar->value = uic_create_value(a, var->type); + uic_var_move(var, newvar, 0); + newvar->type = var->type; + newvar->from = var->from; + newvar->isextern = 0; + + ucx_map_put(var->from, key, newvar); + + //ucx_map_remove(doc->vars, key); // TODO: dont remove! + } + } + + doc->obj->document = NULL; + doc->obj = NULL; +} + +void* ui_document_new(size_t size) { UcxMempool *mp = ucx_mempool_new(256); UiDocument *uidoc = ucx_mempool_malloc(mp, sizeof(UiDocument)); - uidoc->obj = obj; - uidoc->allocator = ucx_mempool_allocator(mp); + uidoc->obj = NULL; uidoc->mempool = mp; - uidoc->vars = ucx_map_new_a(uidoc->allocator, 16); + uidoc->vars = ucx_map_new_a(mp->allocator, 16); + uidoc->subdocument = NULL; void *document = ucx_mempool_calloc(mp, 1, size); ucx_map_put(documents, ucx_key(&document, sizeof(void*)), uidoc); @@ -75,43 +144,119 @@ return ucx_mempool_realloc(uidoc->mempool, ptr, size); } +UiDocument* uic_getdocument(void *doc) { + return doc ? ucx_map_get(documents, ucx_key(&doc, sizeof(void*))) : NULL; +} UiVar* uic_document_getvar(UiDocument *doc, char *name) { - return ucx_map_cstr_get(doc->vars, name); + return doc ? ucx_map_cstr_get(doc->vars, name) : NULL; } -void ui_document_addint(void *doc, char *name) { +void uic_document_addvar(void *doc, char *name, int type, size_t vs) { UiDocument *uidoc = ucx_map_get(documents, ucx_key(&doc, sizeof(void*))); if(!uidoc) { return; } - UiVar *dvar = uic_document_getvar(uidoc, name); - UiVar *wvar = uic_getvar(uidoc->obj, name); - if(!dvar) { - UiVar *var = ucx_mempool_malloc(uidoc->mempool, sizeof(UiVar)); - var->isextern = 0; - var->type = 1; - UiInteger *i = ucx_mempool_calloc(uidoc->mempool, 1, sizeof(UiVar)); - if(wvar && !wvar->isextern) { - *i = *(UiInteger*)wvar->value; + UiVar *newvar = ucx_mempool_malloc(uidoc->mempool, sizeof(UiVar)); + newvar->isextern = 0; + newvar->type = type; + newvar->value = ucx_mempool_calloc(uidoc->mempool, 1, vs); + newvar->from = NULL; + + uic_document_addvar_v(uidoc, name, newvar, type, vs); +} + +void uic_document_addvar_v( + UiDocument *uidoc, + char *name, + UiVar *newvar, + int type, + size_t vs) +{ + // if the window context has this variable, we remove it and put it to + // the document vars + UiVar *var = uidoc->obj ? + ucx_map_cstr_get(uidoc->obj->ctx->vars, name) : NULL; + if(var) { + // external variables cannot be moved + if(var->isextern) { + fprintf( + stderr, + "UI Error: external variable %s " + "cannot be moved to the document.\n", + name); + return; + } + + // check type + if(var->type != type) { + fprintf(stderr, "UI Error: var %s has incompatible type.\n", name); + return; + } + + // override document var with window context var + memcpy(newvar->value, var->value, vs); + + newvar->from = var->from; + + // TODO: free var struct + ucx_map_cstr_remove(uidoc->obj->ctx->vars, name); + } + + // finally, add the new variable to the document + ucx_map_cstr_put(uidoc->vars, name, newvar); +} + +void uic_document_regvar( + void *doc, + char *name, + int type, + size_t vs, + void *value) +{ + UiDocument *uidoc = ucx_map_get(documents, ucx_key(&doc, sizeof(void*))); + if(!uidoc) { + return; + } + + UiVar *newvar = ucx_mempool_malloc(uidoc->mempool, sizeof(UiVar)); + newvar->isextern = 1; + newvar->type = type; + newvar->value = value; + newvar->from = NULL; + + uic_document_addvar_v(uidoc, name, newvar, type, vs); +} + +void uic_var_move(UiVar *from, UiVar *to, int set) { + switch(from->type) { + case UI_VAR_INTEGER: { + //memcpy(to->value, from->value, sizeof(UiInteger)); + UiInteger *f = from->value; + UiInteger *t = to->value; + t->get = f->get; + t->set = f->set; + t->obj = f->obj; + if(set) { + t->set(t, t->value); + } else { + //t->value = t->get(t); + //t->value = 0; + } + break; + } + case UI_VAR_STRING: { + break; } } - - if(wvar && wvar->isextern) { - fprintf(stderr, "UI Error: window variable moved to document!\n"); - } - uic_rmvar(uidoc->obj, name); +} + +void ui_document_addint(void *doc, char *name) { + uic_document_addvar(doc, name, UI_VAR_INTEGER, sizeof(UiInteger)); } void ui_document_regint(void *doc, char *name, UiInteger *i) { - + uic_document_regvar(doc, name, UI_VAR_INTEGER, sizeof(UiInteger), i); } -void ui_document_setint(void *doc, char *name, int val) { - -} - -int ui_document_getint(void *doc, char *name) { - -} diff -r eb5269000bc8 -r eeb50c534497 ui/common/document.h --- a/ui/common/document.h Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/common/document.h Fri Mar 21 13:20:53 2014 +0100 @@ -41,12 +41,29 @@ struct UiDocument { UiObject *obj; UcxMempool *mempool; - UcxAllocator *allocator; UcxMap *vars; // key: char* value: UiVar* + void *subdocument; }; void uic_docmgr_init(); +UiDocument* uic_getdocument(void *doc); UiVar* uic_document_getvar(UiDocument *doc, char *name); +void uic_document_addvar(void *doc, char *name, int type, size_t vs); +void uic_document_addvar_v( + UiDocument *uidoc, + char *name, + UiVar *newvar, + int type, + size_t vs); +void uic_document_regvar( + void *doc, + char *name, + int type, + size_t vs, + void *value); + +void uic_var_move(UiVar *from, UiVar *to, int set); + #ifdef __cplusplus diff -r eb5269000bc8 -r eeb50c534497 ui/gtk/menu.c --- a/ui/gtk/menu.c Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/gtk/menu.c Fri Mar 21 13:20:53 2014 +0100 @@ -253,19 +253,15 @@ GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); - UiVar *var = uic_getvar(obj, ci->varname); - if(!var) { - ui_window_addint(obj, ci->varname); - var = uic_getvar(obj, ci->varname); - } - if(var->type == 1) { + UiVar *var = uic_connect_var(obj->ctx, ci->varname, UI_VAR_INTEGER); + if(var) { UiInteger *value = var->value; value->obj = widget; value->get = ui_checkitem_get; value->set = ui_checkitem_set; value = 0; } else { - // TODO: error message + // TODO: error } } @@ -275,7 +271,7 @@ UiEvent evt; evt.obj = event->obj; evt.window = event->obj->window; - evt.document = NULL; + evt.document = event->obj->document; evt.intval = 0; event->callback(&evt, event->user_data); } @@ -284,7 +280,7 @@ UiEvent evt; evt.obj = event->obj; evt.window = event->obj->window; - evt.document = NULL; + evt.document = event->obj->document; evt.intval = gtk_check_menu_item_get_active(ci); event->callback(&evt, event->user_data); } diff -r eb5269000bc8 -r eeb50c534497 ui/motif/menu.c --- a/ui/motif/menu.c Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/motif/menu.c Fri Mar 21 13:20:53 2014 +0100 @@ -278,19 +278,15 @@ 2); XmStringFree(label); - UiVar *var = uic_getvar(obj, ci->varname); - if(!var) { - ui_window_addint(obj, ci->varname); - var = uic_getvar(obj, ci->varname); - } - if(var->type == 1) { + UiVar *var = uic_connect_var(obj->ctx, ci->varname, UI_VAR_INTEGER); + if(var) { UiInteger *value = var->value; value->obj = checkbox; value->get = ui_toggle_button_get; value->set = ui_toggle_button_set; value = 0; } else { - // TODO: error message + // TODO: error } } @@ -300,7 +296,7 @@ UiEvent e; e.obj = event->obj; e.window = event->obj->window; - // TODO: e.document + e.document = event->obj->document; e.intval = 0; event->callback(&e, event->user_data); } diff -r eb5269000bc8 -r eeb50c534497 ui/motif/window.c --- a/ui/motif/window.c Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/motif/window.c Fri Mar 21 13:20:53 2014 +0100 @@ -89,7 +89,7 @@ NULL); obj->widget = window; ui_create_menubar(obj); - + obj->widget = toplevel; nwindows++; return obj; diff -r eb5269000bc8 -r eeb50c534497 ui/ui/toolkit.h --- a/ui/ui/toolkit.h Sun Dec 08 11:20:41 2013 +0000 +++ b/ui/ui/toolkit.h Fri Mar 21 13:20:53 2014 +0100 @@ -70,9 +70,24 @@ typedef void(*ui_callback)(UiEvent*, void*); // event, user data struct UiObject { + /* + * native widget + */ UIWIDGET widget; + + /* + * window context + */ UiContext *ctx; + + /* + * user window data + */ void *window; + + /* + * current document + */ void *document; }; @@ -106,7 +121,10 @@ void ui_main(); void ui_show(UiObject *obj); -void* ui_document_create(UiObject *obj, size_t size); +void ui_set_document(UiObject *obj, void *document); +void ui_detach_document(UiObject *obj, void *document); + +void* ui_document_new(size_t size); void ui_document_destroy(void *doc); void* ui_document_malloc(void *doc, size_t size); @@ -114,11 +132,16 @@ void ui_document_free(void *doc, void *ptr); void* ui_document_realloc(void *doc, void *ptr, size_t size); +// TODO: remove (or not) void ui_document_addint(void *doc, char *name); void ui_document_regint(void *doc, char *name, UiInteger *i); void ui_document_setint(void *doc, char *name, int val); int ui_document_getint(void *doc, char *name); +// new: +int ui_getint(UiObject *obj, char *name); + + #ifdef __cplusplus }