refactors value binding system

Fri, 10 Nov 2017 17:17:14 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 10 Nov 2017 17:17:14 +0100
changeset 140
c03c338a7dcf
parent 139
dbde25a5bc53
child 141
cc2170ea05ad

refactors value binding system

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/common/document.h file | annotate | diff | comparison | revisions
ui/common/object.c file | annotate | diff | comparison | revisions
ui/common/object.h file | annotate | diff | comparison | revisions
ui/common/objs.mk file | annotate | diff | comparison | revisions
ui/common/properties.c file | annotate | diff | comparison | revisions
ui/common/properties.h file | annotate | diff | comparison | revisions
ui/common/types.c file | annotate | diff | comparison | revisions
ui/common/types.h file | annotate | diff | comparison | revisions
ui/gtk/button.c file | annotate | diff | comparison | revisions
ui/gtk/button.h file | annotate | diff | comparison | revisions
ui/gtk/container.c file | annotate | diff | comparison | revisions
ui/gtk/container.h file | annotate | diff | comparison | revisions
ui/gtk/draw_cairo.c file | annotate | diff | comparison | revisions
ui/gtk/draw_cairo.h file | annotate | diff | comparison | revisions
ui/gtk/draw_gdk.c file | annotate | diff | comparison | revisions
ui/gtk/draw_gdk.h file | annotate | diff | comparison | revisions
ui/gtk/graphics.c file | annotate | diff | comparison | revisions
ui/gtk/graphics.h file | annotate | diff | comparison | revisions
ui/gtk/image.c file | annotate | diff | comparison | revisions
ui/gtk/image.h file | annotate | diff | comparison | revisions
ui/gtk/label.c file | annotate | diff | comparison | revisions
ui/gtk/label.h file | annotate | diff | comparison | revisions
ui/gtk/menu.c file | annotate | diff | comparison | revisions
ui/gtk/menu.h file | annotate | diff | comparison | revisions
ui/gtk/model.c file | annotate | diff | comparison | revisions
ui/gtk/model.h file | annotate | diff | comparison | revisions
ui/gtk/objs.mk file | annotate | diff | comparison | revisions
ui/gtk/range.c file | annotate | diff | comparison | revisions
ui/gtk/range.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/toolbar.h 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/gtk/tree.h file | annotate | diff | comparison | revisions
ui/gtk/window.c file | annotate | diff | comparison | revisions
ui/ui/button.h file | annotate | diff | comparison | revisions
ui/ui/container.h file | annotate | diff | comparison | revisions
ui/ui/graphics.h file | annotate | diff | comparison | revisions
ui/ui/menu.h file | annotate | diff | comparison | revisions
ui/ui/properties.h file | annotate | diff | comparison | revisions
ui/ui/range.h file | annotate | diff | comparison | revisions
ui/ui/stock.h file | annotate | diff | comparison | revisions
ui/ui/text.h file | annotate | diff | comparison | revisions
ui/ui/toolbar.h file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
ui/ui/tree.h file | annotate | diff | comparison | revisions
ui/ui/ui.h file | annotate | diff | comparison | revisions
ui/ui/window.h file | annotate | diff | comparison | revisions
--- a/application/main.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/application/main.c	Fri Nov 10 17:17:14 2017 +0100
@@ -33,49 +33,79 @@
 #include <ucx/buffer.h>
 #include <ucx/utils.h>
 
+typedef struct Document {
+    UiText *text;
+    UiString *t1;
+    UiString *t2;
+    UiString *t3;
+    UiInteger *i;
+} Document;
+
+Document *d1;
+Document *d2;
+int n = 1;
+
+Document* create_doc();
+
+Document* next_doc(void) {
+    Document *doc = d1;
+    if(n == 1) {
+        doc = d2;
+        printf("doc2\n");
+    } else {
+        printf("doc1\n");
+    }
+    n++;
+    n = n%2;
+    return doc;
+}
+
 void action_menu(UiEvent *event, void *data) {
     printf("action_menu\n");
-    fflush(stdout);
-}
-
-void action_button(UiEvent *event, void *data) {
-    printf("action_button\n");
+    
+    Document *doc = event->document;
+    char *s = doc->text->get(doc->text);
+    printf("text: {\n%s\n}\n", s);
+    //int i = doc->i->get(doc->i);
+    //printf("i: %d\n", i);
+    
     fflush(stdout);
 }
 
