| 112 printf("attach %.*s\n", (int)entry->key->len, (char*)entry->key->data); |
112 printf("attach %.*s\n", (int)entry->key->len, (char*)entry->key->data); |
| 113 UiVar *var = entry->value; |
113 UiVar *var = entry->value; |
| 114 UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key); |
114 UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key); |
| 115 if(docvar) { |
115 if(docvar) { |
| 116 // bind var to document var |
116 // bind var to document var |
| 117 uic_copy_binding(var, docvar, TRUE); |
117 uic_copy_var_binding(var, docvar, TRUE); |
| 118 cxIteratorFlagRemoval(i); |
118 cxIteratorFlagRemoval(i); |
| 119 } |
119 } |
| 120 } |
120 } |
| 121 |
121 |
| 122 var_ctx = var_ctx->parent; |
122 var_ctx = var_ctx->parent; |
| 128 cx_foreach(CxMapEntry*, entry, mi) { |
128 cx_foreach(CxMapEntry*, entry, mi) { |
| 129 UiVar *var = entry->value; |
129 UiVar *var = entry->value; |
| 130 // var->from && var->from_ctx && var->from_ctx != ctx |
130 // var->from && var->from_ctx && var->from_ctx != ctx |
| 131 uic_save_var(var); |
131 uic_save_var(var); |
| 132 if(var->from) { |
132 if(var->from) { |
| 133 uic_copy_binding(var, var->from, FALSE); |
133 uic_copy_var_binding(var, var->from, FALSE); |
| 134 cxMapPut(var->from->from_ctx->vars, *entry->key, var->from); |
134 cxMapPut(var->from->from_ctx->vars, *entry->key, var->from); |
| 135 var->from = NULL; |
135 var->from = NULL; |
| 136 } |
136 } |
| 137 } |
137 } |
| 138 |
138 |
| 264 } |
265 } |
| 265 } |
266 } |
| 266 return val; |
267 return val; |
| 267 } |
268 } |
| 268 |
269 |
| |
270 // destroys a value, that was created by uic_create_value |
| |
271 void uic_destroy_value(UiContext *ctx, UiVarType type, void *value) { |
| |
272 switch(type) { |
| |
273 default: { |
| |
274 ui_free(ctx, value); |
| |
275 break; |
| |
276 } |
| |
277 case UI_VAR_SPECIAL: break; |
| |
278 case UI_VAR_STRING: { |
| |
279 UiString *s = value; |
| |
280 if(s->value.free) { |
| |
281 s->value.free(s->value.ptr); |
| |
282 } |
| |
283 ui_free(ctx, value); |
| |
284 } |
| |
285 case UI_VAR_TEXT: { |
| |
286 UiText *t = value; |
| |
287 if(t->value.free) { |
| |
288 t->value.free(t->value.ptr); |
| |
289 t->value.free = NULL; |
| |
290 t->value.ptr = NULL; |
| |
291 } |
| |
292 if(t->destroy) { |
| |
293 t->destroy(t); |
| |
294 } |
| |
295 ui_free(ctx, value); |
| |
296 } |
| |
297 case UI_VAR_LIST: { |
| |
298 ui_list_free(ctx, value); |
| |
299 break; |
| |
300 } |
| |
301 } |
| |
302 } |
| |
303 |
| 269 |
304 |
| 270 UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type) { |
305 UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type) { |
| 271 if (value) { |
306 if (value) { |
| 272 return uic_create_value_var(current, value); |
307 return uic_create_value_var(current, value); |
| 273 } |
308 } |
| 299 to->value = to->original_value; |
334 to->value = to->original_value; |
| 300 tovalue = to->value; |
335 tovalue = to->value; |
| 301 } |
336 } |
| 302 } |
337 } |
| 303 |
338 |
| 304 ui_setop_enable(TRUE); |
339 uic_copy_value_binding(from->type, from, to); |
| |
340 } |
| |
341 |
| |
342 void uic_copy_value_binding(UiVarType type, void *from, void *to) { |
| |
343 ui_setop_enable(TRUE); |
| 305 |
344 |
| 306 // copy binding |
345 // copy binding |
| 307 // we don't copy the observer, because the from var has never one |
346 // we don't copy the observer, because the from value never has oberservers |
| 308 switch(from->type) { |
347 switch(type) { |
| 309 default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break; |
348 default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break; |
| 310 case UI_VAR_SPECIAL: break; |
349 case UI_VAR_SPECIAL: break; |
| 311 case UI_VAR_INTEGER: { |
350 case UI_VAR_INTEGER: { |
| 312 UiInteger *f = fromvalue; |
351 UiInteger *f = from; |
| 313 UiInteger *t = tovalue; |
352 UiInteger *t = to; |
| 314 if(!f->obj) break; |
353 if(!f->obj) break; |
| 315 uic_int_copy(f, t); |
354 uic_int_copy(f, t); |
| 316 t->set(t, t->value); |
355 t->set(t, t->value); |
| 317 break; |
356 break; |
| 318 } |
357 } |
| 319 case UI_VAR_DOUBLE: { |
358 case UI_VAR_DOUBLE: { |
| 320 UiDouble *f = fromvalue; |
359 UiDouble *f = from; |
| 321 UiDouble *t = tovalue; |
360 UiDouble *t = to; |
| 322 if(!f->obj) break; |
361 if(!f->obj) break; |
| 323 uic_double_copy(f, t); |
362 uic_double_copy(f, t); |
| 324 t->set(t, t->value); |
363 t->set(t, t->value); |
| 325 break; |
364 break; |
| 326 } |
365 } |
| 327 case UI_VAR_STRING: { |
366 case UI_VAR_STRING: { |
| 328 UiString *f = fromvalue; |
367 UiString *f = from; |
| 329 UiString *t = tovalue; |
368 UiString *t = to; |
| 330 if(!f->obj) break; |
369 if(!f->obj) break; |
| 331 uic_string_copy(f, t); |
370 uic_string_copy(f, t); |
| 332 char *tvalue = t->value.ptr ? t->value.ptr : ""; |
371 char *tvalue = t->value.ptr ? t->value.ptr : ""; |
| 333 char *fvalue = f->value.ptr ? f->value.ptr : ""; |
372 char *fvalue = f->value.ptr ? f->value.ptr : ""; |
| 334 t->set(t, tvalue); |
373 t->set(t, tvalue); |
| 335 break; |
374 break; |
| 336 } |
375 } |
| 337 case UI_VAR_TEXT: { |
376 case UI_VAR_TEXT: { |
| 338 UiText *f = fromvalue; |
377 UiText *f = from; |
| 339 UiText *t = tovalue; |
378 UiText *t = to; |
| 340 if(!f->obj) break; |
379 if(!f->obj) break; |
| 341 uic_text_copy(f, t); |
380 uic_text_copy(f, t); |
| 342 t->restore(t); |
381 t->restore(t); |
| 343 break; |
382 break; |
| 344 } |
383 } |
| 345 case UI_VAR_LIST: { |
384 case UI_VAR_LIST: { |
| 346 UiList *f = fromvalue; |
385 UiList *f = from; |
| 347 UiList *t = tovalue; |
386 UiList *t = to; |
| 348 uic_list_copy(f, t); |
387 uic_list_copy(f, t); |
| 349 ui_list_update(t); |
388 ui_list_update(t); |
| 350 break; |
389 break; |
| 351 } |
390 } |
| 352 case UI_VAR_RANGE: { |
391 case UI_VAR_RANGE: { |
| 353 UiRange *f = fromvalue; |
392 UiRange *f = from; |
| 354 UiRange *t = tovalue; |
393 UiRange *t = to; |
| 355 if(!f->obj) break; |
394 if(!f->obj) break; |
| 356 uic_range_copy(f, t); |
395 uic_range_copy(f, t); |
| 357 t->setextent(t, t->extent); |
396 t->setextent(t, t->extent); |
| 358 t->setrange(t, t->min, t->max); |
397 t->setrange(t, t->min, t->max); |
| 359 t->set(t, t->value); |
398 t->set(t, t->value); |
| 360 break; |
399 break; |
| 361 } |
400 } |
| 362 case UI_VAR_GENERIC: { |
401 case UI_VAR_GENERIC: { |
| 363 UiGeneric *f = fromvalue; |
402 UiGeneric *f = from; |
| 364 UiGeneric *t = tovalue; |
403 UiGeneric *t = to; |
| 365 if(!f->obj) break; |
404 if(!f->obj) break; |
| 366 uic_generic_copy(f, t); |
405 uic_generic_copy(f, t); |
| 367 t->set(t, t->value, t->type); |
406 t->set(t, t->value, t->type); |
| 368 break; |
407 break; |
| 369 } |
408 } |
| 396 case UI_VAR_RANGE: uic_range_unbind(var->value); break; |
435 case UI_VAR_RANGE: uic_range_unbind(var->value); break; |
| 397 case UI_VAR_GENERIC: uic_generic_unbind(var->value); break; |
436 case UI_VAR_GENERIC: uic_generic_unbind(var->value); break; |
| 398 } |
437 } |
| 399 } |
438 } |
| 400 |
439 |
| |
440 const char *uic_type2str(UiVarType type) { |
| |
441 switch(type) { |
| |
442 default: return ""; |
| |
443 case UI_VAR_INTEGER: return "int"; |
| |
444 case UI_VAR_DOUBLE: return "double"; |
| |
445 case UI_VAR_STRING: return "string"; |
| |
446 case UI_VAR_TEXT: return "text"; |
| |
447 case UI_VAR_LIST: return "list"; |
| |
448 case UI_VAR_RANGE: return "range"; |
| |
449 case UI_VAR_GENERIC: return "generic"; |
| |
450 } |
| |
451 } |
| |
452 |
| 401 void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) { |
453 void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) { |
| 402 // TODO: do we need/want this? Why adding vars to a context after |
454 UiVar *var = cxMapGet(ctx->vars, name); |
| 403 // widgets reference these? Workarounds: |
455 if(!var) { |
| 404 // 1. add vars to ctx before creating ui |
456 // create new var and add it to the context var map |
| 405 // 2. create ui, create new document with vars, attach doc |
457 var = ui_malloc(ctx, sizeof(UiVar)); |
| 406 // also it would be possible to create a function, that scans unbound vars |
458 cxMapPut(ctx->vars, name, var); |
| 407 // and connects them to available vars |
459 } else { |
| 408 /* |
460 // override var with new value |
| 409 UiContext *rootctx = uic_root_context(ctx); |
461 if(var->type != type) { |
| 410 UiVar *b = NULL; |
462 fprintf(stderr, "Error: var %s type mismatch: %s - %s\n", name, uic_type2str(var->type), type); |
| 411 if(rootctx->bound) { |
463 return; |
| 412 // some widgets are already bound to some vars |
464 } |
| 413 b = ucx_map_cstr_get(rootctx->bound, name); |
465 if(var->bound) { |
| 414 if(b) { |
466 fprintf(stderr, "Error: var %s already bound\n", name); |
| 415 // a widget is bound to a var with this name |
467 return; |
| 416 // if ctx is the root context we can remove the var from bound |
468 } |
| 417 // because set_doc or detach can't fuck things up |
469 UiInteger *prev_value = var->value; |
| 418 if(ctx == rootctx) { |
470 uic_copy_value_binding(type, prev_value, value); |
| 419 ucx_map_cstr_remove(ctx->bound, name); |
471 uic_destroy_value(var->from_ctx, var->type, var->value); |
| 420 // TODO: free stuff |
472 } |
| 421 } |
473 |
| 422 } |
|
| 423 } |
|
| 424 */ |
|
| 425 |
|
| 426 // create new var and add it to doc's vars |
|
| 427 UiVar *var = ui_malloc(ctx, sizeof(UiVar)); |
|
| 428 var->type = type; |
474 var->type = type; |
| 429 var->value = value; |
475 var->value = value; |
| 430 var->from = NULL; |
476 var->from = NULL; |
| 431 var->from_ctx = ctx; |
477 var->from_ctx = ctx; |
| 432 size_t oldcount = cxMapSize(ctx->vars); |
478 var->bound = TRUE; |
| 433 cxMapPut(ctx->vars, name, var); |
479 } |
| 434 if(cxMapSize(ctx->vars) != oldcount + 1) { |
|
| 435 fprintf(stderr, "UiError: var '%s' already exists\n", name); |
|
| 436 } |
|
| 437 |
|
| 438 // TODO: remove? |
|
| 439 // a widget is already bound to a var with this name |
|
| 440 // copy the binding (like uic_context_set_document) |
|
| 441 /* |
|
| 442 if(b) { |
|
| 443 uic_copy_binding(b, var, TRUE); |
|
| 444 } |
|
| 445 */ |
|
| 446 } |
|
| 447 |
|
| 448 void uic_remove_bound_var(UiContext *ctx, UiVar *var) { |
|
| 449 // TODO |
|
| 450 } |
|
| 451 |
|
| 452 |
480 |
| 453 // public API |
481 // public API |
| 454 |
482 |
| 455 void ui_attach_document(UiContext *ctx, void *document) { |
483 void ui_attach_document(UiContext *ctx, void *document) { |
| 456 uic_context_attach_document(ctx, document); |
484 uic_context_attach_document(ctx, document); |