refactore document system to support document trees

Sat, 05 Dec 2020 17:50:22 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 05 Dec 2020 17:50:22 +0100
changeset 163
b70e2a77dea0
parent 162
18892c0a9adc
child 164
1d912f78fd1d

refactore document system to support document trees

application/main.c file | annotate | diff | comparison | revisions
ui/common/context.c file | annotate | diff | comparison | revisions
ui/common/context.h file | annotate | diff | comparison | revisions
ui/common/document.c file | annotate | diff | comparison | revisions
ui/gtk/container.c file | annotate | diff | comparison | revisions
ui/gtk/model.h file | annotate | diff | comparison | revisions
ui/gtk/text.c file | annotate | diff | comparison | revisions
ui/gtk/text.h file | annotate | diff | comparison | revisions
ui/gtk/toolbar.c file | annotate | diff | comparison | revisions
ui/gtk/toolkit.c file | annotate | diff | comparison | revisions
ui/gtk/toolkit.h file | annotate | diff | comparison | revisions
ui/gtk/tree.c file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
--- a/application/main.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/application/main.c	Sat Dec 05 17:50:22 2020 +0100
@@ -33,14 +33,57 @@
 #include <ucx/buffer.h>
 #include <ucx/utils.h>
 
+typedef struct {
+    UiText *text;
+} MyDocument;
+
+MyDocument *doc1;
+MyDocument *doc2;
+
+
 void action_menu(UiEvent *event, void *userdata) {
     
 }
 
+void action_button(UiEvent *event, void *userdata) {
+    printf("button test\n");
+    MyDocument *doc = event->document;
+    if(!doc) {
+        printf("no document\n");
+        return;
+    }
+    
+    char *text = doc->text->get(doc->text);
+    printf("text: {\n%s\n}\n", text);
+}
+
+void action_switch(UiEvent *event, void *userdata) {
+    if(event->document == doc1) {
+        ui_set_document(event->obj, doc2);
+    } else {
+        ui_set_document(event->obj, doc1);
+    }
+}
+
+
+MyDocument* create_doc(void) {
+    MyDocument *doc = ui_document_new(sizeof(MyDocument));
+    UiContext *docctx = ui_document_context(doc);
+    doc->text = ui_text_new(docctx, "text");
+    return doc;
+}
+
 void application_startup(UiEvent *event, void *data) {
     
     UiObject *obj = ui_window("Test", NULL);
+    ui_textarea_nv(obj, "text");
+    ui_button(obj, "Test", action_button, NULL);
+    ui_button(obj, "Switch Document", action_switch, NULL);
     
+    doc1 = create_doc();
+    doc2 = create_doc();
+    
+    ui_attach_document(obj->ctx, doc1);
     
     ui_show(obj);
 }
--- a/ui/common/context.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/common/context.c	Sat Dec 05 17:50:22 2020 +0100
@@ -44,8 +44,8 @@
     ctx->obj = toplevel;
     ctx->vars = ucx_map_new_a(mp->allocator, 16);
     
-    ctx->set_document = uic_context_set_document;
-    ctx->detach_document = uic_context_detach_document;
+    ctx->attach_document = uic_context_attach_document;
+    ctx->detach_document2 = uic_context_detach_document2;
     
 #ifdef UI_GTK
     if(toplevel->widget) {
@@ -61,139 +61,126 @@
     return ctx->parent ? uic_root_context(ctx->parent) : ctx;
 }
 