-void draw(UiEvent *event, UiGraphics *g, void *data) {
-    printf("draw: %d, %d\n", g->width, g->height);
-    fflush(stdout);
+Document* create_doc() {
+    Document *doc = ui_document_new(sizeof(Document));
+    UiContext *ctx = ui_document_context(doc);
     
-    ui_graphics_color(g, 200, 240, 240);
-    ui_draw_rect(g, 0, 0, 50, g->height, TRUE);
+    doc->text = ui_text_new(ctx, "text");
+    //doc->t1 = ui_string_new(ctx, "t1");
+    //doc->t2 = ui_string_new(ctx, "t2");
+    //doc->t3 = ui_string_new(ctx, "t3");
     
-    ui_graphics_color(g, 150, 150, 200);
-    ui_draw_rect(g, 50, 0, g->width - 50, g->height, TRUE);
+    //doc->i = ui_int_new(ctx, "int");
+    return doc;
+}
+
+void action_newdoc(UiEvent *event, void *data) {
+    printf("new doc\n");
     
-    ui_graphics_color(g, 0, 0, 0);
-    ui_draw_line(g, 0, 10, 100, 10);
-    ui_draw_line(g, 0, 10, 10, 50);
-    ui_draw_line(g, 10, 50, 50, 50);
-    ui_draw_line(g, 50, 50, 100, 100);
-    
-    ui_draw_rect(g, 15, 15, 80, 80, FALSE);
+    Document *newd = next_doc();
+    printf("newd: %d\n", (int)(intptr_t)newd);
+    ui_set_document(event->obj, newd);
 }
 
 void application_startup(UiEvent *event, void *data) {
-    UiObject *obj = ui_window("Test", NULL);
-    
-    ui_tabview(obj);
+    //Document *doc = create_doc();
+    d1 = create_doc();
+    d2 = create_doc();
     
-    ui_tab(obj, "Tab 1");
-    ui_textarea(obj, NULL);
-    ui_end(obj);
+    UiObject *obj = ui_window("Test", NULL);
+    ui_set_document(obj, d1);
     
-    ui_tab(obj, "Tab 2");
-    ui_textarea(obj, NULL);
-    ui_end(obj);
+    ui_textarea_nv(obj, "text");
+    
     
-    ui_end(obj);
+    
+    ui_button(obj, "Switch Document", action_newdoc, NULL);
     
     ui_show(obj);
 }
@@ -94,22 +124,7 @@
     ui_menuitem("item3", action_menu, NULL);
     ui_submenu_end();
     ui_menuitem("item4", action_menu, NULL);
-    
-    // toolbar
-    ui_toolitem("button1", "Test1", action_button, NULL);
-    ui_toolitem("button2", "Test2", action_button, NULL);
-    ui_toolitem("button3", "Test3", action_button, NULL);
-    ui_toolitem("button4", "Test4", action_button, NULL);
-    ui_toolitem("button5", "Test5", action_button, NULL);
-    ui_toolitem("button6", "Test6", action_button, NULL);
-    ui_toolitem("button7", "Test7", action_button, NULL);
-    ui_toolbar_add_default("button1");
-    ui_toolbar_add_default("button2");
-    ui_toolbar_add_default("button3");
-    ui_toolbar_add_default("button4");
-    ui_toolbar_add_default("button5");
-    ui_toolbar_add_default("button6");
-    ui_toolbar_add_default("button7");
+
     
     ui_main();
     
--- a/ui/common/context.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/context.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -34,6 +34,7 @@
 #include "context.h"
 #include "../ui/window.h"
 #include "document.h"
+#include "types.h"
 
 
 UiContext* uic_context(UiObject *toplevel, UcxMempool *mp) {
@@ -64,85 +65,67 @@
     if(ctx->document == document) {
         return;
     }
+    if(ctx->document) {
+        uic_context_detach_document(ctx);
+    }
+    ctx->document = document;
     
     UiContext *docctx = ui_document_context(document);
     if(!docctx) {
+        fprintf(stderr, "UiError: uic_context_set_document: pointer is not a document\n");
         return;
     }
     docctx->obj = ctx->obj;
     docctx->parent = ctx;
     
-    if(ctx->document) {
-        uic_context_detach_document(ctx, ctx->document);
+    UiContext *root = uic_root_context(ctx);
+    if(!root->bound || root->bound->count == 0) {
+        return;
     }
-    //obj->document = document;
-    ctx->document = document;
     
+    // 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(uic_root_context(ctx)->vars, key);
+        UiVar *v = ucx_map_get(root->bound, 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_move_var(v, var, TRUE);
-            var->from = v->from;
-            
-            // TODO: free var struct
-            ucx_map_remove(ctx->vars, key);
+            // 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);
         }
     }
 }
 
-void uic_context_detach_document(UiContext *ctx, void *document) {
-    UiContext *docctx = ui_document_context(document);
-    if(!docctx) {
-        fprintf(
-                stderr,
-                "UiError: ui_detach_document: document is not registered\n");
-        return;
-    }
-    if(ctx->document != document) {
-        fprintf(stderr, "UiError: ui_detach_document: wrong document\n");
+void uic_context_detach_document(UiContext *ctx) {
+    if(!ctx->document) {
         return;
     }
     
+    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;
+    
+    // unbind all vars
     UcxMapIterator i = ucx_map_iterator(docctx->vars);
     UiVar *var;
     UCX_MAP_FOREACH(key, var, i) {
-        if(var->from && var->from != docctx->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_move_var(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!
+        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);
         }
+        uic_unbind_var(var);
     }
-    
-    if(docctx->parent) {
-        docctx->parent->document = NULL;
-    }
-    
-    docctx->obj = NULL;
-    docctx->parent = NULL;
 }
 
 UiVar* uic_get_var(UiContext *ctx, char *name) {
@@ -161,185 +144,207 @@
     return var;
 }
 
-UiVar* uic_connect_var(UiContext *ctx, char *name, int type) {
-    // TODO: get current map (Document Container, Tabbed Pane)
-    UcxMap *from = ctx->vars;
+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) {
+        return cv; // I'm not sure if this can actually happen, lol
+    }
+    
+    // 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
+    UiVar *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
     
-    UiVar *var = uic_get_var(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
-            var->from = from;
-            
-            return var;
+    if(!ctx->bound) {
+        ctx->bound = ucx_map_new_a(ctx->mempool->allocator, 16);
+    }
+    size_t oldcount = ctx->bound->count;
+    ucx_map_cstr_put(ctx->bound, name, var);
+    if(ctx->bound->count != oldcount + 1) {
+        fprintf(stderr, "UiError: var '%s' already bound\n", name);
+    }
+    
+    // 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;
         }
-    } else {
-        // create an empty value and add it to the context 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;
     }
+    
+    return var;
 }
 
-void uic_move_var(UiVar *from, UiVar *to, UiBool set) {
+void* uic_create_value(UiContext *ctx, UiVarType type) {
+    void *val = NULL;
+    switch(type) {
+        case UI_VAR_INTEGER: {
+            val = ui_int_new(ctx, NULL);
+            break;
+        }
+        case UI_VAR_STRING: {
+            val = ui_string_new(ctx, NULL);
+            break;
+        }
+        case UI_VAR_TEXT: {
+            val = ui_text_new(ctx, NULL);
+            break;
+        }
+        case UI_VAR_LIST: {
+            val = NULL; // TODO
+            break;
+        }
+        case UI_VAR_RANGE: {
+            val = NULL; // TODO
+            break;
+        }
+    }
+    return val;
+}
+
+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");
+        return;
+    }
+    
+    // copy binding
+    // we don't copy the observer, because the from var has never one
     switch(from->type) {
+        default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break;
+        case UI_VAR_SPECIAL: break;
         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) {
+            if(!copytodoc) {
+                f->value = f->get(f);
+            }
+            uic_int_copy(f, t);
+            if(t->value != 0) {
                 t->set(t, t->value);
-            } else {
-                //t->value = t->get(t);
-                f->value = f->get(f);
-                //t->value = 0;
             }
             break;
         }
         case UI_VAR_STRING: {
-            // TODO
+            UiString *f = from->value;
+            UiString *t = to->value;
+            uic_string_copy(f, t);
+            if(!copytodoc) {
+                f->value = f->get(f);
+            } else {
+                char *tvalue = t->value ? t->value : "";
+                t->set(t, tvalue);
+            }
+
             break;
         }
         case UI_VAR_TEXT: {
             UiText *f = from->value;
             UiText *t = to->value;
-            char *tvalue = t->value ? t->value : "";
-            int tpos = t->pos;
-            memcpy(t, f, sizeof(UiText));
-            if(set) {
-                t->set(t, tvalue);
-                t->setposition(t, tpos);
+            uic_text_copy(f, t);
+            if(!copytodoc) {
+                f->value = f->get(f);
             } else {
-                f->value = f->get(f);
-                f->pos = f->position(f);
-                f->set = NULL;
-                f->get = NULL;
-                f->setposition = NULL;
-                f->position = NULL;
+                char *tvalue = t->value ? t->value : "";
+                t->set(t, tvalue);
+                t->setposition(t, t->pos);
             }
             break;
         }
         case UI_VAR_LIST: {
-            UiListVar *f = from->value;
-            UiListVar *t = to->value;
-            UiList *list = t->listptr->list;
-            UiObserver *observers = f->listptr->list->observers;
-            t->listptr = f->listptr;
-            if(set) {
-                t->listptr->list = list;
-                list->observers = observers;
-                ui_notify(observers, list);
+            UiList *f = from->value;
+            UiList *t = to->value;
+            uic_list_copy(f, t);
+            t->update(t, -1);
+        }
+        case UI_VAR_RANGE: {
+            UiRange *f = from->value;
+            UiRange *t = to->value;
+            if(!copytodoc) {
+                f->value = f->get(f);
             }
-            break;
+            uic_range_copy(f, t);
+            t->setextent(t, t->extent);
+            t->setrange(t, t->min, t->max);
+            t->set(t, t->value);
         }
     }
+    
+    if(copytodoc) {
+        to->from = from;
+    
+        from->orig_val = from->value;
+        from->value = to->value;
+    }
+}
+
+void uic_unbind_var(UiVar *var) {
+    switch(var->type) {
+        case UI_VAR_INTEGER: uic_int_unbind(var->value); break;
+        case UI_VAR_STRING: uic_string_unbind(var->value); break;
+        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;
+    }
 }
 
-void uic_reg_var(UiContext *ctx, char *name, int type, size_t vs, void *value) {
-    UiVar *newvar = ucx_mempool_malloc(ctx->mempool, sizeof(UiVar));
-    newvar->isextern = 1;
-    newvar->type = type;
-    newvar->value = value;
-    newvar->from = NULL;
+void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value) {
+    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
+            }
+        }
+    }
     
-    uic_add_var(ctx, name, newvar, type, vs);
+    // 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;
+    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);
+    }
+    
+    // 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_add_var(
-        UiContext *ctx,
-        char *name,
-        UiVar *newvar,
-        int type,
-        size_t vs)
-{ 
-    // if a parent context has a variable with this name, we remove it and put
-    // it to this context
-    UiVar *var = ctx->obj ? uic_get_var(ctx->obj->ctx, name) : NULL;
-    
-    if(var && var->from != ctx->vars) {
-        // 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(var->from, name);
-    }
-    
-    // finally, add the new variable to the document
-    ucx_map_cstr_put(ctx->vars, name, newvar);
+void uic_remove_bound_var(UiContext *ctx, UiVar *var) {
+    // TODO: implement
 }
 
-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;
-        }
-        case UI_VAR_TEXT: {
-            UiText *t = a->calloc(
-                    a->pool,
-                    1,
-                    sizeof(UiText));
-            return t;
-        }
-        case UI_VAR_LIST: {
-            UiListVar *l = a->malloc(a->pool, sizeof(UiListVar));
-            UiListPtr *lp = a->malloc(a->pool, sizeof(UiListPtr));
-            l->listptr = lp;
-            lp->list = NULL;
-            // TODO: create empty list
-            return l;
-        }
-    }
-    return NULL;
-}
 
 // public API
 
