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); |
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 |