-void uic_context_set_document(UiContext *ctx, void *document) {
-    if(ctx->document == document) {
-        return;
-    }
-    if(ctx->document) {
-        uic_context_detach_document(ctx);
-    }
-    ctx->document = document;
+void uic_context_attach_document(UiContext *ctx, void *document) {
+    ctx->documents = ucx_list_append_a(ctx->mempool->allocator, ctx->documents, document);
+    ctx->document = ctx->documents->data;
+    
+    UiContext *doc_ctx = ui_document_context(document);
     
-    UiContext *docctx = ui_document_context(document);
-    if(!docctx) {
-        fprintf(stderr, "UiError: uic_context_set_document: pointer is not a document\n");
-        return;
+    // check if any parent context has an unbound variable with the same name
+    // as any document variable
+    UiContext *var_ctx = ctx;
+    while(var_ctx) {
+        if(var_ctx->vars_unbound && var_ctx->vars_unbound->count > 0) {
+            UcxMapIterator i = ucx_map_iterator(var_ctx->vars_unbound);
+            UiVar *var;
+            // rmkeys holds all keys, that shall be removed from vars_unbound
+            UcxKey *rmkeys = calloc(var_ctx->vars_unbound->count, sizeof(UcxKey));
+            size_t numkeys = 0;
+            UCX_MAP_FOREACH(key, var, i) {
+                UiVar *docvar = ucx_map_get(doc_ctx->vars, key);
+                if(docvar) {
+                    // bind var to document var
+                    uic_copy_binding(var, docvar, TRUE);
+                    rmkeys[numkeys++] = key; // save the key for removal
+                }
+            }
+            // now that we may have bound some vars to the document,
+            // we can remove them from the unbound map
+            for(size_t k=0;k<numkeys;k++) {
+                ucx_map_remove(var_ctx->vars_unbound, rmkeys[k]);
+            }
+        }
+        
+        var_ctx = ctx->parent;
     }
-    docctx->obj = ctx->obj;
-    docctx->parent = ctx;
-    
-    UiContext *root = uic_root_context(ctx);
-    if(!root->bound || root->bound->count == 0) {
-        return;
+}
+
+static void uic_context_unbind_vars(UiContext *ctx) {
+    UcxMapIterator i = ucx_map_iterator(ctx->vars);
+    UiVar *var;
+    UCX_MAP_FOREACH(key, var, i) {
+        if(var->from && var->from_ctx) {
+            uic_save_var2(var);
+            uic_copy_binding(var, var->from, FALSE);
+            ucx_map_put(var->from_ctx->vars_unbound, key, var->from);
+            var->from_ctx = ctx;
+        }
     }
     
-    // there are bound variables in the root ctx
-    // copy bindings with correct name to doc vars
-    UcxMapIterator i = ucx_map_iterator(docctx->vars);
-    UiVar *var;
-    UCX_MAP_FOREACH(key, var, i) {
-        UiVar *v = ucx_map_get(root->bound, key);
-        if(v) {
-            // copy binding: after this, all doc vars with names of previously
-            // bound variables are bound to the widgets
-            // the widgets still hold a pointer to the root ctx vars, but this
-            // vars have a pointer to the document variable value - confusing
-            uic_copy_binding(v, var, TRUE);
-        }
+    UCX_FOREACH(elm, ctx->documents) {
+        UiContext *subctx = ui_document_context(elm->data);
+        uic_context_unbind_vars(subctx);
     }
 }
 
-void uic_context_detach_document(UiContext *ctx) {
-    if(!ctx->document) {
-        return;
+void uic_context_detach_document2(UiContext *ctx, void *document) {
+    // find the document in the documents list
+    UcxList *doc = NULL;
+    UCX_FOREACH(elm, ctx->documents) {
+        if(elm->data == document) {
+            doc = elm;
+            break;
+        }
+    }
+    if(!doc) {
+        return; // document is not a subdocument of this context
     }
     
-    UiContext *docctx = ui_document_context(ctx->document);
-    if(!docctx) {
-        fprintf(stderr, "UiError: Cannot detach document: no context\n");
-        return;
-    }
-    ctx->document = NULL;
-    docctx->parent = NULL;
-    docctx->obj = NULL;
+    ctx->documents = ucx_list_remove_a(ctx->mempool->allocator, ctx->documents, doc);
+    ctx->document = ctx->documents ? ctx->documents->data : NULL;
     
-    // unbind all vars
-    UcxMapIterator i = ucx_map_iterator(docctx->vars);
-    UiVar *var;
-    UCX_MAP_FOREACH(key, var, i) {
-        uic_save_var(var);
-        if(var->from) {
-            // restore old root bound var val
-            var->from->value = var->from->orig_val;
-            var->from->orig_val = NULL;
-            // copy
-            uic_copy_binding(var, var->from, FALSE);
+    UiContext *docctx = ui_document_context(document);
+    uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent
+}
+
+void uic_context_detach_all(UiContext *ctx) {
+    UcxList *ls = ucx_list_clone(ctx->documents, NULL, NULL);
+    UCX_FOREACH(elm, ls) {
+        ctx->detach_document2(ctx, elm->data);
+    }
+    ucx_list_free(ls);
+}
+
+static UiVar* ctx_getvar(UiContext *ctx, UcxKey key) {
+    UiVar *var = ucx_map_get(ctx->vars, key);
+    if(!var) {
+        UCX_FOREACH(elm, ctx->documents) {
+            UiContext *subctx = ui_document_context(elm->data);
+            var = ctx_getvar(subctx, key);
+            if(var) {
+                break;
+            }
         }
-        uic_unbind_var(var);
     }
+    return var;
 }
 
 UiVar* uic_get_var(UiContext *ctx, char *name) {
-    // check document variables first
-    UiVar *var = NULL;
-    UiContext *doc_ctx = ui_document_context(ctx->document);
-    if(doc_ctx) {
-        var = uic_get_var(doc_ctx, name);
-    }
-    
-    // check variables of this context
-    if(!var) {
-        var = ucx_map_cstr_get(ctx->vars, name);
-    }
-    
-    return var;
+    UcxKey key = ucx_key(name, strlen(name));
+    return ctx_getvar(ctx, key);
 }
 
 UiVar* uic_create_var(UiContext *ctx, char *name, UiVarType type) {
-    // check if this context has a var with this name
-    // otherweise add it to the bound map
-    UiVar *cv = ucx_map_cstr_get(ctx->vars, name);
-    if(cv) {
-        if(cv->type == type) {
-            return cv;
+    UiVar *var = uic_get_var(ctx, name);
+    if(var) {
+        if(var->type == type) {
+            return var;
         } else {
-            fprintf(stderr, "UiError: var '%s' already exists with different type\n", name);
-        }
-    }
-    
-    UiVar *var;
-    if(ctx->bound) {
-        var = ucx_map_cstr_get(ctx->bound, name);
-        if(var) {
-            if(var->type != type) {
-                fprintf(stderr, "UiError: var '%s' already bound with different type\n", name);
-            } else {
-                return var;
-            }
+            fprintf(stderr, "UiError: var '%s' already bound with different type\n", name);
         }
     }
     
-    // create var and add it to the bound map
-    // this map contains vars that are created by widgets
-    // the vars can later be moved to subdocuments
     var = ui_malloc(ctx, sizeof(UiVar));
     var->type = type;
     var->value = uic_create_value(ctx, type);
-    var->orig_val = NULL;
-    var->from = NULL; // not connected to a doc var
-    
-    if(!ctx->bound) {
-        ctx->bound = ucx_map_new_a(ctx->mempool->allocator, 16);
+    var->from = NULL;
+    var->from_ctx = ctx;
+
+    if(!ctx->vars_unbound) {
+        ctx->vars_unbound = ucx_map_new_a(ctx->mempool->allocator, 16);
     }
-    ucx_map_cstr_put(ctx->bound, name, var);
-    
-    // if a subdocument has a variable with this name, we must copy
-    // the binding to the doc var
-    UiContext *doc_ctx = ui_document_context(ctx->document);
-    if(doc_ctx) {
-        UiVar *docvar = uic_get_var(doc_ctx, name);
-        if(docvar) {
-            var->orig_val = var->value;
-            var->value = docvar->value;
-            docvar->from = var;
-        }
-    }
+    ucx_map_cstr_put(ctx->vars_unbound, name, var);
     
     return var;
 }
@@ -230,11 +217,6 @@
 }
 
 void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
-    if(copytodoc && from->from) {
-        fprintf(stderr, "UiError: var already connected to a document\n");
-        return;
-    }
-    
     // check type
     if(from->type != to->type) {
         fprintf(stderr, "UI Error: var has incompatible type.\n");
@@ -245,9 +227,7 @@
     // update var
     if(copytodoc) {
         to->from = from;
-    
-        from->orig_val = from->value;
-        from->value = to->value;
+        to->from_ctx = from->from_ctx;
     }
     
     // copy binding
@@ -311,8 +291,9 @@
     }
 }
 
-void uic_save_var(UiVar *var) {
+void uic_save_var2(UiVar *var) {
     switch(var->type) {
+        case UI_VAR_SPECIAL: break;
         case UI_VAR_INTEGER: uic_int_save(var->value); break;
         case UI_VAR_DOUBLE: uic_double_save(var->value); break;
         case UI_VAR_STRING: uic_string_save(var->value); break;
@@ -334,8 +315,14 @@
 }
 
 void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value) {
-    UiContext *rootctx = uic_root_context(ctx);
-    
+    // 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
@@ -350,33 +337,46 @@
             }
         }
     }
+    */
     
     // create new var and add it to doc's vars
     UiVar *var = ui_malloc(ctx, sizeof(UiVar));
-    var->from = NULL;
-    var->orig_val = NULL;
     var->type = type;
     var->value = value;
+    var->from = NULL;
+    var->from_ctx = ctx;
     size_t oldcount = ctx->vars->count;
     ucx_map_cstr_put(ctx->vars, name, var);
     if(ctx->vars->count != 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);
     }
+    */
 }
 
 void uic_remove_bound_var(UiContext *ctx, UiVar *var) {
     // TODO: implement
+    printf("TODO: implement uic_remove_bound_var\n");
 }
 
 
 // public API
 
+void ui_attach_document(UiContext *ctx, void *document) {
+    uic_context_attach_document(ctx, document);
+}
+
+void ui_detach_document2(UiContext *ctx, void *document) {
+    uic_context_detach_document2(ctx, document);
+}
+
 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) {
     ctx->close_callback = fnc;
     ctx->close_data = udata;
--- a/ui/common/context.h	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/common/context.h	Sat Dec 05 17:50:22 2020 +0100
@@ -60,18 +60,17 @@
     UiObject      *obj;
     UcxMempool    *mempool;
     
-    UcxMap        *bound; // key: char*  value: UiVar*       deprecated
-    UcxMap        *vars; // key: char*  value: UiVar*        deprecated
-    void          *document; //                              deprecated
+    void          *document;
+    UcxList       *documents;
     
-    UcxMap        *vars2; // manually created context vars
+    UcxMap        *vars; // manually created context vars
     UcxMap        *vars_unbound; // unbound vars created by widgets
     
     UcxList       *groups; // int list
     UcxList       *group_widgets; // UiGroupWidget* list
     
-    void (*set_document)(UiContext *ctx, void *document); // deprecated
-    void (*detach_document)(UiContext *ctx);              // deprecated    
+    void (*attach_document)(UiContext *ctx, void *document);
+    void (*detach_document2)(UiContext *ctx, void *document); 
     
     char          *title;
     
@@ -83,19 +82,12 @@
     void          *close_data;
 };
 
-// deprecated
+// UiVar replacement, rename it to UiVar when finished
 struct UiVar {
     void      *value;
-    void      *orig_val;
     UiVarType type;
-    UiVar     *from;
-};
-
-// UiVar replacement, rename it to UiVar when finished
-struct UiVar2 {
-    void      *value;
-    UiVarType type;
-    UiContext *bound_from; /* bound by this context or NULL if unbound */
+    UiVar    *from;
+    UiContext *from_ctx;
 };
 
 struct UiGroupWidget {
@@ -110,12 +102,16 @@
 void uic_context_set_document(UiContext *ctx, void *document); // deprecated
 void uic_context_detach_document(UiContext *ctx); // deprecated
 
-//UiVar* uic_get_var(UiContext *ctx, char *name);
+void uic_context_attach_document(UiContext *ctx, void *document);
+void uic_context_detach_document2(UiContext *ctx, void *document);
+void uic_context_detach_all(UiContext *ctx);
+
+UiVar* uic_get_var(UiContext *ctx, char *name);
 UiVar* uic_create_var(UiContext *ctx, char *name, UiVarType type);
 void* uic_create_value(UiContext *ctx, UiVarType type);
 
 void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc);
-void uic_save_var(UiVar *var);
+void uic_save_var2(UiVar *var);
 void uic_unbind_var(UiVar *var);
 
 void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value);
--- a/ui/common/document.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/common/document.c	Sat Dec 05 17:50:22 2020 +0100
@@ -39,11 +39,12 @@
 }
 
 void ui_set_document(UiObject *obj, void *document) {
-    obj->ctx->set_document(obj->ctx, document);
+    uic_context_detach_all(obj->ctx);
+    obj->ctx->attach_document(obj->ctx, document);
 }
 
 void ui_detach_document(UiObject *obj) {
-    obj->ctx->detach_document(obj->ctx);
+    uic_context_detach_all(obj->ctx);
 }
 
 void* ui_get_document(UiObject *obj) {
@@ -55,7 +56,7 @@
     if(!ctx) {
         fprintf(stderr, "UI Error: pointer is not a document\n");
     }
-    uic_context_set_document(ctx, sub);
+    // TODO
 }
 
 void ui_detach_subdocument(void *document, void *sub) {
@@ -63,7 +64,7 @@
     if(!ctx) {
         fprintf(stderr, "UI Error: pointer is not a document\n");
     }
-    uic_context_detach_document(ctx);
+    // TODO
 }
 
 void* ui_get_subdocument(void *document) {
@@ -71,14 +72,15 @@
     if(!ctx) {
         fprintf(stderr, "UI Error: pointer is not a document\n");
     }
-    return ctx->document;
+    // TODO
+    return NULL;
 }
 
 void* ui_document_new(size_t size) {
     UcxMempool *mp = ucx_mempool_new(256);
     UiContext *ctx = ucx_mempool_calloc(mp, 1, sizeof(UiContext));
-    ctx->set_document = uic_context_set_document;
-    ctx->detach_document = uic_context_detach_document;
+    ctx->attach_document = uic_context_attach_document;
+    ctx->detach_document2 = uic_context_detach_document2;
     ctx->mempool = mp;
     ctx->vars = ucx_map_new_a(mp->allocator, 16);
     
--- a/ui/gtk/container.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/container.c	Sat Dec 05 17:50:22 2020 +0100
@@ -426,7 +426,8 @@
     
     //printf("page_change: %d\n", page_num);
     UiContext *ctx = tab->ctx;
-    ctx->parent->set_document(ctx->parent, ctx->document);
+    uic_context_detach_all(ctx->parent); // TODO: fix?
+    ctx->parent->attach_document(ctx->parent, ctx->document);
 }
 
 UiTabbedPane* ui_tabbed_document_view(UiObject *obj) {
@@ -460,8 +461,8 @@
     tab->widget = NULL; // initialization for uic_context()
     tab->ctx = uic_context(tab, view->ctx->mempool);
     tab->ctx->parent = view->ctx;
-    tab->ctx->set_document = ui_tab_set_document;
-    tab->ctx->detach_document = ui_tab_detach_document;
+    tab->ctx->attach_document = uic_context_attach_document;
+    tab->ctx->detach_document2 = uic_context_detach_document2;
     tab->widget = frame;
     tab->window = view->ctx->obj->window;
     tab->container = ui_frame_container(tab, frame);
@@ -474,16 +475,18 @@
 }
 
 void ui_tab_set_document(UiContext *ctx, void *document) {
+    // TODO: remove?
     if(ctx->parent->document) {
         //ctx->parent->detach_document(ctx->parent, ctx->parent->document);
     }
-    uic_context_set_document(ctx, document);
+    //uic_context_set_document(ctx, document);
     //uic_context_set_document(ctx->parent, document);
     //ctx->parent->document = document;
 }
 
 void ui_tab_detach_document(UiContext *ctx) {
-    uic_context_detach_document(ctx->parent);
+    // TODO: remove?
+    //uic_context_detach_document(ctx->parent);
 }
 
 
--- a/ui/gtk/model.h	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/model.h	Sat Dec 05 17:50:22 2020 +0100
@@ -46,7 +46,7 @@
     GObject  object;
     UiObject *obj;
     UiModel  *model;
-    UiVar    *var;
+    UiVar   *var;
     GType    *columntypes;
     int      numcolumns;
     int      stamp;
--- a/ui/gtk/text.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/text.c	Sat Dec 05 17:50:22 2020 +0100
@@ -155,12 +155,11 @@
 }
 
 UIWIDGET ui_textarea(UiObject *obj, UiText *value) {
-    UiVar *var = NULL;
-    if(value) {
-        var = malloc(sizeof(UiVar));
-        var->value = value;
-        var->type = UI_VAR_SPECIAL;
-    }
+    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);
 }
 
--- a/ui/gtk/text.h	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/text.h	Sat Dec 05 17:50:22 2020 +0100
@@ -57,13 +57,13 @@
 
 typedef struct UiTextArea {
     UiContext *ctx;
-    UiVar     *var;
+    UiVar    *var;
     int       last_selection_state;
 } UiTextArea;
 
 typedef struct UiTextField {
     UiContext *ctx;
-    UiVar     *var;
+    UiVar    *var;
     // TODO: validatefunc
 } UiTextField;
 
--- a/ui/gtk/toolbar.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/toolbar.c	Sat Dec 05 17:50:22 2020 +0100
@@ -168,6 +168,8 @@
     UiVar *var = malloc(sizeof(UiVar));
     var->value = list;
     var->type = UI_VAR_SPECIAL;
+    var->from = NULL;
+    var->from_ctx = NULL;
     cb->var = var;
     cb->getvalue = getvalue;
     cb->callback = f;
--- a/ui/gtk/toolkit.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/toolkit.c	Sat Dec 05 17:50:22 2020 +0100
@@ -182,6 +182,7 @@
     if(!result) {
         g_idle_add(ui_job_finished, job);
     }
+    return NULL;
 }
 
 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) {
--- a/ui/gtk/toolkit.h	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/toolkit.h	Sat Dec 05 17:50:22 2020 +0100
@@ -46,7 +46,7 @@
 
 typedef struct UiVarEventData {
     UiObject   *obj;
-    UiVar      *var;
+    UiVar     *var;
     UiObserver **observers;
 } UiVarEventData;
 
--- a/ui/gtk/tree.c	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/gtk/tree.c	Sat Dec 05 17:50:22 2020 +0100
@@ -493,6 +493,7 @@
     GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata);
     UiContainer *ct = uic_get_current_container(obj);
     ct->add(ct, combobox, FALSE);
