--- a/ui/common/context.c Mon Nov 17 11:28:47 2025 +0100 +++ b/ui/common/context.c Mon Nov 17 14:27:48 2025 +0100 @@ -114,7 +114,7 @@ UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key); if(docvar) { // bind var to document var - uic_copy_binding(var, docvar, TRUE); + uic_copy_var_binding(var, docvar, TRUE); cxIteratorFlagRemoval(i); } } @@ -130,7 +130,7 @@ // var->from && var->from_ctx && var->from_ctx != ctx uic_save_var(var); if(var->from) { - uic_copy_binding(var, var->from, FALSE); + uic_copy_var_binding(var, var->from, FALSE); cxMapPut(var->from->from_ctx->vars, *entry->key, var->from); var->from = NULL; } @@ -213,7 +213,8 @@ var->original_value = NULL; var->from = NULL; var->from_ctx = ctx; - + var->bound = FALSE; + cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var); cxMapPut(ctx->vars, name, var); @@ -266,6 +267,40 @@ return val; } +// destroys a value, that was created by uic_create_value +void uic_destroy_value(UiContext *ctx, UiVarType type, void *value) { + switch(type) { + default: { + ui_free(ctx, value); + break; + } + case UI_VAR_SPECIAL: break; + case UI_VAR_STRING: { + UiString *s = value; + if(s->value.free) { + s->value.free(s->value.ptr); + } + ui_free(ctx, value); + } + case UI_VAR_TEXT: { + UiText *t = value; + if(t->value.free) { + t->value.free(t->value.ptr); + t->value.free = NULL; + t->value.ptr = NULL; + } + if(t->destroy) { + t->destroy(t); + } + ui_free(ctx, value); + } + case UI_VAR_LIST: { + ui_list_free(ctx, value); + break; + } + } +} + UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type) { if (value) { @@ -278,7 +313,7 @@ } -void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) { +void uic_copy_var_binding(UiVar *from, UiVar *to, UiBool copytodoc) { // check type if(from->type != to->type) { fprintf(stderr, "UI Error: var has incompatible type.\n"); @@ -301,32 +336,36 @@ } } - ui_setop_enable(TRUE); + uic_copy_value_binding(from->type, from, to); +} + +void uic_copy_value_binding(UiVarType type, void *from, void *to) { + ui_setop_enable(TRUE); // copy binding - // we don't copy the observer, because the from var has never one - switch(from->type) { + // we don't copy the observer, because the from value never has oberservers + switch(type) { default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break; case UI_VAR_SPECIAL: break; case UI_VAR_INTEGER: { - UiInteger *f = fromvalue; - UiInteger *t = tovalue; + UiInteger *f = from; + UiInteger *t = to; if(!f->obj) break; uic_int_copy(f, t); t->set(t, t->value); break; } case UI_VAR_DOUBLE: { - UiDouble *f = fromvalue; - UiDouble *t = tovalue; + UiDouble *f = from; + UiDouble *t = to; if(!f->obj) break; uic_double_copy(f, t); t->set(t, t->value); break; } case UI_VAR_STRING: { - UiString *f = fromvalue; - UiString *t = tovalue; + UiString *f = from; + UiString *t = to; if(!f->obj) break; uic_string_copy(f, t); char *tvalue = t->value.ptr ? t->value.ptr : ""; @@ -335,23 +374,23 @@ break; } case UI_VAR_TEXT: { - UiText *f = fromvalue; - UiText *t = tovalue; + UiText *f = from; + UiText *t = to; if(!f->obj) break; uic_text_copy(f, t); t->restore(t); break; } case UI_VAR_LIST: { - UiList *f = fromvalue; - UiList *t = tovalue; + UiList *f = from; + UiList *t = to; uic_list_copy(f, t); ui_list_update(t); break; } case UI_VAR_RANGE: { - UiRange *f = fromvalue; - UiRange *t = tovalue; + UiRange *f = from; + UiRange *t = to; if(!f->obj) break; uic_range_copy(f, t); t->setextent(t, t->extent); @@ -360,8 +399,8 @@ break; } case UI_VAR_GENERIC: { - UiGeneric *f = fromvalue; - UiGeneric *t = tovalue; + UiGeneric *f = from; + UiGeneric *t = to; if(!f->obj) break; uic_generic_copy(f, t); t->set(t, t->value, t->type); @@ -398,58 +437,47 @@ } } +const char *uic_type2str(UiVarType type) { + switch(type) { + default: return ""; + case UI_VAR_INTEGER: return "int"; + case UI_VAR_DOUBLE: return "double"; + case UI_VAR_STRING: return "string"; + case UI_VAR_TEXT: return "text"; + case UI_VAR_LIST: return "list"; + case UI_VAR_RANGE: return "range"; + case UI_VAR_GENERIC: return "generic"; + } +} + void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) { - // TODO: do we need/want this? Why adding vars to a context after - // widgets reference these? Workarounds: - // 1. add vars to ctx before creating ui - // 2. create ui, create new document with vars, attach doc - // also it would be possible to create a function, that scans unbound vars - // and connects them to available vars - /* - UiContext *rootctx = uic_root_context(ctx); - UiVar *b = NULL; - if(rootctx->bound) { - // some widgets are already bound to some vars - b = ucx_map_cstr_get(rootctx->bound, name); - if(b) { - // a widget is bound to a var with this name - // if ctx is the root context we can remove the var from bound - // because set_doc or detach can't fuck things up - if(ctx == rootctx) { - ucx_map_cstr_remove(ctx->bound, name); - // TODO: free stuff - } + UiVar *var = cxMapGet(ctx->vars, name); + if(!var) { + // create new var and add it to the context var map + var = ui_malloc(ctx, sizeof(UiVar)); + cxMapPut(ctx->vars, name, var); + } else { + // override var with new value + if(var->type != type) { + fprintf(stderr, "Error: var %s type mismatch: %s - %s\n", name, uic_type2str(var->type), type); + return; } + if(var->bound) { + fprintf(stderr, "Error: var %s already bound\n", name); + return; + } + UiInteger *prev_value = var->value; + uic_copy_value_binding(type, prev_value, value); + uic_destroy_value(var->from_ctx, var->type, var->value); } - */ - // create new var and add it to doc's vars - UiVar *var = ui_malloc(ctx, sizeof(UiVar)); var->type = type; var->value = value; var->from = NULL; var->from_ctx = ctx; - size_t oldcount = cxMapSize(ctx->vars); - cxMapPut(ctx->vars, name, var); - if(cxMapSize(ctx->vars) != oldcount + 1) { - fprintf(stderr, "UiError: var '%s' already exists\n", name); - } - - // TODO: remove? - // a widget is already bound to a var with this name - // copy the binding (like uic_context_set_document) - /* - if(b) { - uic_copy_binding(b, var, TRUE); - } - */ + var->bound = TRUE; } -void uic_remove_bound_var(UiContext *ctx, UiVar *var) { - // TODO -} - - // public API void ui_attach_document(UiContext *ctx, void *document) {