@@ -348,81 +353,6 @@
     ctx->close_data = udata;
 }
 
-int ui_getint(UiObject *obj, char *name) {
-    UiVar *var = uic_get_var(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);
-    }
-    return 0;
-}
-
-char* ui_getstr(UiObject *obj, char *name) {
-    UiVar *var = uic_get_var(obj->ctx, name);
-    if(var) {
-        if(var->type == UI_VAR_STRING) {
-            UiString *s = var->value;
-            if(s->get) {
-                return s->get(s);
-            } else {
-                fprintf(
-                        stderr,
-                        "UI Error: variable %s is not connected.\n",
-                        name);
-            }
-        } else {
-            fprintf(
-                    stderr,
-                    "UI Error: requested variable %s is not an string.\n",
-                    name);
-        }
-    } else {
-        fprintf(stderr, "UI Error: unkown variable %s.\n", name);
-    }
-    return NULL;
-}
-
-char* ui_gettext(UiObject *obj, char *name) {
-    UiVar *var = uic_get_var(obj->ctx, name);
-    if(var) {
-        if(var->type == UI_VAR_TEXT) {
-            UiText *s = var->value;
-            if(s->get) {
-                return s->get(s);
-            } else {
-                fprintf(
-                        stderr,
-                        "UI Error: variable %s is not connected.\n",
-                        name);
-            }
-        } else {
-            fprintf(
-                    stderr,
-                    "UI Error: requested variable %s is not a text.\n",
-                    name);
-        }
-    } else {
-        fprintf(stderr, "UI Error: unkown variable %s.\n", name);
-    }
-    return NULL;
-}
-
 
 
 void ui_set_group(UiContext *ctx, int group) {
--- a/ui/common/context.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/context.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -43,17 +43,29 @@
 typedef struct UiListVar     UiListVar;
 typedef struct UiGroupWidget UiGroupWidget;
 
+typedef enum UiVarType UiVarType;
+
+enum UiVarType {
+    UI_VAR_SPECIAL = 0,
+    UI_VAR_INTEGER,
+    UI_VAR_STRING,
+    UI_VAR_TEXT,
+    UI_VAR_LIST,
+    UI_VAR_RANGE
+};
+
 struct UiContext {
     UiContext     *parent;
     UiObject      *obj;
     UcxMempool    *mempool;
+    UcxMap        *bound; // key: char*  value: UiVar*
     UcxMap        *vars; // key: char*  value: UiVar*
     void          *document;
     UcxList       *groups; // int list
     UcxList       *group_widgets; // UiGroupWidget* list
     
     void (*set_document)(UiContext *ctx, void *document);
-    void (*detach_document)(UiContext *ctx, void *document);
+    void (*detach_document)(UiContext *ctx);
     
     char          *title;
     
@@ -66,18 +78,10 @@
 };
 
 struct UiVar {
-    void   *value;
-    int    type;
-    int    isextern;
-    UcxMap *from;
-};
-
-struct UiListPtr {
-    UiList *list;
-};
-
-struct UiListVar {
-    UiListPtr *listptr;
+    void      *value;
+    void      *orig_val;
+    UiVarType type;
+    UiVar     *from;
 };
 
 struct UiGroupWidget {
@@ -86,30 +90,22 @@
     int      numgroups;
 };
 
-enum UiVarType {
-    UI_VAR_INTEGER = 0,
-    UI_VAR_STRING,
-    UI_VAR_TEXT,
-    UI_VAR_LIST
-};
 
 UiContext* uic_context(UiObject *toplevel, UcxMempool *mp);
 UiContext* uic_root_context(UiContext *ctx);
 void uic_context_set_document(UiContext *ctx, void *document);
-void uic_context_detach_document(UiContext *ctx, void *document);
+void uic_context_detach_document(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);
 
-UiVar* uic_get_var(UiContext *ctx, char *name);
-UiVar* uic_connect_var(UiContext *ctx, char *name, int type);
-void uic_move_var(UiVar *from, UiVar *to, UiBool set);
-void uic_reg_var(UiContext *ctx, char *name, int type, size_t vs, void *value);
-void uic_add_var(
-        UiContext *ctx,
-        char *name,
-        UiVar *newvar,
-        int type,
-        size_t vs);
+void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc);
+void uic_unbind_var(UiVar *var);
 
-void* uic_create_value(UcxAllocator *a, int type);
+void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value);
+
+void uic_remove_bound_var(UiContext *ctx, UiVar *var);
 
 void uic_check_group_widgets(UiContext *ctx);
 void uic_add_group_widget(UiContext *ctx, void *widget, UcxList *groups);
--- a/ui/common/document.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/document.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -42,8 +42,8 @@
     obj->ctx->set_document(obj->ctx, document);
 }
 
-void ui_detach_document(UiObject *obj, void *document) {
-    obj->ctx->detach_document(obj->ctx, document);
+void ui_detach_document(UiObject *obj) {
+    obj->ctx->detach_document(obj->ctx);
 }
 
 void* ui_get_document(UiObject *obj) {
@@ -63,7 +63,7 @@
     if(!ctx) {
         fprintf(stderr, "UI Error: pointer is not a document\n");
     }
-    uic_context_detach_document(ctx, sub);
+    uic_context_detach_document(ctx);
 }
 
 void* ui_get_subdocument(void *document) {
@@ -98,68 +98,3 @@
         return NULL;
     }
 }
-
-void* ui_document_malloc(void *doc, size_t size) {
-    UiContext *uidoc = ui_document_context(doc);
-    return ucx_mempool_malloc(uidoc->mempool, size);
-}
-
-void* ui_document_calloc(void *doc, size_t nelem, size_t elsize) {
-    UiContext *uidoc = ucx_map_get(documents, ucx_key(&doc, sizeof(void*)));
-    return ucx_mempool_calloc(uidoc->mempool, nelem, elsize);
-}
-
-void  ui_document_free(void *doc, void *ptr) {
-    UiContext *uidoc = ucx_map_get(documents, ucx_key(&doc, sizeof(void*)));
-    ucx_mempool_free(uidoc->mempool, ptr);
-}
-
-void* ui_document_realloc(void *doc, void *ptr, size_t size) {
-    UiContext *uidoc = ucx_map_get(documents, ucx_key(&doc, sizeof(void*)));
-    return ucx_mempool_realloc(uidoc->mempool, ptr, size);
-}
-
-void uic_document_addvar(void *doc, char *name, int type, size_t vs) {
-    // TODO: remove
-    UiContext *ctx = ui_document_context(doc);
-    if(ctx) {
-        UiVar *newvar = ucx_mempool_malloc(ctx->mempool, sizeof(UiVar));
-        newvar->isextern = 0;
-        newvar->type = type;
-        newvar->value = ucx_mempool_calloc(ctx->mempool, 1, vs);
-        newvar->from = NULL;
-
-        uic_add_var(ctx, name, newvar, type, vs);
-    }
-}
-
-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) {
-    UiContext *ctx = ui_document_context(doc);
-    if(ctx) {
-        uic_reg_var(ctx, name, UI_VAR_INTEGER, sizeof(UiInteger), i);
-    }
-}
-
-void ui_document_regtext(void *doc, char *name, UiText *text) {
-    UiContext *ctx = ui_document_context(doc);
-    if(ctx) {
-        uic_reg_var(ctx, name, UI_VAR_TEXT, sizeof(UiText), text);
-    }
-}
-
-void ui_document_reglist(void *doc, char *name, UiList *list) {
-    UiContext *ctx = ui_document_context(doc);
-    if(ctx) {
-        UiListVar *lv = ui_document_malloc(doc, sizeof(UiListVar));
-        UiListPtr *lp = ui_document_malloc(doc, sizeof(UiListPtr));
-        lv->listptr = lp;
-        lp->list = list;
-        uic_reg_var(ctx, name, UI_VAR_LIST, sizeof(UiListPtr), lv);
-    }
-}
--- a/ui/common/document.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/document.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/common/object.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/object.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/common/object.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/object.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/common/objs.mk	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/objs.mk	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 #
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 #
-# Copyright 2012 Olaf Wintermann. All rights reserved.
+# 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:
--- a/ui/common/properties.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/properties.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/common/properties.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/properties.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/common/types.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/types.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <stdarg.h>
 
 #include "../../ucx/list.h"
