| 31 #include <string.h> |
31 #include <string.h> |
| 32 #include <stdarg.h> |
32 #include <stdarg.h> |
| 33 |
33 |
| 34 #include <cx/list.h> |
34 #include <cx/list.h> |
| 35 #include <cx/array_list.h> |
35 #include <cx/array_list.h> |
| 36 #include "../ui/tree.h" |
36 #include "../ui/list.h" |
| 37 #include "types.h" |
37 #include "types.h" |
| 38 #include "context.h" |
38 #include "context.h" |
| 39 #include "../ui/image.h" |
39 #include "../ui/image.h" |
| 40 |
40 |
| 41 static ui_list_init_func default_list_init; |
41 static ui_list_init_func default_list_init; |
| 42 static void *default_list_init_userdata; |
42 static void *default_list_init_userdata; |
| |
43 static ui_list_destroy_func default_list_destroy; |
| |
44 static void *default_list_destroy_userdata; |
| 43 |
45 |
| 44 UiObserver* ui_observer_new(ui_callback f, void *data) { |
46 UiObserver* ui_observer_new(ui_callback f, void *data) { |
| 45 UiObserver *observer = malloc(sizeof(UiObserver)); |
47 UiObserver *observer = malloc(sizeof(UiObserver)); |
| 46 observer->callback = f; |
48 observer->callback = f; |
| 47 observer->data = data; |
49 observer->data = data; |
| 103 list->next = ui_list_next; |
105 list->next = ui_list_next; |
| 104 list->get = ui_list_get; |
106 list->get = ui_list_get; |
| 105 list->count = ui_list_count; |
107 list->count = ui_list_count; |
| 106 } |
108 } |
| 107 |
109 |
| |
110 void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused) { |
| |
111 cxListFree(list->data); |
| |
112 ui_free(ctx, list); |
| |
113 } |
| |
114 |
| 108 UiList* ui_list_new(UiContext *ctx, const char *name) { |
115 UiList* ui_list_new(UiContext *ctx, const char *name) { |
| 109 return ui_list_new2(ctx, name, default_list_init ? default_list_init : uic_ucx_list_init, default_list_init_userdata); |
116 return ui_list_new2(ctx, name, default_list_init ? default_list_init : uic_ucx_list_init, default_list_init_userdata); |
| 110 } |
117 } |
| 111 |
118 |
| 112 UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listinit, void *userdata) { |
119 UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listinit, void *userdata) { |
| 238 return info; |
250 return info; |
| 239 } |
251 } |
| 240 |
252 |
| 241 #define UI_MODEL_DEFAULT_ALLOC_SIZE 16 |
253 #define UI_MODEL_DEFAULT_ALLOC_SIZE 16 |
| 242 |
254 |
| |
255 |
| |
256 static void model_notify_observer(UiModel *model, int insert, int delete) { |
| |
257 UiModelChangeObserver *obs = model->observer; |
| |
258 while(obs) { |
| |
259 obs->update(model, obs->userdata, insert, delete); |
| |
260 obs = obs->next; |
| |
261 } |
| |
262 } |
| |
263 |
| 243 UiModel* ui_model_new(UiContext *ctx) { |
264 UiModel* ui_model_new(UiContext *ctx) { |
| 244 UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel)); |
265 UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel)); |
| |
266 info->ctx = ctx; |
| 245 info->alloc = UI_MODEL_DEFAULT_ALLOC_SIZE; |
267 info->alloc = UI_MODEL_DEFAULT_ALLOC_SIZE; |
| 246 info->types = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(UiModelType)); |
268 info->types = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(UiModelType)); |
| 247 info->titles = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(char*)); |
269 info->titles = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(char*)); |
| 248 info->columnsize = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(int)); |
270 info->columnsize = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(int)); |
| 249 return info; |
271 return info; |
| 250 } |
272 } |
| 251 |
273 |
| 252 void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width) { |
274 void ui_model_add_column(UiModel *model, UiModelType type, const char *title, int width) { |
| |
275 UiContext *ctx = model->ctx; |
| 253 if(model->columns >= model->alloc) { |
276 if(model->columns >= model->alloc) { |
| 254 model->alloc += UI_MODEL_DEFAULT_ALLOC_SIZE; |
277 model->alloc += UI_MODEL_DEFAULT_ALLOC_SIZE; |
| 255 model->types = ui_realloc(ctx, model->types, model->alloc * sizeof(UiModelType)); |
278 model->types = ui_realloc(ctx, model->types, model->alloc * sizeof(UiModelType)); |
| 256 model->titles = ui_realloc(ctx, model->titles, model->alloc * sizeof(char*)); |
279 model->titles = ui_realloc(ctx, model->titles, model->alloc * sizeof(char*)); |
| 257 model->columnsize = ui_realloc(ctx, model->columnsize, model->alloc * sizeof(int)); |
280 model->columnsize = ui_realloc(ctx, model->columnsize, model->alloc * sizeof(int)); |
| 258 } |
281 } |
| 259 model->types[model->columns] = type; |
282 int index = model->columns; |
| 260 model->titles[model->columns] = ui_strdup(ctx, title); |
283 model->types[index] = type; |
| 261 model->columnsize[model->columns] = width; |
284 model->titles[index] = ui_strdup(ctx, title); |
| |
285 model->columnsize[index] = width; |
| |
286 |
| |
287 model_notify_observer(model, index, -1); |
| |
288 |
| 262 model->columns++; |
289 model->columns++; |
| 263 } |
290 } |
| 264 |
291 |
| 265 UiModel* ui_model_copy(UiContext *ctx, UiModel* model) { |
292 UiModel* ui_model_copy(UiContext *ctx, UiModel* model) { |
| 266 const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator; |
293 const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator; |
| 267 |
294 |
| 268 UiModel* newmodel = cxMalloc(a, sizeof(UiModel)); |
295 UiModel* newmodel = cxMalloc(a, sizeof(UiModel)); |
| |
296 newmodel->ctx = ctx; |
| 269 *newmodel = *model; |
297 *newmodel = *model; |
| 270 |
298 |
| 271 newmodel->types = cxCalloc(a, model->columns, sizeof(UiModelType)); |
299 newmodel->types = cxCalloc(a, model->columns, sizeof(UiModelType)); |
| 272 memcpy(newmodel->types, model->types, model->columns); |
300 memcpy(newmodel->types, model->types, model->columns); |
| 273 |
301 |
| 279 memcpy(newmodel->columnsize, model->columnsize, model->columns*sizeof(int)); |
307 memcpy(newmodel->columnsize, model->columnsize, model->columns*sizeof(int)); |
| 280 |
308 |
| 281 return newmodel; |
309 return newmodel; |
| 282 } |
310 } |
| 283 |
311 |
| 284 void ui_model_free(UiContext *ctx, UiModel *mi) { |
312 void ui_model_ref(UiModel *model) { |
| 285 const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator; |
313 model->ref++; |
| |
314 } |
| |
315 |
| |
316 void ui_model_unref(UiModel *model) { |
| |
317 if(--model->ref == 0) { |
| |
318 ui_model_free(model); |
| |
319 } |
| |
320 } |
| |
321 |
| |
322 void ui_model_add_observer(UiModel *model, ui_model_update_func update, void *data) { |
| |
323 UiModelChangeObserver *observer = ui_malloc(model->ctx, sizeof(UiModelChangeObserver)); |
| |
324 observer->update = update; |
| |
325 observer->userdata = data; |
| |
326 observer->next = NULL; |
| |
327 |
| |
328 if(model->observer) { |
| |
329 UiModelChangeObserver *last = model->observer; |
| |
330 while(last->next) { |
| |
331 last = last->next; |
| |
332 } |
| |
333 last->next = observer; |
| |
334 } else { |
| |
335 model->observer = observer; |
| |
336 } |
| |
337 } |
| |
338 |
| |
339 void ui_model_remove_observer(UiModel *model, void *data) { |
| |
340 if(model->observer) { |
| |
341 UiModelChangeObserver *obs = model->observer; |
| |
342 UiModelChangeObserver *prev = NULL; |
| |
343 while(obs) { |
| |
344 if(obs->userdata == data) { |
| |
345 // remove |
| |
346 if(prev) { |
| |
347 prev->next = obs->next; |
| |
348 } else { |
| |
349 model->observer = obs->next; |
| |
350 } |
| |
351 // free |
| |
352 ui_free(model->ctx, obs); |
| |
353 break; |
| |
354 } |
| |
355 prev = obs; |
| |
356 obs = obs->next; |
| |
357 } |
| |
358 } |
| |
359 } |
| |
360 |
| |
361 void ui_model_free(UiModel *mi) { |
| |
362 UiContext *ctx = mi->ctx; |
| |
363 const CxAllocator* a = ctx->allocator; |
| 286 for(int i=0;i<mi->columns;i++) { |
364 for(int i=0;i<mi->columns;i++) { |
| 287 ui_free(ctx, mi->titles[i]); |
365 ui_free(ctx, mi->titles[i]); |
| |
366 } |
| |
367 UiModelChangeObserver *obs = mi->observer; |
| |
368 while(obs) { |
| |
369 UiModelChangeObserver *n = obs->next; |
| |
370 cxFree(a, obs); |
| |
371 obs = n; |
| 288 } |
372 } |
| 289 cxFree(a, mi->types); |
373 cxFree(a, mi->types); |
| 290 cxFree(a, mi->titles); |
374 cxFree(a, mi->titles); |
| 291 cxFree(a, mi->columnsize); |
375 cxFree(a, mi->columnsize); |
| 292 cxFree(a, mi); |
376 cxFree(a, mi); |
| 785 destr->observer = observer; |
867 destr->observer = observer; |
| 786 cxMempoolSetDestructor(destr, (cx_destructor_func)observer_destructor); |
868 cxMempoolSetDestructor(destr, (cx_destructor_func)observer_destructor); |
| 787 } |
869 } |
| 788 |
870 |
| 789 static int ui_set_op = 0; |
871 static int ui_set_op = 0; |
| |
872 static int ui_onchange_events_enabled = TRUE; |
| 790 |
873 |
| 791 void ui_setop_enable(int set) { |
874 void ui_setop_enable(int set) { |
| 792 ui_set_op = set; |
875 ui_set_op = set; |
| 793 } |
876 } |
| 794 |
877 |
| 795 int ui_get_setop(void) { |
878 int ui_get_setop(void) { |
| 796 return ui_set_op; |
879 return ui_set_op; |
| |
880 } |
| |
881 |
| |
882 void ui_onchange_events_enable(UiBool enable) { |
| |
883 ui_onchange_events_enabled = enable; |
| |
884 } |
| |
885 |
| |
886 UiBool ui_onchange_events_is_enabled(void) { |
| |
887 return ui_onchange_events_enabled; |
| 797 } |
888 } |
| 798 |
889 |
| 799 /* ---------------- List initializers and wrapper functions ---------------- */ |
890 /* ---------------- List initializers and wrapper functions ---------------- */ |
| 800 |
891 |
| 801 void ui_global_list_initializer(ui_list_init_func func, void *userdata) { |
892 void ui_global_list_initializer(ui_list_init_func func, void *userdata) { |
| 802 default_list_init = func; |
893 default_list_init = func; |
| 803 default_list_init_userdata = userdata; |
894 default_list_init_userdata = userdata; |
| 804 } |
895 } |
| 805 |
896 |
| |
897 void ui_global_list_destructor(ui_list_destroy_func func, void *userdata) { |
| |
898 default_list_destroy = func; |
| |
899 default_list_destroy_userdata = userdata; |
| |
900 } |
| |
901 |
| 806 void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) { |
902 void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) { |
| 807 list->first = first; |
903 list->first = first; |
| 808 } |
904 } |
| 809 |
905 |
| 810 void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list)) { |
906 void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list)) { |