ui/common/context.c

changeset 140
c03c338a7dcf
parent 131
774b741984a2
child 141
cc2170ea05ad
--- 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) {

mercurial