@@ -93,6 +94,9 @@
     list->data = NULL;
     list->iter = NULL;
     
+    list->update = NULL;
+    list->obj = NULL;
+    
     return list;
 }
 
@@ -199,3 +203,118 @@
     ucx_mempool_free(ctx->mempool, mi->titles);
     ucx_mempool_free(ctx->mempool, mi);
 }
+
+// types
+
+// public functions
+UiInteger* ui_int_new(UiContext *ctx, char *name) {
+    UiInteger *i = ui_malloc(ctx, sizeof(UiInteger));
+    memset(i, 0, sizeof(UiInteger));
+    if(name) {
+        uic_reg_var(ctx, name, UI_VAR_INTEGER, i);
+    }
+    return i;
+}
+
+UiString* ui_string_new(UiContext *ctx, char *name) {
+    UiString *s = ui_malloc(ctx, sizeof(UiString));
+    memset(s, 0, sizeof(UiString));
+    if(name) {
+        uic_reg_var(ctx, name, UI_VAR_STRING, s);
+    }
+    return s;
+}
+
+UiText* ui_text_new(UiContext *ctx, char *name) {
+    UiText *t = ui_malloc(ctx, sizeof(UiText));
+    memset(t, 0, sizeof(UiText));
+    if(name) {
+        uic_reg_var(ctx, name, UI_VAR_TEXT, t);
+    }
+    return t;
+}
+
+
+// private functions
+void uic_int_copy(UiInteger *from, UiInteger *to) {
+    to->get = from->get;
+    to->set = from->set;
+    to->obj = from->obj;
+}
+
+void uic_string_copy(UiString *from, UiString *to) {
+    to->get = from->get;
+    to->set = from->set;
+    to->obj = from->obj;
+}
+
+void uic_text_copy(UiText *from, UiText *to) {
+    to->get = from->get;
+    to->set = from->set;
+    to->getsubstr = from->getsubstr;
+    to->insert = from->insert;
+    to->setposition = from->setposition;
+    to->position = from->position;
+    to->selection = from->selection;
+    to->length = from->length;
+    to->remove = from->remove;
+    
+    to->obj = from->obj;
+    // do not copy the undo manager
+}
+
+void uic_range_copy(UiRange *from, UiRange *to) {
+    to->get = from->get;
+    to->set = from->set;
+    to->setrange = from->setrange;
+    to->setextent = from->setextent;
+    to->obj = from->obj;
+}
+
+void uic_list_copy(UiList *from, UiList *to) {
+    to->update = from->update;
+    to->obj = from->obj;
+}
+
+
+void uic_int_unbind(UiInteger *i) {
+    i->value = i->get(i);
+    i->get = NULL;
+    i->set = NULL;
+    i->obj = NULL;
+}
+
+void uic_string_unbind(UiString *s) {
+    s->value = s->get(s);
+    s->get = NULL;
+    s->set = NULL;
+    s->obj = NULL;
+}
+
+void uic_text_unbind(UiText *t) {
+    t->value = t->get(t);
+    t->set = NULL;
+    t->get = NULL;
+    t->getsubstr = NULL;
+    t->insert = NULL;
+    t->setposition = NULL;
+    t->position = NULL;
+    t->selection = NULL;
+    t->length = NULL;
+    t->remove = NULL;
+    t->obj = NULL;
+}
+
+void uic_range_unbind(UiRange *r) {
+    r->value = r->get(r);
+    r->get = NULL;
+    r->set = NULL;
+    r->setextent = NULL;
+    r->setrange = NULL;
+    r->obj = NULL;
+}
+
+void uic_list_unbind(UiList *l) {
+    l->update = NULL;
+    l->obj = NULL;
+}
--- a/ui/common/types.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/common/types.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -35,24 +35,18 @@
 extern "C" {
 #endif
 
-/*
-UiObserver* ui_observer_new(ui_callback f, void *data);
-UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer);
-UiObserver* ui_add_observer(UiObserver *list, ui_callback f, void *data);
-void ui_notify(UiObserver *observer, void *data);
-void ui_notify_except(UiObserver *observer, UiObserver *exc, void *data);
-    
 
-UiList* ui_list_new();
-void* ui_list_first(UiList *list);
-void* ui_list_next(UiList *list);
-void* ui_list_get(UiList *list, int i);
-int   ui_list_count(UiList *list);
-void  ui_list_append(UiList *list, void *data);
-void  ui_list_prepend(UiList *list, void *data);
-void  ui_list_addobsv(UiList *list, ui_callback f, void *data);
-void  ui_list_notify(UiList *list);
-*/
+void uic_int_copy(UiInteger *from, UiInteger *to);
+void uic_string_copy(UiString *from, UiString *to);
+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_int_unbind(UiInteger *i);
+void uic_string_unbind(UiString *s);
+void uic_text_unbind(UiText *t);
+void uic_range_unbind(UiRange *r);
+void uic_list_unbind(UiList *l);
     
 #ifdef	__cplusplus
 }
--- a/ui/gtk/button.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/button.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/button.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/button.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/container.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/container.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -481,8 +481,8 @@
     //ctx->parent->document = document;
 }
 
-void ui_tab_detach_document(UiContext *ctx, void *document) {
-    uic_context_detach_document(ctx->parent, document);
+void ui_tab_detach_document(UiContext *ctx) {
+    uic_context_detach_document(ctx->parent);
 }
 
 
--- a/ui/gtk/container.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/container.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -30,6 +30,7 @@
 #define	CONTAINER_H
 
 #include "../ui/toolkit.h"
+#include "../ui/container.h"
 #include <string.h>
 
 #ifdef	__cplusplus
@@ -114,7 +115,7 @@
 
 UiObject* ui_add_document_tab(UiDocumentView *view);
 void ui_tab_set_document(UiContext *ctx, void *document);
-void ui_tab_detach_document(UiContext *ctx, void *document);
+void ui_tab_detach_document(UiContext *ctx);
 
 #ifdef	__cplusplus
 }
--- a/ui/gtk/draw_cairo.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/draw_cairo.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/draw_cairo.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/draw_cairo.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/draw_gdk.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/draw_gdk.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2011 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/draw_gdk.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/draw_gdk.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/graphics.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/graphics.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/graphics.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/graphics.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/image.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/image.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/image.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/image.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/label.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/label.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/label.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/label.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/menu.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/menu.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -346,7 +346,7 @@
     GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
     gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
     
-    UiVar *var = uic_connect_var(obj->ctx, ci->varname, UI_VAR_INTEGER);
+    UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER);
     if(var) {
         UiInteger *value = var->value;
         value->obj = widget;
--- a/ui/gtk/menu.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/menu.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/model.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/model.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -92,7 +92,7 @@
 
 static void list_model_init(UiListModel *instance, GObjectClass *cl) {
     instance->columntypes = NULL;
-    instance->list = NULL;
+    instance->var = NULL;
     instance->numcolumns = 0;
     instance->stamp = g_random_int();
 }
@@ -122,10 +122,10 @@
     value->g_type = G_TYPE_INVALID; 
 }
 
