ui/common/context.c

changeset 140
c03c338a7dcf
parent 131
774b741984a2
child 141
cc2170ea05ad
equal deleted inserted replaced
139:dbde25a5bc53 140:c03c338a7dcf
1 /* 1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 * 3 *
4 * Copyright 2014 Olaf Wintermann. All rights reserved. 4 * Copyright 2017 Olaf Wintermann. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met: 7 * modification, are permitted provided that the following conditions are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
32 #include <inttypes.h> 32 #include <inttypes.h>
33 33
34 #include "context.h" 34 #include "context.h"
35 #include "../ui/window.h" 35 #include "../ui/window.h"
36 #include "document.h" 36 #include "document.h"
37 #include "types.h"
37 38
38 39
39 UiContext* uic_context(UiObject *toplevel, UcxMempool *mp) { 40 UiContext* uic_context(UiObject *toplevel, UcxMempool *mp) {
40 UiContext *ctx = ucx_mempool_malloc(mp, sizeof(UiContext)); 41 UiContext *ctx = ucx_mempool_malloc(mp, sizeof(UiContext));
41 memset(ctx, 0, sizeof(UiContext)); 42 memset(ctx, 0, sizeof(UiContext));
62 63
63 void uic_context_set_document(UiContext *ctx, void *document) { 64 void uic_context_set_document(UiContext *ctx, void *document) {
64 if(ctx->document == document) { 65 if(ctx->document == document) {
65 return; 66 return;
66 } 67 }
68 if(ctx->document) {
69 uic_context_detach_document(ctx);
70 }
71 ctx->document = document;
67 72
68 UiContext *docctx = ui_document_context(document); 73 UiContext *docctx = ui_document_context(document);
69 if(!docctx) { 74 if(!docctx) {
75 fprintf(stderr, "UiError: uic_context_set_document: pointer is not a document\n");
70 return; 76 return;
71 } 77 }
72 docctx->obj = ctx->obj; 78 docctx->obj = ctx->obj;
73 docctx->parent = ctx; 79 docctx->parent = ctx;
74 80
75 if(ctx->document) { 81 UiContext *root = uic_root_context(ctx);
76 uic_context_detach_document(ctx, ctx->document); 82 if(!root->bound || root->bound->count == 0) {
77 } 83 return;
78 //obj->document = document; 84 }
79 ctx->document = document; 85
80 86 // there are bound variables in the root ctx
87 // copy bindings with correct name to doc vars
81 UcxMapIterator i = ucx_map_iterator(docctx->vars); 88 UcxMapIterator i = ucx_map_iterator(docctx->vars);
82 UiVar *var; 89 UiVar *var;
83 UCX_MAP_FOREACH(key, var, i) { 90 UCX_MAP_FOREACH(key, var, i) {
84 UiVar *v = ucx_map_get(uic_root_context(ctx)->vars, key); 91 UiVar *v = ucx_map_get(root->bound, key);
85 if(v) { 92 if(v) {
86 if(v->isextern) { 93 // copy binding: after this all doc vars with names of previously
87 fprintf( 94 // bound variables are bound to the widgets
88 stderr, 95 // the widgets still hold a pointer to the root ctx vars, but this
89 "UI Error: external variable cannot be moved\n"); 96 // vars have a pointer to the document variable value - confusing
90 return; 97 uic_copy_binding(v, var, TRUE);
91 } 98 }
92 // check type 99 }
93 if(var->type != v->type) { 100 }
94 fprintf(stderr, "UI Error: var has incompatible type.\n"); 101
95 return; 102 void uic_context_detach_document(UiContext *ctx) {
96 } 103 if(!ctx->document) {
97 104 return;
98 // copy value 105 }
99 uic_move_var(v, var, TRUE); 106
100 var->from = v->from; 107 UiContext *docctx = ui_document_context(ctx->document);
101
102 // TODO: free var struct
103 ucx_map_remove(ctx->vars, key);
104 }
105 }
106 }
107
108 void uic_context_detach_document(UiContext *ctx, void *document) {
109 UiContext *docctx = ui_document_context(document);
110 if(!docctx) { 108 if(!docctx) {
111 fprintf( 109 fprintf(stderr, "UiError: Cannot detach document: no context\n");
112 stderr, 110 return;
113 "UiError: ui_detach_document: document is not registered\n"); 111 }
114 return; 112 ctx->document = NULL;
115 } 113 docctx->parent = NULL;
116 if(ctx->document != document) { 114 docctx->obj = NULL;
117 fprintf(stderr, "UiError: ui_detach_document: wrong document\n"); 115
118 return; 116 // unbind all vars
119 }
120
121 UcxMapIterator i = ucx_map_iterator(docctx->vars); 117 UcxMapIterator i = ucx_map_iterator(docctx->vars);
122 UiVar *var; 118 UiVar *var;
123 UCX_MAP_FOREACH(key, var, i) { 119 UCX_MAP_FOREACH(key, var, i) {
124 if(var->from && var->from != docctx->vars) { 120 if(var->from) {
125 // this var is bind to an outer widget, so we move it 121 // restore old root bound var val
126 UcxAllocator *a = var->from->allocator; 122 var->from->value = var->from->orig_val;
127 UiVar *newvar = a->malloc(a->pool, sizeof(UiVar)); 123 var->from->orig_val = NULL;
128 newvar->value = uic_create_value(a, var->type); 124 // copy
129 uic_move_var(var, newvar, 0); 125 uic_copy_binding(var, var->from, FALSE);
130 newvar->type = var->type; 126 }
131 newvar->from = var->from; 127 uic_unbind_var(var);
132 newvar->isextern = 0; 128 }
133
134 ucx_map_put(var->from, key, newvar);
135
136 //ucx_map_remove(doc->vars, key); // TODO: dont remove!
137 }
138 }
139
140 if(docctx->parent) {
141 docctx->parent->document = NULL;
142 }
143
144 docctx->obj = NULL;
145 docctx->parent = NULL;
146 } 129 }
147 130
148 UiVar* uic_get_var(UiContext *ctx, char *name) { 131 UiVar* uic_get_var(UiContext *ctx, char *name) {
149 // check document variables first 132 // check document variables first
150 UiVar *var = NULL; 133 UiVar *var = NULL;
159 } 142 }
160 143
161 return var; 144 return var;
162 } 145 }
163 146
164 UiVar* uic_connect_var(UiContext *ctx, char *name, int type) { 147 UiVar* uic_create_var(UiContext *ctx, char *name, UiVarType type) {
165 // TODO: get current map (Document Container, Tabbed Pane) 148 // check if this context has a var with this name
166 UcxMap *from = ctx->vars; 149 // otherweise add it to the bound map
167 150 UiVar *cv = ucx_map_cstr_get(ctx->vars, name);
168 UiVar *var = uic_get_var(ctx, name); 151 if(cv) {
169 if(var) { 152 return cv; // I'm not sure if this can actually happen, lol
170 // the value is registered 153 }
171 154
172 // a little type check 155 // create var and add it to the bound map
173 if(var->type != type) { 156 // this map contains vars that are created by widgets
174 fprintf(stderr, "UI Error: var %s has incompatible type.\n", name); 157 // the vars can later be moved to subdocuments
175 return NULL; 158 UiVar *var = ui_malloc(ctx, sizeof(UiVar));
176 } else { 159 var->type = type;
177 // register the current document/wdata map 160 var->value = uic_create_value(ctx, type);
178 // if the document is closed, the var will be moved to this map 161 var->orig_val = NULL;
179 var->from = from; 162 var->from = NULL; // not connected to a doc var
180 163
181 return var; 164 if(!ctx->bound) {
182 } 165 ctx->bound = ucx_map_new_a(ctx->mempool->allocator, 16);
183 } else { 166 }
184 // create an empty value and add it to the context variables 167 size_t oldcount = ctx->bound->count;
185 // it can be moved to the document vars later 168 ucx_map_cstr_put(ctx->bound, name, var);
186 void *value = uic_create_value(ctx->mempool->allocator, type); 169 if(ctx->bound->count != oldcount + 1) {
187 if(!value) { 170 fprintf(stderr, "UiError: var '%s' already bound\n", name);
188 fprintf(stderr, "UI Error: Cannot create empty value.\n"); 171 }
189 return NULL; 172
190 } 173 // if a subdocument has a variable with this name, we must copy
191 UiVar *var = ucx_mempool_malloc(ctx->mempool, sizeof(UiVar)); 174 // the binding to the doc var
192 var->value = value; 175 UiContext *doc_ctx = ui_document_context(ctx->document);
193 var->type = type; 176 if(doc_ctx) {
194 var->isextern = 0; 177 UiVar *docvar = uic_get_var(doc_ctx, name);
195 var->from = from; 178 if(docvar) {
196 ucx_map_cstr_put(ctx->vars, name, var); 179 var->orig_val = var->value;
197 return var; 180 var->value = docvar->value;
198 } 181 docvar->from = var;
199 } 182 }
200 183 }
201 void uic_move_var(UiVar *from, UiVar *to, UiBool set) { 184
185 return var;
186 }
187
188 void* uic_create_value(UiContext *ctx, UiVarType type) {
189 void *val = NULL;
190 switch(type) {
191 case UI_VAR_INTEGER: {
192 val = ui_int_new(ctx, NULL);
193 break;
194 }
195 case UI_VAR_STRING: {
196 val = ui_string_new(ctx, NULL);
197 break;
198 }
199 case UI_VAR_TEXT: {
200 val = ui_text_new(ctx, NULL);
201 break;
202 }
203 case UI_VAR_LIST: {
204 val = NULL; // TODO
205 break;
206 }
207 case UI_VAR_RANGE: {
208 val = NULL; // TODO
209 break;
210 }
211 }
212 return val;
213 }
214
215 void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
216 if(copytodoc && from->from) {
217 fprintf(stderr, "UiError: var already connected to a document\n");
218 return;
219 }
220
221 // check type
222 if(from->type != to->type) {
223 fprintf(stderr, "UI Error: var has incompatible type.\n");
224 return;
225 }
226
227 // copy binding
228 // we don't copy the observer, because the from var has never one
202 switch(from->type) { 229 switch(from->type) {
230 default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break;
231 case UI_VAR_SPECIAL: break;
203 case UI_VAR_INTEGER: { 232 case UI_VAR_INTEGER: {
204 //memcpy(to->value, from->value, sizeof(UiInteger));
205 UiInteger *f = from->value; 233 UiInteger *f = from->value;
206 UiInteger *t = to->value; 234 UiInteger *t = to->value;
207 t->get = f->get; 235 if(!copytodoc) {
208 t->set = f->set; 236 f->value = f->get(f);
209 t->obj = f->obj; 237 }
210 if(set) { 238 uic_int_copy(f, t);
239 if(t->value != 0) {
211 t->set(t, t->value); 240 t->set(t, t->value);
241 }
242 break;
243 }
244 case UI_VAR_STRING: {
245 UiString *f = from->value;
246 UiString *t = to->value;
247 uic_string_copy(f, t);
248 if(!copytodoc) {
249 f->value = f->get(f);
212 } else { 250 } else {
213 //t->value = t->get(t); 251 char *tvalue = t->value ? t->value : "";
214 f->value = f->get(f); 252 t->set(t, tvalue);
215 //t->value = 0; 253 }
216 } 254
217 break;
218 }
219 case UI_VAR_STRING: {
220 // TODO
221 break; 255 break;
222 } 256 }
223 case UI_VAR_TEXT: { 257 case UI_VAR_TEXT: {
224 UiText *f = from->value; 258 UiText *f = from->value;
225 UiText *t = to->value; 259 UiText *t = to->value;
226 char *tvalue = t->value ? t->value : ""; 260 uic_text_copy(f, t);
227 int tpos = t->pos; 261 if(!copytodoc) {
228 memcpy(t, f, sizeof(UiText)); 262 f->value = f->get(f);
229 if(set) { 263 } else {
264 char *tvalue = t->value ? t->value : "";
230 t->set(t, tvalue); 265 t->set(t, tvalue);
231 t->setposition(t, tpos); 266 t->setposition(t, t->pos);
232 } else { 267 }
268 break;
269 }
270 case UI_VAR_LIST: {
271 UiList *f = from->value;
272 UiList *t = to->value;
273 uic_list_copy(f, t);
274 t->update(t, -1);
275 }
276 case UI_VAR_RANGE: {
277 UiRange *f = from->value;
278 UiRange *t = to->value;
279 if(!copytodoc) {
233 f->value = f->get(f); 280 f->value = f->get(f);
234 f->pos = f->position(f); 281 }
235 f->set = NULL; 282 uic_range_copy(f, t);
236 f->get = NULL; 283 t->setextent(t, t->extent);
237 f->setposition = NULL; 284 t->setrange(t, t->min, t->max);
238 f->position = NULL; 285 t->set(t, t->value);
239 } 286 }
240 break; 287 }
241 } 288
242 case UI_VAR_LIST: { 289 if(copytodoc) {
243 UiListVar *f = from->value; 290 to->from = from;
244 UiListVar *t = to->value; 291
245 UiList *list = t->listptr->list; 292 from->orig_val = from->value;
246 UiObserver *observers = f->listptr->list->observers; 293 from->value = to->value;
247 t->listptr = f->listptr; 294 }
248 if(set) { 295 }
249 t->listptr->list = list; 296
250 list->observers = observers; 297 void uic_unbind_var(UiVar *var) {
251 ui_notify(observers, list); 298 switch(var->type) {
252 } 299 case UI_VAR_INTEGER: uic_int_unbind(var->value); break;
253 break; 300 case UI_VAR_STRING: uic_string_unbind(var->value); break;
254 } 301 case UI_VAR_TEXT: uic_text_unbind(var->value); break;
255 } 302 case UI_VAR_LIST: uic_list_unbind(var->value); break;
256 } 303 case UI_VAR_RANGE: uic_range_unbind(var->value); break;
257 304 }
258 void uic_reg_var(UiContext *ctx, char *name, int type, size_t vs, void *value) { 305 }
259 UiVar *newvar = ucx_mempool_malloc(ctx->mempool, sizeof(UiVar)); 306
260 newvar->isextern = 1; 307 void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value) {
261 newvar->type = type; 308 UiContext *rootctx = uic_root_context(ctx);
262 newvar->value = value; 309
263 newvar->from = NULL; 310 UiVar *b = NULL;
264 311 if(rootctx->bound) {
265 uic_add_var(ctx, name, newvar, type, vs); 312 // some widgets are already bound to some vars
266 } 313 b = ucx_map_cstr_get(rootctx->bound, name);
267 314 if(b) {
268 void uic_add_var( 315 // a widget is bound to a var with this name
269 UiContext *ctx, 316 // if ctx is the root context we can remove the var from bound
270 char *name, 317 // because set_doc or detach can't fuck things up
271 UiVar *newvar, 318 if(ctx == rootctx) {
272 int type, 319 ucx_map_cstr_remove(ctx->bound, name);
273 size_t vs) 320 // TODO: free stuff
274 { 321 }
275 // if a parent context has a variable with this name, we remove it and put 322 }
276 // it to this context 323 }
277 UiVar *var = ctx->obj ? uic_get_var(ctx->obj->ctx, name) : NULL; 324
278 325 // create new var and add it to doc's vars
279 if(var && var->from != ctx->vars) { 326 UiVar *var = ui_malloc(ctx, sizeof(UiVar));
280 // external variables cannot be moved 327 var->from = NULL;
281 if(var->isextern) { 328 var->orig_val = NULL;
282 fprintf( 329 var->type = type;
283 stderr, 330 var->value = value;
284 "UI Error: external variable %s " 331 size_t oldcount = ctx->vars->count;
285 "cannot be moved to the document.\n", 332 ucx_map_cstr_put(ctx->vars, name, var);
286 name); 333 if(ctx->vars->count != oldcount + 1) {
287 return; 334 fprintf(stderr, "UiError: var '%s' already exists\n", name);
288 } 335 }
289 336
290 // check type 337 // a widget is already bound to a var with this name
291 if(var->type != type) { 338 // copy the binding (like uic_context_set_document)
292 fprintf(stderr, "UI Error: var %s has incompatible type.\n", name); 339 if(b) {
293 return; 340 uic_copy_binding(b, var, TRUE);
294 } 341 }
295 342 }
296 // override document var with window context var 343
297 memcpy(newvar->value, var->value, vs); 344 void uic_remove_bound_var(UiContext *ctx, UiVar *var) {
298 345 // TODO: implement
299 newvar->from = var->from; 346 }
300 347
301 // TODO: free var struct
302 ucx_map_cstr_remove(var->from, name);
303 }
304
305 // finally, add the new variable to the document
306 ucx_map_cstr_put(ctx->vars, name, newvar);
307 }
308
309 void* uic_create_value(UcxAllocator *a, int type) {
310 switch(type) {
311 case UI_VAR_INTEGER: {
312 UiInteger *i = a->calloc(
313 a->pool,
314 1,
315 sizeof(UiInteger));
316 return i;
317 }
318 case UI_VAR_STRING: {
319 UiString *s = a->calloc(
320 a->pool,
321 1,
322 sizeof(UiInteger));
323 return s;
324 }
325 case UI_VAR_TEXT: {
326 UiText *t = a->calloc(
327 a->pool,
328 1,
329 sizeof(UiText));
330 return t;
331 }
332 case UI_VAR_LIST: {
333 UiListVar *l = a->malloc(a->pool, sizeof(UiListVar));
334 UiListPtr *lp = a->malloc(a->pool, sizeof(UiListPtr));
335 l->listptr = lp;
336 lp->list = NULL;
337 // TODO: create empty list
338 return l;
339 }
340 }
341 return NULL;
342 }
343 348
344 // public API 349 // public API
345 350
346 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) { 351 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) {
347 ctx->close_callback = fnc; 352 ctx->close_callback = fnc;
348 ctx->close_data = udata; 353 ctx->close_data = udata;
349 }
350
351 int ui_getint(UiObject *obj, char *name) {
352 UiVar *var = uic_get_var(obj->ctx, name);
353 if(var) {
354 if(var->type == UI_VAR_INTEGER) {
355 UiInteger *i = var->value;
356 if(i->get) {
357 return i->get(i);
358 } else {
359 fprintf(
360 stderr,
361 "UI Error: variable %s is not connected.\n",
362 name);
363 }
364 } else {
365 fprintf(
366 stderr,
367 "UI Error: requested variable %s is not an integer.\n",
368 name);
369 }
370 } else {
371 fprintf(stderr, "UI Error: unkown variable %s.\n", name);
372 }
373 return 0;
374 }
375
376 char* ui_getstr(UiObject *obj, char *name) {
377 UiVar *var = uic_get_var(obj->ctx, name);
378 if(var) {
379 if(var->type == UI_VAR_STRING) {
380 UiString *s = var->value;
381 if(s->get) {
382 return s->get(s);
383 } else {
384 fprintf(
385 stderr,
386 "UI Error: variable %s is not connected.\n",
387 name);
388 }
389 } else {
390 fprintf(
391 stderr,
392 "UI Error: requested variable %s is not an string.\n",
393 name);
394 }
395 } else {
396 fprintf(stderr, "UI Error: unkown variable %s.\n", name);
397 }
398 return NULL;
399 }
400
401 char* ui_gettext(UiObject *obj, char *name) {
402 UiVar *var = uic_get_var(obj->ctx, name);
403 if(var) {
404 if(var->type == UI_VAR_TEXT) {
405 UiText *s = var->value;
406 if(s->get) {
407 return s->get(s);
408 } else {
409 fprintf(
410 stderr,
411 "UI Error: variable %s is not connected.\n",
412 name);
413 }
414 } else {
415 fprintf(
416 stderr,
417 "UI Error: requested variable %s is not a text.\n",
418 name);
419 }
420 } else {
421 fprintf(stderr, "UI Error: unkown variable %s.\n", name);
422 }
423 return NULL;
424 } 354 }
425 355
426 356
427 357
428 void ui_set_group(UiContext *ctx, int group) { 358 void ui_set_group(UiContext *ctx, int group) {

mercurial