ui/common/context.c

branch
newapi
changeset 178
7c3ff86ee9d4
parent 174
0358f1d9c506
child 187
24ce2c326d85
equal deleted inserted replaced
177:e79a60b3a7cb 178:7c3ff86ee9d4
30 #include <stdlib.h> 30 #include <stdlib.h>
31 #include <string.h> 31 #include <string.h>
32 #include <inttypes.h> 32 #include <inttypes.h>
33 #include <stdarg.h> 33 #include <stdarg.h>
34 34
35 #include <cx/array_list.h>
36 #include <cx/compare.h>
37 #include <cx/basic_mempool.h>
38
35 #include "context.h" 39 #include "context.h"
36 #include "../ui/window.h" 40 #include "../ui/window.h"
37 #include "document.h" 41 #include "document.h"
38 #include "types.h" 42 #include "types.h"
39 43
40 static UiContext* global_context; 44 static UiContext* global_context;
41 45
42 void uic_init_global_context(void) { 46 void uic_init_global_context(void) {
43 UcxMempool *mp = ucx_mempool_new(32); 47 CxMempool *mp = cxBasicMempoolCreate(32);
44 global_context = uic_context(NULL, mp); 48 global_context = uic_context(NULL, mp->allocator);
45 } 49 }
46 50
47 UiContext* ui_global_context(void) { 51 UiContext* ui_global_context(void) {
48 return global_context; 52 return global_context;
49 } 53 }
50 54
51 UiContext* uic_context(UiObject *toplevel, UcxMempool *mp) { 55 UiContext* uic_context(UiObject *toplevel, const CxAllocator *a) {
52 UiContext *ctx = ucx_mempool_malloc(mp, sizeof(UiContext)); 56 UiContext *ctx = cxMalloc(a, sizeof(UiContext));
53 memset(ctx, 0, sizeof(UiContext)); 57 memset(ctx, 0, sizeof(UiContext));
54 ctx->mempool = mp; 58 ctx->allocator = a;
55 ctx->obj = toplevel; 59 ctx->obj = toplevel;
56 ctx->vars = ucx_map_new_a(mp->allocator, 16); 60 ctx->vars = cxHashMapCreate(a, CX_STORE_POINTERS, 16);
61
62 ctx->documents = cxLinkedListCreate(a, cx_cmp_intptr, CX_STORE_POINTERS);
63 ctx->group_widgets = cxLinkedListCreate(a, NULL, sizeof(UiGroupWidget));
64 ctx->groups = cxArrayListCreate(a, cx_cmp_int, sizeof(int), 32);
57 65
58 ctx->attach_document = uic_context_attach_document; 66 ctx->attach_document = uic_context_attach_document;
59 ctx->detach_document2 = uic_context_detach_document2; 67 ctx->detach_document2 = uic_context_detach_document2;
60 68
61 #ifdef UI_GTK 69 #ifdef UI_GTK
71 UiContext* uic_root_context(UiContext *ctx) { 79 UiContext* uic_root_context(UiContext *ctx) {
72 return ctx->parent ? uic_root_context(ctx->parent) : ctx; 80 return ctx->parent ? uic_root_context(ctx->parent) : ctx;
73 } 81 }
74 82
75 void uic_context_attach_document(UiContext *ctx, void *document) { 83 void uic_context_attach_document(UiContext *ctx, void *document) {
76 ctx->documents = ucx_list_append_a(ctx->mempool->allocator, ctx->documents, document); 84 cxListAdd(ctx->documents, document);
77 ctx->document = ctx->documents->data; 85 ctx->document = document;
78 86
79 UiContext *doc_ctx = ui_document_context(document); 87 UiContext *doc_ctx = ui_document_context(document);
80 88
81 // check if any parent context has an unbound variable with the same name 89 // check if any parent context has an unbound variable with the same name
82 // as any document variable 90 // as any document variable
83 UiContext *var_ctx = ctx; 91 UiContext *var_ctx = ctx;
84 while(var_ctx) { 92 while(var_ctx) {
85 if(var_ctx->vars_unbound && var_ctx->vars_unbound->count > 0) { 93 if(var_ctx->vars_unbound && var_ctx->vars_unbound->size > 0) {
86 UcxMapIterator i = ucx_map_iterator(var_ctx->vars_unbound); 94 CxIterator i = cxMapIterator(var_ctx->vars_unbound);
87 UiVar *var; 95 cx_foreach(CxMapEntry*, entry, i) {
88 // rmkeys holds all keys, that shall be removed from vars_unbound 96 UiVar *var = entry->value;
89 UcxKey *rmkeys = calloc(var_ctx->vars_unbound->count, sizeof(UcxKey)); 97 UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key);
90 size_t numkeys = 0;
91 UCX_MAP_FOREACH(key, var, i) {
92 UiVar *docvar = ucx_map_get(doc_ctx->vars, key);
93 if(docvar) { 98 if(docvar) {
94 // bind var to document var 99 // bind var to document var
95 uic_copy_binding(var, docvar, TRUE); 100 uic_copy_binding(var, docvar, TRUE);
96 rmkeys[numkeys++] = key; // save the key for removal 101 cxIteratorFlagRemoval(i);
97 } 102 }
98 } 103 }
99 // now that we may have bound some vars to the document,
100 // we can remove them from the unbound map
101 for(size_t k=0;k<numkeys;k++) {
102 ucx_map_remove(var_ctx->vars_unbound, rmkeys[k]);
103 }
104 } 104 }
105 105
106 var_ctx = ctx->parent; 106 var_ctx = ctx->parent;
107 } 107 }
108 } 108 }
109 109
110 static void uic_context_unbind_vars(UiContext *ctx) { 110 static void uic_context_unbind_vars(UiContext *ctx) {
111 UcxMapIterator i = ucx_map_iterator(ctx->vars); 111 CxIterator i = cxMapIterator(ctx->vars);
112 UiVar *var; 112 cx_foreach(CxMapEntry*, entry, i) {
113 UCX_MAP_FOREACH(key, var, i) { 113 UiVar *var = entry->value;
114 if(var->from && var->from_ctx) { 114 if(var->from && var->from_ctx) {
115 uic_save_var2(var); 115 uic_save_var2(var);
116 uic_copy_binding(var, var->from, FALSE); 116 uic_copy_binding(var, var->from, FALSE);
117 ucx_map_put(var->from_ctx->vars_unbound, key, var->from); 117 cxMapPut(var->from_ctx->vars_unbound, *entry->key, var->from);
118 var->from_ctx = ctx; 118 var->from_ctx = ctx;
119 } 119 }
120 } 120 }
121 121
122 UCX_FOREACH(elm, ctx->documents) { 122 if(ctx->documents) {
123 UiContext *subctx = ui_document_context(elm->data); 123 i = cxListIterator(ctx->documents);
124 uic_context_unbind_vars(subctx); 124 cx_foreach(void *, doc, i) {
125 UiContext *subctx = ui_document_context(doc);
126 uic_context_unbind_vars(subctx);
127 }
125 } 128 }
126 } 129 }
127 130
128 void uic_context_detach_document2(UiContext *ctx, void *document) { 131 void uic_context_detach_document2(UiContext *ctx, void *document) {
129 // find the document in the documents list 132 // find the document in the documents list
130 UcxList *doc = NULL; 133 ssize_t docIndex = cxListFind(ctx->documents, document);
131 UCX_FOREACH(elm, ctx->documents) { 134 if(docIndex < 0) {
132 if(elm->data == document) { 135 return;
133 doc = elm; 136 }
134 break; 137
135 } 138 cxListRemove(ctx->documents, docIndex);
136 } 139 ctx->document = cxListAt(ctx->documents, 0);
137 if(!doc) {
138 return; // document is not a subdocument of this context
139 }
140
141 ctx->documents = ucx_list_remove_a(ctx->mempool->allocator, ctx->documents, doc);
142 ctx->document = ctx->documents ? ctx->documents->data : NULL;
143 140
144 UiContext *docctx = ui_document_context(document); 141 UiContext *docctx = ui_document_context(document);
145 uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent 142 uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent
146 } 143 }
147 144
148 void uic_context_detach_all(UiContext *ctx) { 145 void uic_context_detach_all(UiContext *ctx) {
149 UcxList *ls = ucx_list_clone(ctx->documents, NULL, NULL); 146 // copy list
150 UCX_FOREACH(elm, ls) { 147 CxList *ls = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS);
151 ctx->detach_document2(ctx, elm->data); 148 CxIterator i = cxListIterator(ctx->documents);
152 } 149 cx_foreach(void *, doc, i) {
153 ucx_list_free(ls); 150 cxListAdd(ls, doc);
154 } 151 }
155 152
156 static UiVar* ctx_getvar(UiContext *ctx, UcxKey key) { 153 // detach documents
157 UiVar *var = ucx_map_get(ctx->vars, key); 154 i = cxListIterator(ls);
155 cx_foreach(void *, doc, i) {
156 ctx->detach_document2(ctx, doc);
157 }
158
159 cxListDestroy(ls);
160 }
161
162 static UiVar* ctx_getvar(UiContext *ctx, CxHashKey key) {
163 UiVar *var = cxMapGet(ctx->vars, key);
158 if(!var) { 164 if(!var) {
159 UCX_FOREACH(elm, ctx->documents) { 165 CxIterator i = cxListIterator(ctx->documents);
160 UiContext *subctx = ui_document_context(elm->data); 166 cx_foreach(void *, doc, i) {
167 UiContext *subctx = ui_document_context(doc);
161 var = ctx_getvar(subctx, key); 168 var = ctx_getvar(subctx, key);
162 if(var) { 169 if(var) {
163 break; 170 break;
164 } 171 }
165 } 172 }
166 } 173 }
167 return var; 174 return var;
168 } 175 }
169 176
170 UiVar* uic_get_var(UiContext *ctx, const char *name) { 177 UiVar* uic_get_var(UiContext *ctx, const char *name) {
171 UcxKey key = ucx_key(name, strlen(name)); 178 CxHashKey key = cx_hash_key(name, strlen(name));
172 return ctx_getvar(ctx, key); 179 return ctx_getvar(ctx, key);
173 } 180 }
174 181
175 UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) { 182 UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) {
176 UiVar *var = uic_get_var(ctx, name); 183 UiVar *var = uic_get_var(ctx, name);
187 var->value = uic_create_value(ctx, type); 194 var->value = uic_create_value(ctx, type);
188 var->from = NULL; 195 var->from = NULL;
189 var->from_ctx = ctx; 196 var->from_ctx = ctx;
190 197
191 if(!ctx->vars_unbound) { 198 if(!ctx->vars_unbound) {
192 ctx->vars_unbound = ucx_map_new_a(ctx->mempool->allocator, 16); 199 ctx->vars_unbound = cxHashMapCreate(ctx->allocator, CX_STORE_POINTERS, 16);
193 } 200 }
194 ucx_map_cstr_put(ctx->vars_unbound, name, var); 201 cxMapPut(ctx->vars_unbound, name, var);
195 202
196 return var; 203 return var;
197 } 204 }
198 205
199 void* uic_create_value(UiContext *ctx, UiVarType type) { 206 void* uic_create_value(UiContext *ctx, UiVarType type) {
356 UiVar *var = ui_malloc(ctx, sizeof(UiVar)); 363 UiVar *var = ui_malloc(ctx, sizeof(UiVar));
357 var->type = type; 364 var->type = type;
358 var->value = value; 365 var->value = value;
359 var->from = NULL; 366 var->from = NULL;
360 var->from_ctx = ctx; 367 var->from_ctx = ctx;
361 size_t oldcount = ctx->vars->count; 368 size_t oldcount = ctx->vars->size;
362 ucx_map_cstr_put(ctx->vars, name, var); 369 cxMapPut(ctx->vars, name, var);
363 if(ctx->vars->count != oldcount + 1) { 370 if(ctx->vars->size != oldcount + 1) {
364 fprintf(stderr, "UiError: var '%s' already exists\n", name); 371 fprintf(stderr, "UiError: var '%s' already exists\n", name);
365 } 372 }
366 373
367 // TODO: remove? 374 // TODO: remove?
368 // a widget is already bound to a var with this name 375 // a widget is already bound to a var with this name
373 } 380 }
374 */ 381 */
375 } 382 }
376 383
377 void uic_remove_bound_var(UiContext *ctx, UiVar *var) { 384 void uic_remove_bound_var(UiContext *ctx, UiVar *var) {
378 // TODO: implement 385 // TODO
379 printf("TODO: implement uic_remove_bound_var\n");
380 } 386 }
381 387
382 388
383 // public API 389 // public API
384 390
395 ctx->close_data = udata; 401 ctx->close_data = udata;
396 } 402 }
397 403
398 404
399 void ui_set_group(UiContext *ctx, int group) { 405 void ui_set_group(UiContext *ctx, int group) {
400 if(ucx_list_find(ctx->groups, (void*)(intptr_t)group, NULL, NULL) == -1) { 406 if(cxListFind(ctx->groups, &group) == -1) {
401 ctx->groups = ucx_list_append_a(ctx->mempool->allocator, ctx->groups, (void*)(intptr_t)group); 407 cxListAdd(ctx->groups, &group);
402 } 408 }
403 409
404 // enable/disable group widgets 410 // enable/disable group widgets
405 uic_check_group_widgets(ctx); 411 uic_check_group_widgets(ctx);
406 } 412 }
407 413
408 void ui_unset_group(UiContext *ctx, int group) { 414 void ui_unset_group(UiContext *ctx, int group) {
409 int i = ucx_list_find(ctx->groups, (void*)(intptr_t)group, NULL, NULL); 415 int i = cxListFind(ctx->groups, &group);
410 if(i != -1) { 416 if(i != -1) {
411 UcxList *elm = ucx_list_get(ctx->groups, i); 417 cxListRemove(ctx->groups, i);
412 ctx->groups = ucx_list_remove_a(ctx->mempool->allocator, ctx->groups, elm);
413 } 418 }
414 419
415 // enable/disable group widgets 420 // enable/disable group widgets
416 uic_check_group_widgets(ctx); 421 uic_check_group_widgets(ctx);
417 } 422 }
418 423
419 int* ui_active_groups(UiContext *ctx, int *ngroups) { 424 int* ui_active_groups(UiContext *ctx, int *ngroups) {
420 if(!ctx->groups) { 425 *ngroups = ctx->groups->size;
421 return NULL; 426 return cxListAt(ctx->groups, 0);
422 }
423
424 int nelm = ucx_list_size(ctx->groups);
425 int *groups = calloc(sizeof(int), nelm);
426
427 int i = 0;
428 UCX_FOREACH(elm, ctx->groups) {
429 groups[i++] = (intptr_t)elm->data;
430 }
431
432 *ngroups = nelm;
433 return groups;
434 } 427 }
435 428
436 void uic_check_group_widgets(UiContext *ctx) { 429 void uic_check_group_widgets(UiContext *ctx) {
437 int ngroups = 0; 430 int ngroups = 0;
438 int *groups = ui_active_groups(ctx, &ngroups); 431 int *groups = ui_active_groups(ctx, &ngroups);
439 432
440 UCX_FOREACH(elm, ctx->group_widgets) { 433 CxIterator i = cxListIterator(ctx->group_widgets);
441 UiGroupWidget *gw = elm->data; 434 cx_foreach(UiGroupWidget *, gw, i) {
442 char *check = calloc(1, gw->numgroups); 435 char *check = calloc(1, gw->numgroups);
443 436
444 for(int i=0;i<ngroups;i++) { 437 for(int i=0;i<ngroups;i++) {
445 for(int k=0;k<gw->numgroups;k++) { 438 for(int k=0;k<gw->numgroups;k++) {
446 if(groups[i] == gw->groups[k]) { 439 if(groups[i] == gw->groups[k]) {
454 if(check[i] == 0) { 447 if(check[i] == 0) {
455 enable = 0; 448 enable = 0;
456 break; 449 break;
457 } 450 }
458 } 451 }
452 free(check);
459 gw->enable(gw->widget, enable); 453 gw->enable(gw->widget, enable);
460 }
461
462 if(groups) {
463 free(groups);
464 } 454 }
465 } 455 }
466 456
467 void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) { 457 void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
468 // get groups 458 // get groups
469 UcxList *groups = NULL; 459 CxList *groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16);
470 va_list ap; 460 va_list ap;
471 va_start(ap, enable); 461 va_start(ap, enable);
472 int group; 462 int group;
473 while((group = va_arg(ap, int)) != -1) { 463 while((group = va_arg(ap, int)) != -1) {
474 groups = ucx_list_append(groups, (void*)(intptr_t)group); 464 cxListAdd(groups, &group);
475 } 465 }
476 va_end(ap); 466 va_end(ap);
477 467
478 uic_add_group_widget(ctx, widget, enable, groups); 468 uic_add_group_widget(ctx, widget, enable, groups);
479 469
480 ucx_list_free(groups); 470 cxListDestroy(groups);
481 } 471 }
482 472
483 void uic_add_group_widget(UiContext *ctx, void *widget, ui_enablefunc enable, UcxList *groups) { 473 void uic_add_group_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *groups) {
484 UcxMempool *mp = ctx->mempool; 474 const CxAllocator *a = ctx->allocator;
485 UiGroupWidget *gw = ucx_mempool_malloc(mp, sizeof(UiGroupWidget)); 475 UiGroupWidget gw;
486 476
487 gw->widget = widget; 477 gw.widget = widget;
488 gw->enable = enable; 478 gw.enable = enable;
489 gw->numgroups = ucx_list_size(groups); 479 gw.numgroups = groups->size;
490 gw->groups = ucx_mempool_calloc(mp, gw->numgroups, sizeof(int)); 480 gw.groups = cxCalloc(a, gw.numgroups, sizeof(int));
491 int i = 0; 481
492 UCX_FOREACH(elm, groups) { 482 // copy groups
493 gw->groups[i++] = (intptr_t)elm->data; 483 int *intgroups = cxListAt(groups, 0);
494 } 484 if(intgroups) {
495 485 memcpy(gw.groups, intgroups, gw.numgroups * sizeof(int));
496 ctx->group_widgets = ucx_list_append_a( 486 }
497 mp->allocator, 487
498 ctx->group_widgets, 488 cxListAdd(ctx->group_widgets, &gw);
499 gw);
500 } 489 }
501 490
502 void* ui_malloc(UiContext *ctx, size_t size) { 491 void* ui_malloc(UiContext *ctx, size_t size) {
503 return ctx ? ucx_mempool_malloc(ctx->mempool, size) : NULL; 492 return ctx ? cxMalloc(ctx->allocator, size) : NULL;
504 } 493 }
505 494
506 void* ui_calloc(UiContext *ctx, size_t nelem, size_t elsize) { 495 void* ui_calloc(UiContext *ctx, size_t nelem, size_t elsize) {
507 return ctx ? ucx_mempool_calloc(ctx->mempool, nelem, elsize) : NULL; 496 return ctx ? cxCalloc(ctx->allocator, nelem, elsize) : NULL;
508 } 497 }
509 498
510 void ui_free(UiContext *ctx, void *ptr) { 499 void ui_free(UiContext *ctx, void *ptr) {
511 if(ctx) { 500 if(ctx) {
512 ucx_mempool_free(ctx->mempool, ptr); 501 cxFree(ctx->allocator, ptr);
513 } 502 }
514 } 503 }
515 504
516 void* ui_realloc(UiContext *ctx, void *ptr, size_t size) { 505 void* ui_realloc(UiContext *ctx, void *ptr, size_t size) {
517 return ctx ? ucx_mempool_realloc(ctx->mempool, ptr, size) : NULL; 506 return ctx ? cxRealloc(ctx->allocator, ptr, size) : NULL;
518 } 507 }
519 508

mercurial