-UiListModel* ui_list_model_new(UiListPtr *list, UiModelInfo *info) {
+UiListModel* ui_list_model_new(UiVar *var, UiModelInfo *info) {
     UiListModel *model = g_object_new(list_model_type, NULL);
     model->info = info;
-    model->list = list;
+    model->var = var;
     model->columntypes = calloc(sizeof(GType), 2 * info->columns);
     int ncol = 0;
     for(int i=0;i<info->columns;i++) {
@@ -168,7 +168,7 @@
 {
     g_assert(IS_UI_LIST_MODEL(tree_model));
     UiListModel *model = UI_LIST_MODEL(tree_model);
-    UiList *list = model->list->list;
+    UiList *list = model->var->value;
     
     // check the depth of the path
     // a list must have a depth of 1
@@ -215,7 +215,6 @@
     g_return_val_if_fail(iter->user_data != NULL, NULL);
     
     UiListModel *model = UI_LIST_MODEL(tree_model);
-    UiList *list = model->list->list;
     
     GtkTreePath *path = gtk_tree_path_new();
     gtk_tree_path_append_index(path, (int)(intptr_t)iter->user_data2); // list->index
@@ -234,7 +233,7 @@
     g_return_if_fail(iter->user_data != NULL);
     
     UiListModel *model = UI_LIST_MODEL(tree_model);
-    UiList *list = model->list->list;
+    UiList *list = model->var->value;
     
     g_return_if_fail(column < model->numcolumns);
     
@@ -261,7 +260,7 @@
     g_return_val_if_fail(iter->user_data != NULL, FALSE);
     
     UiListModel *model = UI_LIST_MODEL(tree_model);
-    UiList *list = model->list->list;
+    UiList *list = model->var->value;
     list->iter = iter->user_data;
     //list->index = (int)(intptr_t)iter->user_data2;
     void *val = list->next(list);
@@ -282,7 +281,7 @@
     g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE);
     
     UiListModel *model = UI_LIST_MODEL(tree_model);
-    UiList *list = model->list->list;
+    UiList *list = model->var->value;
     
     if(parent) {
         return FALSE;
@@ -317,7 +316,7 @@
     if(!iter) {
         // return number of rows
         UiListModel *model = UI_LIST_MODEL(tree_model);
-        UiList *list = model->list->list;
+        UiList *list = model->var->value;
         return list->count(list);
     }
     
@@ -337,7 +336,7 @@
     }
     
     UiListModel *model = UI_LIST_MODEL(tree_model);
-    UiList *list = model->list->list;
+    UiList *list = model->var->value;
     
     // check n
     if(n == 0) {
--- a/ui/gtk/model.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/model.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -45,7 +45,7 @@
 struct UiListModel {
     GObject     object;
     UiModelInfo *info;
-    UiListPtr   *list;
+    UiVar       *var;
     GType       *columntypes;
     int         numcolumns;
     int         stamp;
@@ -59,7 +59,7 @@
 /*
  * Creates a UiListModel for a given UiList
  */
-UiListModel* ui_list_model_new(UiListPtr *list, UiModelInfo *info);
+UiListModel* ui_list_model_new(UiVar *var, UiModelInfo *info);
 
 
 // interface functions
--- a/ui/gtk/objs.mk	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/objs.mk	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 #
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 #
-# Copyright 2012 Olaf Wintermann. All rights reserved.
+# 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:
--- a/ui/gtk/range.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/range.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2016 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/range.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/range.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2016 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/gtk/text.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/text.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -32,8 +32,7 @@
 
 #include "text.h"
 #include "container.h"
-#include "../common/context.h"
-#include "../common/document.h"
+
 
 static void selection_handler(
         GtkTextBuffer *buf,
@@ -57,7 +56,7 @@
     }
 }
 
-UIWIDGET ui_textarea(UiObject *obj, UiText *value) {
+UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var) {
     GtkWidget *text_area = gtk_text_view_new();
     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_area), GTK_WRAP_WORD_CHAR);
     g_signal_connect(
@@ -65,17 +64,17 @@
             "realize",
             G_CALLBACK(ui_textarea_realize_event),
             NULL);
-    g_signal_connect(
-            text_area,
-            "selection-clear-event",
-            G_CALLBACK(selection_handler),
-            NULL);
+    
+    UiTextArea *uitext = malloc(sizeof(UiTextArea));
+    uitext->ctx = obj->ctx;
+    uitext->var = var;
+    uitext->last_selection_state = 0;
     
-    UiTextArea *uitext = ucx_mempool_malloc(
-            obj->ctx->mempool,
-            sizeof(UiTextArea));
-    uitext->ctx = obj->ctx;
-    uitext->last_selection_state = 0;
+    g_signal_connect(
+                text_area,
+                "destroy",
+                G_CALLBACK(ui_textarea_destroy),
+                uitext);
     
     GtkWidget *scroll_area = gtk_scrolled_window_new (NULL, NULL);
     gtk_scrolled_window_set_policy(
@@ -98,6 +97,7 @@
     ct->add(ct, scroll_area, TRUE);
     
     // bind value
+    UiText *value = var->value;
     if(value) {
         GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_area));
         
@@ -126,12 +126,12 @@
                 buf,
                 "insert-text",
                 G_CALLBACK(ui_textbuf_insert),
-                value);
+                var);
         g_signal_connect(
                 buf,
                 "delete-range",
                 G_CALLBACK(ui_textbuf_delete),
-                value);
+                var);
         
         g_signal_connect(
                 buf,
@@ -143,11 +143,25 @@
     return scroll_area;
 }
 
+void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea) {
+    ui_destroy_boundvar(textarea->ctx, textarea->var);
+    free(textarea);
+}
+
+UIWIDGET ui_textarea(UiObject *obj, UiText *value) {
+    UiVar *var = NULL;
+    if(value) {
+        var = malloc(sizeof(UiVar));
+        var->value = value;
+        var->type = UI_VAR_SPECIAL;
+    }
+    return ui_textarea_var(obj, var);
+}
+
 UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) {
-    UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_TEXT);
+    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_TEXT);
     if(var) {
-        UiText *value = var->value;
-        return ui_textarea(obj, value);
+        return ui_textarea_var(obj, var);
     } else {
         // TODO: error
     }
@@ -168,11 +182,11 @@
 }
 
 void ui_textarea_set(UiText *text, char *str) {
+    gtk_text_buffer_set_text((GtkTextBuffer*)text->obj, str, -1);
     if(text->value) {
         g_free(text->value);
     }
     text->value = NULL;
-    gtk_text_buffer_set_text((GtkTextBuffer*)text->obj, str, -1);
 }
 
 char* ui_textarea_getsubstr(UiText *text, int begin, int end) {
@@ -242,24 +256,7 @@
     gtk_widget_grab_focus(widget);
 }
 
-void ui_text_set(UiText *text, char *str) {
-    if(text->set) {
-        text->set(text, str);
-    } else {
-        if(text->value) {
-            g_free(text->value);
-        }
-        text->value = g_strdup(str);
-    }
-}
 
-char* ui_text_get(UiText *text) {
-    if(text->get) {
-        return text->get(text);
-    } else {
-        return text->value;
-    }
-}
 
 
 // undo manager functions
