diff -r b34bd1557c6c -r 77254bd6dccb ui/common/context.c --- a/ui/common/context.c Sat Apr 05 17:57:04 2025 +0200 +++ b/ui/common/context.c Sun Jul 20 22:04:39 2025 +0200 @@ -58,6 +58,7 @@ memset(ctx, 0, sizeof(UiContext)); ctx->mp = mp; ctx->allocator = mp->allocator; + ctx->destroy_handler = cxArrayListCreate(ctx->allocator, NULL, sizeof(UiDestroyHandler), 16); ctx->obj = toplevel; ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16); @@ -66,7 +67,7 @@ ctx->groups = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32); ctx->attach_document = uic_context_attach_document; - ctx->detach_document2 = uic_context_detach_document2; + ctx->detach_document2 = uic_context_detach_document; #if UI_GTK2 || UI_GTK3 if(toplevel && toplevel->widget) { @@ -82,6 +83,13 @@ return ctx->parent ? uic_root_context(ctx->parent) : ctx; } +void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data) { + UiDestroyHandler handler; + handler.destructor = func; + handler.data = data; + cxListAdd(ctx->destroy_handler, &handler); +} + void uic_context_prepare_close(UiContext *ctx) { cxListClear(ctx->groups); cxListClear(ctx->group_widgets); @@ -120,11 +128,12 @@ CxMapIterator mi = cxMapIterator(ctx->vars); cx_foreach(CxMapEntry*, entry, mi) { UiVar *var = entry->value; - if(var->from && var->from_ctx && var->from_ctx != ctx) { + // var->from && var->from_ctx && var->from_ctx != ctx + if(var->from) { uic_save_var2(var); uic_copy_binding(var, var->from, FALSE); - cxMapPut(var->from_ctx->vars_unbound, *entry->key, var->from); - var->from_ctx = ctx; + cxMapPut(var->from->from_ctx->vars_unbound, *entry->key, var->from); + var->from = NULL; } } @@ -137,7 +146,7 @@ } } -void uic_context_detach_document2(UiContext *ctx, void *document) { +void uic_context_detach_document(UiContext *ctx, void *document) { // find the document in the documents list size_t docIndex = cxListFind(ctx->documents, document); if(!cxListIndexValid(ctx->documents, docIndex)) { @@ -209,6 +218,7 @@ var = ui_malloc(ctx, sizeof(UiVar)); var->type = type; var->value = uic_create_value(ctx, type); + var->original_value = NULL; var->from = NULL; var->from_ctx = ctx; @@ -227,6 +237,7 @@ var->from = NULL; var->from_ctx = ctx; var->value = value; + var->original_value = NULL; var->type = UI_VAR_SPECIAL; return var; } @@ -286,10 +297,19 @@ } void *fromvalue = from->value; + void *tovalue = to->value; // update var if(copytodoc) { - to->from = from; - to->from_ctx = from->from_ctx; + to->from = from; // from which UiVar are the bindings copied + from->original_value = fromvalue; // save original value otherwise it would be lost + // widgets store a reference to the UiVar with their value + // the UiVar object must be updated to contain the current value object + from->value = tovalue; + } else { + if(to->original_value) { + to->value = to->original_value; + tovalue = to->value; + } } ui_setop_enable(TRUE); @@ -301,7 +321,7 @@ case UI_VAR_SPECIAL: break; case UI_VAR_INTEGER: { UiInteger *f = fromvalue; - UiInteger *t = to->value; + UiInteger *t = tovalue; if(!f->obj) break; uic_int_copy(f, t); t->set(t, t->value); @@ -309,7 +329,7 @@ } case UI_VAR_DOUBLE: { UiDouble *f = fromvalue; - UiDouble *t = to->value; + UiDouble *t = tovalue; if(!f->obj) break; uic_double_copy(f, t); t->set(t, t->value); @@ -317,48 +337,32 @@ } case UI_VAR_STRING: { UiString *f = fromvalue; - UiString *t = to->value; + UiString *t = tovalue; if(!f->obj) break; uic_string_copy(f, t); char *tvalue = t->value.ptr ? t->value.ptr : ""; + char *fvalue = f->value.ptr ? f->value.ptr : ""; t->set(t, tvalue); break; } case UI_VAR_TEXT: { UiText *f = fromvalue; - UiText *t = to->value; + UiText *t = tovalue; if(!f->obj) break; uic_text_copy(f, t); t->restore(t); break; } - case UI_VAR_LIST: { - // TODO: not sure how correct this is - - UiList *f = from->value; - UiList *t = to->value; - if (f->obj) { - t->obj = f->obj; - t->update = f->update; - t->getselection = f->getselection; - t->setselection = f->setselection; - } - - UiVar tmp = *from; - *from = *to; - *to = tmp; - - UiList* t2 = to->value; - if(t->update) { - t->update(t, -1); - } - ui_notify(t2->observers, NULL); // TODO: why not t? - + case UI_VAR_LIST: { + UiList *f = fromvalue; + UiList *t = tovalue; + uic_list_copy(f, t); + ui_list_update(t); break; } case UI_VAR_RANGE: { UiRange *f = fromvalue; - UiRange *t = to->value; + UiRange *t = tovalue; if(!f->obj) break; uic_range_copy(f, t); t->setextent(t, t->extent); @@ -368,7 +372,7 @@ } case UI_VAR_GENERIC: { UiGeneric *f = fromvalue; - UiGeneric *t = to->value; + UiGeneric *t = tovalue; if(!f->obj) break; uic_generic_copy(f, t); t->set(t, t->value, t->type); @@ -405,7 +409,7 @@ } } -void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value) { +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 @@ -463,8 +467,8 @@ uic_context_attach_document(ctx, document); } -void ui_detach_document2(UiContext *ctx, void *document) { - uic_context_detach_document2(ctx, document); +void ui_detach_document(UiContext *ctx, void *document) { + uic_context_detach_document(ctx, document); } void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) { @@ -472,10 +476,18 @@ ctx->close_data = udata; } -UIEXPORT void ui_context_destroy(UiContext *ctx) { +void ui_context_destroy(UiContext *ctx) { + CxIterator i = cxListIterator(ctx->destroy_handler); + cx_foreach(UiDestroyHandler *, h, i) { + h->destructor(h->data); + } cxMempoolFree(ctx->mp); } +UiContext* ui_context_parent(UiContext *ctx) { + return ctx->parent; +} + void ui_set_group(UiContext *ctx, int group) { if(!cxListIndexValid(ctx->groups, cxListFind(ctx->groups, &group))) {