+    return combobox;
 }
 
 GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata) {
--- a/ui/ui/toolkit.h	Sat Dec 05 11:54:58 2020 +0100
+++ b/ui/ui/toolkit.h	Sat Dec 05 17:50:22 2020 +0100
@@ -300,16 +300,17 @@
 void* ui_document_new(size_t size);
 void  ui_document_destroy(void *doc);
 
-void ui_set_document(UiObject *obj, void *document);
-void ui_detach_document(UiObject *obj);
-void* ui_get_document(UiObject *obj);
-void ui_set_subdocument(void *document, void *sub);
-void ui_detach_subdocument(void *document, void *sub);
-void* ui_get_subdocument(void *document);
+void ui_set_document(UiObject *obj, void *document);    // deprecated
+void ui_detach_document(UiObject *obj);                 // deprecated
+void* ui_get_document(UiObject *obj);                   // deprecated
+void ui_set_subdocument(void *document, void *sub);     // deprecated
+void ui_detach_subdocument(void *document, void *sub);  // deprecated
+void* ui_get_subdocument(void *document);               // deprecated
 
 UiContext* ui_document_context(void *doc);
 
-
+void ui_attach_document(UiContext *ctx, void *document);
+void ui_detach_document2(UiContext *ctx, void *document);
 
 void ui_set_group(UiContext *ctx, int group);
 void ui_unset_group(UiContext *ctx, int group);

mercurial