@@ -271,7 +268,11 @@
         int length,
         void *data)
 {
-    UiText *value = data;
+    UiVar *var = data;
+    UiText *value = var->value;
+    if(!value->undomgr) {
+        value->undomgr = ui_create_undomgr();
+    }
     UiUndoMgr *mgr = value->undomgr;
     if(!mgr->event) {
         return;
@@ -332,7 +333,11 @@
         GtkTextIter *end,
         void *data)
 {
-    UiText *value = data;
+    UiVar *var = data;
+    UiText *value = var->value;
+    if(!value->undomgr) {
+        value->undomgr = ui_create_undomgr();
+    }
     UiUndoMgr *mgr = value->undomgr;
     if(!mgr->event) {
         return;
@@ -474,8 +479,19 @@
 }
 
 
-static UIWIDGET create_textfield(UiObject *obj, int width, UiBool frameless, UiBool password, UiString *value) {
+static UIWIDGET create_textfield_var(UiObject *obj, int width, UiBool frameless, UiBool password, UiVar *var) {
     GtkWidget *textfield = gtk_entry_new();
+    
+    UiTextField *uitext = malloc(sizeof(UiTextField));
+    uitext->ctx = obj->ctx;
+    uitext->var = var;
+    
+    g_signal_connect(
+                textfield,
+                "destroy",
+                G_CALLBACK(ui_textfield_destroy),
+                uitext);
+    
     if(width > 0) {
         gtk_entry_set_width_chars(GTK_ENTRY(textfield), width);
     }
@@ -490,11 +506,12 @@
     UiContainer *ct = uic_get_current_container(obj);
     ct->add(ct, textfield, FALSE);
     
-    if(value) {
+    if(var) {
+        UiString *value = var->value;
         if(value->value) {
             gtk_entry_set_text(GTK_ENTRY(textfield), value->value);
             g_free(value->value);
-            // TODO: free value
+            value->value = NULL;
         }
         
         value->get = ui_textfield_get;
@@ -507,16 +524,30 @@
 }
 
 static UIWIDGET create_textfield_nv(UiObject *obj, int width, UiBool frameless, UiBool password, char *varname) {
-    UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_STRING);
+    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_STRING);
     if(var) {
-        UiString *value = var->value;
-        return create_textfield(obj, width, frameless, password, value);
+        return create_textfield_var(obj, width, frameless, password, var);
     } else {
         // TODO: error
     }
     return NULL;
 }
 
+static UIWIDGET create_textfield(UiObject *obj, int width, UiBool frameless, UiBool password, UiString *value) {
+    UiVar *var = NULL;
+    if(value) {
+        var = malloc(sizeof(UiVar));
+        var->value = value;
+        var->type = UI_VAR_SPECIAL;
+    }
+    return create_textfield_var(obj, width, frameless, password, var);
+}
+
+void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield) {
+    ui_destroy_boundvar(textfield->ctx, textfield->var);
+    free(textfield);
+}
+
 UIWIDGET ui_textfield(UiObject *obj, UiString *value) {
     return create_textfield(obj, 0, FALSE, FALSE, value);
 }
--- a/ui/gtk/text.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/text.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -32,6 +32,7 @@
 #include "../ui/text.h"
 #include "toolkit.h"
 #include "../../ucx/list.h"
+#include "../common/context.h"
 
 #ifdef	__cplusplus
 extern "C" {
@@ -56,9 +57,19 @@
 
 typedef struct UiTextArea {
     UiContext *ctx;
-    int last_selection_state;
+    UiVar     *var;
+    int       last_selection_state;
 } UiTextArea;
 
+typedef struct UiTextField {
+    UiContext *ctx;
+    UiVar     *var;
+    // TODO: validatefunc
+} UiTextField;
+
+UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var);
+void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea);
+
 char* ui_textarea_get(UiText *text);
 void ui_textarea_set(UiText *text, char *str);
 char* ui_textarea_getsubstr(UiText *text, int begin, int end);
@@ -85,6 +96,8 @@
 void ui_free_textbuf_op(UiTextBufOp *op);
 int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen);
 
+void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield);
+
 char* ui_textfield_get(UiString *str);
 void ui_textfield_set(UiString *str, char *value);
 
--- a/ui/gtk/toolbar.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/toolbar.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -164,8 +164,11 @@
         void *udata)
 {
     UiToolbarComboBox *cb = malloc(sizeof(UiToolbarComboBox));
-    cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox;  
-    cb->list = list;
+    cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox;
+    UiVar *var = malloc(sizeof(UiVar));
+    var->value = list;
+    var->type = UI_VAR_SPECIAL;
+    cb->var = var;
     cb->getvalue = getvalue;
     cb->callback = f;
     cb->userdata = udata;
@@ -357,9 +360,7 @@
 void add_toolbar_combobox(GtkToolbar *tb, UiToolbarComboBox *cb, UiObject *obj) {
     UiModelInfo *modelinfo = ui_model_info(obj->ctx, UI_STRING, "", -1);
     modelinfo->getvalue = cb->getvalue;
-    UiListPtr *listptr = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListPtr));
-    listptr->list = cb->list;
-    UiListModel *model = ui_list_model_new(listptr, modelinfo);
+    UiListModel *model = ui_list_model_new(cb->var, modelinfo);
     
     GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata);
     GtkToolItem *item = gtk_tool_item_new();
@@ -368,6 +369,16 @@
 }
 
 void add_toolbar_combobox_nv(GtkToolbar *tb, UiToolbarComboBoxNV *cb, UiObject *obj) {
-    // TODO
+    UiVar *var = uic_create_var(obj->ctx, cb->listname, UI_VAR_LIST);
+    if(var) {
+        UiModelInfo *modelinfo = ui_model_info(obj->ctx, UI_STRING, "", -1);
+        modelinfo->getvalue = cb->getvalue;
+        UiListModel *model = ui_list_model_new(var, modelinfo);
+        
+        GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata);
+        GtkToolItem *item = gtk_tool_item_new();
+        gtk_container_add(GTK_CONTAINER(item), combobox);
+        gtk_toolbar_insert(tb, item, -1);
+    }
 }
 
--- a/ui/gtk/toolbar.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/toolbar.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -74,7 +74,7 @@
 
 struct UiToolbarComboBox {
     UiToolItemI         item;
-    UiList              *list;
+    UiVar               *var;
     ui_model_getvalue_f getvalue;
     ui_callback         callback;
     void                *userdata;
--- a/ui/gtk/toolkit.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/toolkit.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -226,6 +226,14 @@
     free(userdata);
 }
 
+void ui_destroy_boundvar(UiContext *ctx, UiVar *var) {
+    if(var->type == UI_VAR_SPECIAL) {
+        free(var);
+    } else {
+        uic_remove_bound_var(ctx, var);
+    }
+}
+
 void ui_set_active_window(UiObject *obj) {
     active_window = obj;
 }
--- a/ui/gtk/toolkit.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/toolkit.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -62,6 +62,8 @@
 
 void ui_destroy_userdata(GtkWidget *object, void *userdata);
 
+void ui_destroy_boundvar(UiContext *ctx, UiVar *var);
+
 void ui_set_active_window(UiObject *obj);
 UiObject *ui_get_active_window();
 
--- a/ui/gtk/tree.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/tree.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -46,7 +46,7 @@
     return ui_listview(obj, list, ui_strmodel_getvalue, f, udata);
 }
 
-UIWIDGET ui_listview_var(UiObject *obj, UiListPtr *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
+UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
@@ -66,19 +66,24 @@
     
     UiModelInfo *modelinfo = ui_model_info(obj->ctx, UI_STRING, "", -1);
     modelinfo->getvalue = getvalue;
-    UiListModel *model = ui_list_model_new(list, modelinfo);
+    UiList *list = var->value;
+    UiListModel *model = ui_list_model_new(var, modelinfo);
     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(model));
     
-    // add TreeView as observer to the UiList to update the TreeView if the
-    // data changes
-    UiTableView *listview = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiTableView));
+    UiListView *listview = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListView));
+    listview->ctx = obj->ctx;
     listview->widget = view;
-    listview->list = list;
+    listview->var = var;
     listview->modelinfo = modelinfo;
-    list->list->observers = ui_add_observer(
-            list->list->observers,
-            (ui_callback)ui_listview_update,
-            listview);
+    g_signal_connect(
+                view,
+                "destroy",
+                G_CALLBACK(ui_listview_destroy),
+                listview);
+    
+    // bind var
+    list->update = ui_listview_update;
+    list->obj = listview;
     
     // add callback
     if(f) {
@@ -114,16 +119,16 @@
 }
 
 UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
-    UiListPtr *listptr = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListPtr));
-    listptr->list = list;
-    return ui_listview_var(obj, listptr, getvalue, f, udata);
+    UiVar *var = malloc(sizeof(UiVar));
+    var->value = list;
+    var->type = UI_VAR_SPECIAL;
+    return ui_listview_var(obj, var, getvalue, f, udata);
 }
 
 UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
-    UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_LIST);
+    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
     if(var) {
-        UiListVar *value = var->value;
-        return ui_listview_var(obj, value->listptr, getvalue, f, udata);
+        return ui_listview_var(obj, var, getvalue, f, udata);
     } else {
         // TODO: error
     }
@@ -131,7 +136,7 @@
 }
 
 
