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