| 56 UiContext* uic_context(UiObject *toplevel, CxMempool *mp) { |
56 UiContext* uic_context(UiObject *toplevel, CxMempool *mp) { |
| 57 UiContext *ctx = cxMalloc(mp->allocator, sizeof(UiContext)); |
57 UiContext *ctx = cxMalloc(mp->allocator, sizeof(UiContext)); |
| 58 memset(ctx, 0, sizeof(UiContext)); |
58 memset(ctx, 0, sizeof(UiContext)); |
| 59 ctx->mp = mp; |
59 ctx->mp = mp; |
| 60 ctx->allocator = mp->allocator; |
60 ctx->allocator = mp->allocator; |
| |
61 ctx->destroy_handler = cxArrayListCreate(ctx->allocator, NULL, sizeof(UiDestroyHandler), 16); |
| 61 ctx->obj = toplevel; |
62 ctx->obj = toplevel; |
| 62 ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16); |
63 ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16); |
| 63 |
64 |
| 64 ctx->documents = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, CX_STORE_POINTERS); |
65 ctx->documents = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, CX_STORE_POINTERS); |
| 65 ctx->group_widgets = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, sizeof(UiGroupWidget)); |
66 ctx->group_widgets = cxLinkedListCreate(mp->allocator, cx_cmp_ptr, sizeof(UiGroupWidget)); |
| 66 ctx->groups = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32); |
67 ctx->groups = cxArrayListCreate(mp->allocator, cx_cmp_int, sizeof(int), 32); |
| 67 |
68 |
| 68 ctx->attach_document = uic_context_attach_document; |
69 ctx->attach_document = uic_context_attach_document; |
| 69 ctx->detach_document2 = uic_context_detach_document2; |
70 ctx->detach_document2 = uic_context_detach_document; |
| 70 |
71 |
| 71 #if UI_GTK2 || UI_GTK3 |
72 #if UI_GTK2 || UI_GTK3 |
| 72 if(toplevel && toplevel->widget) { |
73 if(toplevel && toplevel->widget) { |
| 73 ctx->accel_group = gtk_accel_group_new(); |
74 ctx->accel_group = gtk_accel_group_new(); |
| 74 gtk_window_add_accel_group(GTK_WINDOW(toplevel->widget), ctx->accel_group); |
75 gtk_window_add_accel_group(GTK_WINDOW(toplevel->widget), ctx->accel_group); |
| 78 return ctx; |
79 return ctx; |
| 79 } |
80 } |
| 80 |
81 |
| 81 UiContext* uic_root_context(UiContext *ctx) { |
82 UiContext* uic_root_context(UiContext *ctx) { |
| 82 return ctx->parent ? uic_root_context(ctx->parent) : ctx; |
83 return ctx->parent ? uic_root_context(ctx->parent) : ctx; |
| |
84 } |
| |
85 |
| |
86 void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data) { |
| |
87 UiDestroyHandler handler; |
| |
88 handler.destructor = func; |
| |
89 handler.data = data; |
| |
90 cxListAdd(ctx->destroy_handler, &handler); |
| 83 } |
91 } |
| 84 |
92 |
| 85 void uic_context_prepare_close(UiContext *ctx) { |
93 void uic_context_prepare_close(UiContext *ctx) { |
| 86 cxListClear(ctx->groups); |
94 cxListClear(ctx->groups); |
| 87 cxListClear(ctx->group_widgets); |
95 cxListClear(ctx->group_widgets); |
| 118 |
126 |
| 119 static void uic_context_unbind_vars(UiContext *ctx) { |
127 static void uic_context_unbind_vars(UiContext *ctx) { |
| 120 CxMapIterator mi = cxMapIterator(ctx->vars); |
128 CxMapIterator mi = cxMapIterator(ctx->vars); |
| 121 cx_foreach(CxMapEntry*, entry, mi) { |
129 cx_foreach(CxMapEntry*, entry, mi) { |
| 122 UiVar *var = entry->value; |
130 UiVar *var = entry->value; |
| 123 if(var->from && var->from_ctx && var->from_ctx != ctx) { |
131 // var->from && var->from_ctx && var->from_ctx != ctx |
| |
132 if(var->from) { |
| 124 uic_save_var2(var); |
133 uic_save_var2(var); |
| 125 uic_copy_binding(var, var->from, FALSE); |
134 uic_copy_binding(var, var->from, FALSE); |
| 126 cxMapPut(var->from_ctx->vars_unbound, *entry->key, var->from); |
135 cxMapPut(var->from->from_ctx->vars_unbound, *entry->key, var->from); |
| 127 var->from_ctx = ctx; |
136 var->from = NULL; |
| 128 } |
137 } |
| 129 } |
138 } |
| 130 |
139 |
| 131 if(ctx->documents) { |
140 if(ctx->documents) { |
| 132 CxIterator i = cxListIterator(ctx->documents); |
141 CxIterator i = cxListIterator(ctx->documents); |
| 284 fprintf(stderr, "UI Error: var has incompatible type.\n"); |
295 fprintf(stderr, "UI Error: var has incompatible type.\n"); |
| 285 return; |
296 return; |
| 286 } |
297 } |
| 287 |
298 |
| 288 void *fromvalue = from->value; |
299 void *fromvalue = from->value; |
| |
300 void *tovalue = to->value; |
| 289 // update var |
301 // update var |
| 290 if(copytodoc) { |
302 if(copytodoc) { |
| 291 to->from = from; |
303 to->from = from; // from which UiVar are the bindings copied |
| 292 to->from_ctx = from->from_ctx; |
304 from->original_value = fromvalue; // save original value otherwise it would be lost |
| |
305 // widgets store a reference to the UiVar with their value |
| |
306 // the UiVar object must be updated to contain the current value object |
| |
307 from->value = tovalue; |
| |
308 } else { |
| |
309 if(to->original_value) { |
| |
310 to->value = to->original_value; |
| |
311 tovalue = to->value; |
| |
312 } |
| 293 } |
313 } |
| 294 |
314 |
| 295 ui_setop_enable(TRUE); |
315 ui_setop_enable(TRUE); |
| 296 |
316 |
| 297 // copy binding |
317 // copy binding |
| 299 switch(from->type) { |
319 switch(from->type) { |
| 300 default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break; |
320 default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break; |
| 301 case UI_VAR_SPECIAL: break; |
321 case UI_VAR_SPECIAL: break; |
| 302 case UI_VAR_INTEGER: { |
322 case UI_VAR_INTEGER: { |
| 303 UiInteger *f = fromvalue; |
323 UiInteger *f = fromvalue; |
| 304 UiInteger *t = to->value; |
324 UiInteger *t = tovalue; |
| 305 if(!f->obj) break; |
325 if(!f->obj) break; |
| 306 uic_int_copy(f, t); |
326 uic_int_copy(f, t); |
| 307 t->set(t, t->value); |
327 t->set(t, t->value); |
| 308 break; |
328 break; |
| 309 } |
329 } |
| 310 case UI_VAR_DOUBLE: { |
330 case UI_VAR_DOUBLE: { |
| 311 UiDouble *f = fromvalue; |
331 UiDouble *f = fromvalue; |
| 312 UiDouble *t = to->value; |
332 UiDouble *t = tovalue; |
| 313 if(!f->obj) break; |
333 if(!f->obj) break; |
| 314 uic_double_copy(f, t); |
334 uic_double_copy(f, t); |
| 315 t->set(t, t->value); |
335 t->set(t, t->value); |
| 316 break; |
336 break; |
| 317 } |
337 } |
| 318 case UI_VAR_STRING: { |
338 case UI_VAR_STRING: { |
| 319 UiString *f = fromvalue; |
339 UiString *f = fromvalue; |
| 320 UiString *t = to->value; |
340 UiString *t = tovalue; |
| 321 if(!f->obj) break; |
341 if(!f->obj) break; |
| 322 uic_string_copy(f, t); |
342 uic_string_copy(f, t); |
| 323 char *tvalue = t->value.ptr ? t->value.ptr : ""; |
343 char *tvalue = t->value.ptr ? t->value.ptr : ""; |
| |
344 char *fvalue = f->value.ptr ? f->value.ptr : ""; |
| 324 t->set(t, tvalue); |
345 t->set(t, tvalue); |
| 325 break; |
346 break; |
| 326 } |
347 } |
| 327 case UI_VAR_TEXT: { |
348 case UI_VAR_TEXT: { |
| 328 UiText *f = fromvalue; |
349 UiText *f = fromvalue; |
| 329 UiText *t = to->value; |
350 UiText *t = tovalue; |
| 330 if(!f->obj) break; |
351 if(!f->obj) break; |
| 331 uic_text_copy(f, t); |
352 uic_text_copy(f, t); |
| 332 t->restore(t); |
353 t->restore(t); |
| 333 break; |
354 break; |
| 334 } |
355 } |
| 335 case UI_VAR_LIST: { |
356 case UI_VAR_LIST: { |
| 336 // TODO: not sure how correct this is |
357 UiList *f = fromvalue; |
| 337 |
358 UiList *t = tovalue; |
| 338 UiList *f = from->value; |
359 uic_list_copy(f, t); |
| 339 UiList *t = to->value; |
360 ui_list_update(t); |
| 340 if (f->obj) { |
|
| 341 t->obj = f->obj; |
|
| 342 t->update = f->update; |
|
| 343 t->getselection = f->getselection; |
|
| 344 t->setselection = f->setselection; |
|
| 345 } |
|
| 346 |
|
| 347 UiVar tmp = *from; |
|
| 348 *from = *to; |
|
| 349 *to = tmp; |
|
| 350 |
|
| 351 UiList* t2 = to->value; |
|
| 352 if(t->update) { |
|
| 353 t->update(t, -1); |
|
| 354 } |
|
| 355 ui_notify(t2->observers, NULL); // TODO: why not t? |
|
| 356 |
|
| 357 break; |
361 break; |
| 358 } |
362 } |
| 359 case UI_VAR_RANGE: { |
363 case UI_VAR_RANGE: { |
| 360 UiRange *f = fromvalue; |
364 UiRange *f = fromvalue; |
| 361 UiRange *t = to->value; |
365 UiRange *t = tovalue; |
| 362 if(!f->obj) break; |
366 if(!f->obj) break; |
| 363 uic_range_copy(f, t); |
367 uic_range_copy(f, t); |
| 364 t->setextent(t, t->extent); |
368 t->setextent(t, t->extent); |
| 365 t->setrange(t, t->min, t->max); |
369 t->setrange(t, t->min, t->max); |
| 366 t->set(t, t->value); |
370 t->set(t, t->value); |
| 367 break; |
371 break; |
| 368 } |
372 } |
| 369 case UI_VAR_GENERIC: { |
373 case UI_VAR_GENERIC: { |
| 370 UiGeneric *f = fromvalue; |
374 UiGeneric *f = fromvalue; |
| 371 UiGeneric *t = to->value; |
375 UiGeneric *t = tovalue; |
| 372 if(!f->obj) break; |
376 if(!f->obj) break; |
| 373 uic_generic_copy(f, t); |
377 uic_generic_copy(f, t); |
| 374 t->set(t, t->value, t->type); |
378 t->set(t, t->value, t->type); |
| 375 break; |
379 break; |
| 376 } |
380 } |
| 403 case UI_VAR_RANGE: uic_range_unbind(var->value); break; |
407 case UI_VAR_RANGE: uic_range_unbind(var->value); break; |
| 404 case UI_VAR_GENERIC: uic_generic_unbind(var->value); break; |
408 case UI_VAR_GENERIC: uic_generic_unbind(var->value); break; |
| 405 } |
409 } |
| 406 } |
410 } |
| 407 |
411 |
| 408 void uic_reg_var(UiContext *ctx, char *name, UiVarType type, void *value) { |
412 void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) { |
| 409 // TODO: do we need/want this? Why adding vars to a context after |
413 // TODO: do we need/want this? Why adding vars to a context after |
| 410 // widgets reference these? Workarounds: |
414 // widgets reference these? Workarounds: |
| 411 // 1. add vars to ctx before creating ui |
415 // 1. add vars to ctx before creating ui |
| 412 // 2. create ui, create new document with vars, attach doc |
416 // 2. create ui, create new document with vars, attach doc |
| 413 // also it would be possible to create a function, that scans unbound vars |
417 // also it would be possible to create a function, that scans unbound vars |
| 461 |
465 |
| 462 void ui_attach_document(UiContext *ctx, void *document) { |
466 void ui_attach_document(UiContext *ctx, void *document) { |
| 463 uic_context_attach_document(ctx, document); |
467 uic_context_attach_document(ctx, document); |
| 464 } |
468 } |
| 465 |
469 |
| 466 void ui_detach_document2(UiContext *ctx, void *document) { |
470 void ui_detach_document(UiContext *ctx, void *document) { |
| 467 uic_context_detach_document2(ctx, document); |
471 uic_context_detach_document(ctx, document); |
| 468 } |
472 } |
| 469 |
473 |
| 470 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) { |
474 void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) { |
| 471 ctx->close_callback = fnc; |
475 ctx->close_callback = fnc; |
| 472 ctx->close_data = udata; |
476 ctx->close_data = udata; |
| 473 } |
477 } |
| 474 |
478 |
| 475 UIEXPORT void ui_context_destroy(UiContext *ctx) { |
479 void ui_context_destroy(UiContext *ctx) { |
| |
480 CxIterator i = cxListIterator(ctx->destroy_handler); |
| |
481 cx_foreach(UiDestroyHandler *, h, i) { |
| |
482 h->destructor(h->data); |
| |
483 } |
| 476 cxMempoolFree(ctx->mp); |
484 cxMempoolFree(ctx->mp); |
| |
485 } |
| |
486 |
| |
487 UiContext* ui_context_parent(UiContext *ctx) { |
| |
488 return ctx->parent; |
| 477 } |
489 } |
| 478 |
490 |
| 479 |
491 |
| 480 void ui_set_group(UiContext *ctx, int group) { |
492 void ui_set_group(UiContext *ctx, int group) { |
| 481 if(!cxListIndexValid(ctx->groups, cxListFind(ctx->groups, &group))) { |
493 if(!cxListIndexValid(ctx->groups, cxListFind(ctx->groups, &group))) { |