-UIWIDGET ui_table_var(UiObject *obj, UiListPtr *list, UiModelInfo *modelinfo) {
+UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModelInfo *modelinfo) {
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
     int addi = 0;
@@ -172,19 +177,26 @@
     
 #endif
     
-    UiListModel *model = ui_list_model_new(list, modelinfo);
+    UiList *list = var->value;
+    UiListModel *model = ui_list_model_new(var, modelinfo);
     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(model));
     
     // add TreeView as observer to the UiList to update the TreeView if the
     // data changes
-    UiTableView *tableview = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiTableView));
+    UiListView *tableview = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListView));
+    tableview->ctx = obj->ctx;
     tableview->widget = view;
-    tableview->list = list;
+    tableview->var = var;
     tableview->modelinfo = modelinfo;
-    list->list->observers = ui_add_observer(
-            list->list->observers,
-            (ui_callback)ui_listview_update,
-            tableview);
+    g_signal_connect(
+                view,
+                "destroy",
+                G_CALLBACK(ui_listview_destroy),
+                tableview);
+    
+    // bind var
+    list->update = ui_listview_update;
+    list->obj = tableview;
     
     // add callback
     UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
@@ -232,31 +244,36 @@
 }
 
 UIWIDGET ui_table(UiObject *obj, UiList *list, UiModelInfo *modelinfo) {
-    UiListPtr *listptr = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListPtr));
-    listptr->list = list;
-    return ui_table_var(obj, listptr, modelinfo);
+    UiVar *var = malloc(sizeof(UiVar));
+    var->value = list;
+    var->type = UI_VAR_SPECIAL;
+    return ui_table_var(obj, var, modelinfo);
 }
 
 UIWIDGET ui_table_nv(UiObject *obj, char *varname, UiModelInfo *modelinfo) {
-    UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_LIST);
+    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
     if(var) {
-        UiListVar *value = var->value;
-        return ui_table_var(obj, value->listptr, modelinfo);
+        return ui_table_var(obj, var, modelinfo);
     } else {
         // TODO: error
     }
     return NULL;
 }
 
-
-
-void ui_listview_update(UiEvent *event, UiTableView *view) {
-    UiListModel *model = ui_list_model_new(view->list, view->modelinfo);
-    gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model));   
-    
+void ui_listview_update(UiList *list, int i) {
+    UiListView *view = list->obj;
+    UiListModel *model = ui_list_model_new(view->var, view->modelinfo);
+    gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model));
     // TODO: free old model
 }
 
+void ui_listview_destroy(GtkWidget *w, UiListView *v) {
+    ui_destroy_boundvar(v->ctx, v->var);
+    // TODO: destroy model?
+    free(v);
+}
+
+
 void ui_listview_activate_event(
         GtkTreeView *treeview,
         GtkTreePath *path,
@@ -339,26 +356,27 @@
 }
 
 UIWIDGET ui_combobox(UiObject *obj, UiList *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
-    UiListPtr *listptr = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListPtr));
-    listptr->list = list;
-    return ui_combobox_var(obj, listptr, getvalue, f, udata);
+    UiVar *var = malloc(sizeof(UiVar));
+    var->value = list;
+    var->type = UI_VAR_SPECIAL;
+    return ui_combobox_var(obj, var, getvalue, f, udata);
 }
 
 UIWIDGET ui_combobox_nv(UiObject *obj, char *varname, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
-    UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_LIST);
+    UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
     if(var) {
-        UiListVar *value = var->value;
-        return ui_combobox_var(obj, value->listptr, getvalue, f, udata);
+        return ui_combobox_var(obj, var, getvalue, f, udata);
     } else {
         // TODO: error
     }
     return NULL;
 }
 
-UIWIDGET ui_combobox_var(UiObject *obj, UiListPtr *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
+UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_model_getvalue_f getvalue, ui_callback f, void *udata) {
     UiModelInfo *modelinfo = ui_model_info(obj->ctx, UI_STRING, "", -1);
     modelinfo->getvalue = getvalue;
-    UiListModel *model = ui_list_model_new(list, modelinfo);
+    UiList *list = var->value;
+    UiListModel *model = ui_list_model_new(var, modelinfo);
     
     GtkWidget *combobox = ui_create_combobox(obj, model, f, udata);
     UiContainer *ct = uic_get_current_container(obj);
@@ -368,11 +386,22 @@
 GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata) {
     GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
     
-    UiList *list = model->list->list;
-    list->observers = ui_add_observer(
-            list->observers,
-            (ui_callback)ui_listview_update,
-            combobox);
+    UiListView *uicbox = malloc(sizeof(UiListView));
+    uicbox->ctx = obj->ctx;
+    uicbox->widget = combobox;
+    uicbox->var = model->var;
+    uicbox->modelinfo = model->info;
+    
+    g_signal_connect(
+                combobox,
+                "destroy",
+                G_CALLBACK(ui_listview_destroy),
+                uicbox);
+    
+    // bind var
+    UiList *list = model->var->value;
+    list->update = ui_combobox_modelupdate;
+    list->obj = uicbox;
     
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
     gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
@@ -412,8 +441,9 @@
     e->callback(&event, e->userdata);
 }
 
-void ui_combobox_update(UiEvent *event, void *combobox) {
-    printf("ui_combobox_update\n");
-    printf("TODO: implement\n");
+void ui_combobox_modelupdate(UiList *list, int i) {
+    UiListView *view = list->obj;
+    UiListModel *model = ui_list_model_new(view->var, view->modelinfo);
+    gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(model));
 }
 
--- a/ui/gtk/tree.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/tree.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -37,11 +37,12 @@
 extern "C" {
 #endif
 
-typedef struct UiTableView {
-    GtkWidget           *widget;
-    UiListPtr           *list;
-    UiModelInfo         *modelinfo;
-} UiTableView;
+typedef struct UiListView {
+    UiContext   *ctx;
+    GtkWidget   *widget;
+    UiVar       *var;
+    UiModelInfo *modelinfo;
+} UiListView;
 
 typedef struct UiTreeEventData {
     UiObject    *obj;
@@ -52,10 +53,12 @@
     
 void* ui_strmodel_getvalue(void *elm, int column);
 
-UIWIDGET ui_listview_var(UiObject *obj, UiListPtr *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata);
-UIWIDGET ui_table_var(UiObject *obj, UiListPtr *list, UiModelInfo *modelinfo);
+UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_model_getvalue_f getvalue, ui_callback f, void *udata);
+UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModelInfo *modelinfo);
 
-void ui_listview_update(UiEvent *event, UiTableView *view);
+void ui_listview_update(UiList *list, int i);
+void ui_listview_destroy(GtkWidget *w, UiListView *v);
+
 void ui_listview_activate_event(
         GtkTreeView *tree_view,
         GtkTreePath *path,
@@ -69,10 +72,10 @@
         UiTreeEventData *event);
 int ui_tree_path_list_index(GtkTreePath *path);
 
-UIWIDGET ui_combobox_var(UiObject *obj, UiListPtr *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata);
+UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_model_getvalue_f getvalue, ui_callback f, void *udata);
 GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata);
 void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e);
-void ui_combobox_update(UiEvent *event, void *combobox);
+void ui_combobox_modelupdate(UiList *list, int i);
         
 #ifdef	__cplusplus
 }
--- a/ui/gtk/window.c	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/gtk/window.c	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/button.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/button.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/ui/container.h	Fri Nov 10 17:17:14 2017 +0100
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef UI_CONTAINER_H
+#define UI_CONTAINER_H
+
+#include "toolkit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UIWIDGET ui_vbox(UiObject *obj);
+UIWIDGET ui_hbox(UiObject *obj);
+UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing);
+UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing);
+
+UIWIDGET ui_grid(UiObject *obj);
+UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing);
+
+UIWIDGET ui_scrolledwindow(UiObject *obj);
+
+UIWIDGET ui_sidebar(UiObject *obj);
+void ui_end(UiObject *obj);
+
+UIWIDGET ui_tabview(UiObject *obj);
+void ui_tab(UiObject *obj, char *title);
+void ui_select_tab(UIWIDGET tabview, int tab);
+
+// box container layout functions
+void ui_layout_fill(UiObject *obj, UiBool fill);
+// grid container layout functions
+void ui_layout_hexpand(UiObject *obj, UiBool expand);
+void ui_layout_vexpand(UiObject *obj, UiBool expand);
+void ui_layout_gridwidth(UiObject *obj, int width);
+void ui_newline(UiObject *obj);
+
+
+UiTabbedPane* ui_tabbed_document_view(UiObject *obj);
+
+UiObject* ui_document_tab(UiTabbedPane *view);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UI_CONTAINER_H */
+
--- a/ui/ui/graphics.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/graphics.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2015 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/menu.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/menu.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/properties.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/properties.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/range.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/range.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2016 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/stock.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/stock.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/text.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/text.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/toolbar.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/toolbar.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/toolkit.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/toolkit.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -97,23 +97,16 @@
 typedef struct UiList       UiList;
 typedef struct UiRange      UiRange;
 
-/* private types */
+/* begin opaque types */
 typedef struct UiContext    UiContext;
 typedef struct UiContainer  UiContainer;
+/* end opaque types */
 
 typedef struct UiTabbedPane UiTabbedPane;
 
 enum UiMouseEventType { UI_PRESS = 0, UI_PRESS2 };
 
-#define ui_getval(val) (val).get(&(val))
-#define ui_setval(val, v) (val).set(&(val), v)
 
-#define ui_getsubstr(text, begin, end) (text).getsubstr(&(text), begin, end)
-#define ui_insert(text, begin, str) (text).insert(&(text), begin, str)
-#define ui_length(text) (text).length(&(text))
-#define ui_selection(text, begin, end) (text).selection(&(text), begin, end)
-#define ui_position(text) (text).position(&(text))
-#define ui_remove(text, begin, end) (text).remove(&(text), begin, end)
   
 typedef void(*ui_callback)(UiEvent*, void*); /* event, user data */
 
@@ -133,12 +126,12 @@
     void        *window;
     
     /*
-     * window context (private)
+     * window context
      */
     UiContext   *ctx;
     
     /*
-     * container interface (private)
+     * container interface
      */
     UiContainer *container;
     
@@ -189,32 +182,37 @@
 struct UiInteger {
     int  (*get)(UiInteger*);
     void (*set)(UiInteger*, int);
+    void *obj;
+    
     int  value;
-    void *obj;
+    UiObserver *observers;
 };
 
 struct UiString {
     char* (*get)(UiString*);
     void  (*set)(UiString*, char*);
+    void  *obj;
+    
     char* value;
-    void  *obj;
+    UiObserver *observers;
 };
 
 struct UiText {
     void  (*set)(UiText*, char*);
     char* (*get)(UiText*);
-    char* (*getsubstr)(UiText*, int, int); // text, begin, end
+    char* (*getsubstr)(UiText*, int, int); /* text, begin, end */
     void  (*insert)(UiText*, int, char*);
     void  (*setposition)(UiText*,int);
     int   (*position)(UiText*);
-    void  (*selection)(UiText*, int*, int*); // text, begin, end
+    void  (*selection)(UiText*, int*, int*); /* text, begin, end */
     int   (*length)(UiText*);
-    void  (*remove)(UiText*, int, int); // text, begin, end
+    void  (*remove)(UiText*, int, int); /* text, begin, end */
     char  *value;
     int   pos;
     void  *obj;
     void  *undomgr;
-    // TODO: replace, ...
+    // TODO: replacefunc, ...
+    UiObserver *observers;
 };
     
 /*
@@ -229,13 +227,18 @@
     void*(*get)(UiList *list, int i);
     /* get the number of elements */
     int(*count)(UiList *list);
-    /* list of observers */
-    UiObserver *observers;
     /* iterator changes after first() next() and get() */
     void *iter;
     /* private - implementation dependent */
     void *data;
     
+    /* binding function */
+    void (*update)(UiList *list, int i);
+    /* binding object */
+    void *obj;
+    
+    /* list of observers */
+    UiObserver *observers;
 };
 
 struct UiRange {
@@ -248,15 +251,14 @@
     double max;
     double extent;
     void   *obj;
+    /* list of observers */
+    UiObserver *observers;
 };
 
 
 void ui_init(char *appname, int argc, char **argv);
 char* ui_appname();
 
-void ui_exitfunc(ui_callback f, void *userdata); // deprecated
-void ui_openfilefunc(ui_callback f, void *userdata); // deprecated
-
 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata);
 
 void ui_onstartup(ui_callback f, void *userdata);
@@ -269,74 +271,18 @@
 
 void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd);
 
-void ui_set_enabled(UIWIDGET widget, int enabled);
-void ui_set_show_all(UIWIDGET widget, int value);
-void ui_set_visible(UIWIDGET widget, int visible);
-
-UIWIDGET ui_vbox(UiObject *obj);
-UIWIDGET ui_hbox(UiObject *obj);
-UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing);
-UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing);
-
-UIWIDGET ui_grid(UiObject *obj);
-UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing);
-
-UIWIDGET ui_scrolledwindow(UiObject *obj);
-
-UIWIDGET ui_sidebar(UiObject *obj);
-void ui_end(UiObject *obj);
-
-UIWIDGET ui_tabview(UiObject *obj);
-void ui_tab(UiObject *obj, char *title);
-void ui_select_tab(UIWIDGET tabview, int tab);
-
-// box container layout functions
-void ui_layout_fill(UiObject *obj, UiBool fill);
-// grid container layout functions
-void ui_layout_hexpand(UiObject *obj, UiBool expand);
-void ui_layout_vexpand(UiObject *obj, UiBool expand);
-void ui_layout_gridwidth(UiObject *obj, int width);
-void ui_newline(UiObject *obj);
-
-
-UiTabbedPane* ui_tabbed_document_view(UiObject *obj);
-
-UiObject* ui_document_tab(UiTabbedPane *view);
-
-
-
+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 *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_document_new(size_t size);
-void  ui_document_destroy(void *doc);
-
 UiContext* ui_document_context(void *doc);
 
-// TODO: remove
-void* ui_document_malloc(void *doc, size_t size);
-void* ui_document_calloc(void *doc, size_t nelem, size_t elsize);
-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);
-
-void ui_document_regtext(void *doc, char *name, UiText *text);
-void ui_document_reglist(void *doc, char *name, UiList *list);
-
-// new:
-int ui_getint(UiObject *obj, char *name);
-char *ui_getstr(UiObject *obj, char *name);
-char* ui_gettext(UiObject *obj, char *name);
 
 
 void ui_set_group(UiContext *ctx, int group);
@@ -349,6 +295,11 @@
 void* ui_realloc(UiContext *ctx, void *ptr, size_t size);
 
 // types
+
+UiInteger* ui_int_new(UiContext *ctx, char *name);
+UiString* ui_string_new(UiContext *ctx, char *name);
+UiText* ui_text_new(UiContext *ctx, char *name);
+
 UiObserver* ui_observer_new(ui_callback f, void *data);
 UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer);
 UiObserver* ui_add_observer(UiObserver *list, ui_callback f, void *data);
@@ -371,6 +322,12 @@
 
 void ui_add_image(char *imgname, char *filename);
 
+// general widget functions
+void ui_set_enabled(UIWIDGET widget, int enabled);
+void ui_set_show_all(UIWIDGET widget, int value);
+void ui_set_visible(UIWIDGET widget, int visible);
+
+
 // label widgets
 UIWIDGET ui_label(UiObject *obj, char *label);
 UIWIDGET ui_llabel(UiObject *obj, char *label);
--- a/ui/ui/tree.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/tree.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
--- a/ui/ui/ui.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/ui.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:
@@ -30,6 +30,7 @@
 #define	UI_H
 
 #include "toolkit.h"
+#include "container.h"
 #include "menu.h"
 #include "toolbar.h"
 #include "window.h"
--- a/ui/ui/window.h	Tue Jan 24 18:46:47 2017 +0100
+++ b/ui/ui/window.h	Fri Nov 10 17:17:14 2017 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * 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:

mercurial