#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <cx/list.h>
#include <cx/array_list.h>
#include "../ui/tree.h"
#include "types.h"
#include "context.h"
UiObserver* ui_observer_new(ui_callback f,
void *data) {
UiObserver *observer = malloc(
sizeof(UiObserver));
observer->callback = f;
observer->data = data;
observer->next =
NULL;
return observer;
}
UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer) {
if(!list) {
return observer;
}
else {
UiObserver *l = list;
while(l->next) {
l = l->next;
}
l->next = observer;
return list;
}
}
UiObserver* ui_add_observer(UiObserver *list, ui_callback f,
void *data) {
UiObserver *observer = ui_observer_new(f, data);
return ui_obsvlist_add(list, observer);
}
void ui_notify(UiObserver *observer,
void *data) {
ui_notify_except(observer,
NULL, data);
}
void ui_notify_except(UiObserver *observer, UiObserver *exc,
void *data) {
UiEvent evt;
evt.obj =
NULL;
evt.window =
NULL;
evt.document =
NULL;
evt.eventdata = data;
evt.intval =
0;
while(observer) {
if(observer != exc) {
observer->callback(&evt, observer->data);
}
observer = observer->next;
}
}
void ui_notify_evt(UiObserver *observer, UiEvent *event) {
while(observer) {
observer->callback(event, observer->data);
observer = observer->next;
}
}
UiList* ui_list_new(UiContext *ctx,
char *name) {
UiList *list = malloc(
sizeof(UiList));
list->first = ui_list_first;
list->next = ui_list_next;
list->get = ui_list_get;
list->count = ui_list_count;
list->observers =
NULL;
list->data = cxArrayListCreate(cxDefaultAllocator,
NULL,
CX_STORE_POINTERS,
32);
list->iter =
NULL;
list->update =
NULL;
list->getselection =
NULL;
list->obj =
NULL;
if(name) {
uic_reg_var(ctx, name,
UI_VAR_LIST, list);
}
return list;
}
void ui_list_free(UiList *list) {
cxListDestroy(list->data);
free(list);
}
void* ui_list_first(UiList *list) {
list->iter = (
void*)(
intptr_t)
0;
return cxListAt(list->data,
0);
}
void* ui_list_next(UiList *list) {
intptr_t iter = (
intptr_t)list->iter;
iter++;
void *elm = cxListAt(list->data, iter);
if(elm) {
list->iter = (
void*)iter;
}
return elm;
}
void* ui_list_get(UiList *list,
int i) {
return cxListAt(list->data, i);
}
int ui_list_count(UiList *list) {
return cxListSize(list->data);
}
void ui_list_append(UiList *list,
void *data) {
cxListAdd(list->data, data);
}
void ui_list_prepend(UiList *list,
void *data) {
cxListInsert(list->data,
0, data);
}
void ui_list_remove(UiList *list,
int i) {
cxListRemove(list->data, i);
}
void ui_list_clear(UiList *list) {
cxListClear(list->data);
}
UIEXPORT void ui_list_update(UiList *list) {
if(list->update) {
list->update(list,
0);
}
}
void ui_list_addobsv(UiList *list, ui_callback f,
void *data) {
list->observers = ui_add_observer(list->observers, f, data);
}
void ui_list_notify(UiList *list) {
ui_notify(list->observers, list);
}
typedef struct {
int type;
char *name;
} UiColumn;
UiModel* ui_model(UiContext *ctx, ...) {
UiModel *info = ui_calloc(ctx,
1,
sizeof(UiModel));
va_list ap;
va_start(ap, ctx);
CxList *cols = cxArrayListCreate(cxDefaultAllocator,
NULL,
sizeof(UiColumn),
32);
int type;
while((type = va_arg(ap,
int)) != -
1) {
char *name = va_arg(ap,
char*);
UiColumn column;
column.type = type;
column.name = name;
cxListAdd(cols, &column);
}
va_end(ap);
size_t len = cxListSize(cols);
info->columns = len;
info->types = ui_calloc(ctx, len,
sizeof(UiModelType));
info->titles = ui_calloc(ctx, len,
sizeof(
char*));
info->columnsize = ui_calloc(ctx, len,
sizeof(
int));
int i =
0;
CxIterator iter = cxListIterator(cols);
cx_foreach(UiColumn*, c, iter) {
info->types[i] = c->type;
info->titles[i] = c->name;
i++;
}
cxListDestroy(cols);
return info;
}
UiModel* ui_model_copy(UiContext *ctx, UiModel* model) {
const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
UiModel* newmodel = cxMalloc(a,
sizeof(UiModel));
*newmodel = *model;
newmodel->types = cxCalloc(a, model->columns,
sizeof(UiModelType));
memcpy(newmodel->types, model->types, model->columns);
newmodel->titles = cxCalloc(a, model->columns,
sizeof(
char*));
for (
int i =
0; i < model->columns; i++) {
newmodel->titles[i] = model->titles[i] ? cx_strdup_a(a, cx_str(model->titles[i])).ptr :
NULL;
}
return newmodel;
}
void ui_model_free(UiContext *ctx, UiModel *mi) {
const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
cxFree(a, mi->types);
cxFree(a, mi->titles);
cxFree(a, mi);
}
UiInteger* ui_int_new(UiContext *ctx,
char *name) {
UiInteger *i = ui_malloc(ctx,
sizeof(UiInteger));
memset(i,
0,
sizeof(UiInteger));
if(name) {
uic_reg_var(ctx, name,
UI_VAR_INTEGER, i);
}
return i;
}
UiDouble* ui_double_new(UiContext *ctx,
char *name) {
UiDouble *d = ui_malloc(ctx,
sizeof(UiDouble));
memset(d,
0,
sizeof(UiDouble));
if(name) {
uic_reg_var(ctx, name,
UI_VAR_DOUBLE, d);
}
return d;
}
UiString* ui_string_new(UiContext *ctx,
char *name) {
UiString *s = ui_malloc(ctx,
sizeof(UiString));
memset(s,
0,
sizeof(UiString));
if(name) {
uic_reg_var(ctx, name,
UI_VAR_STRING, s);
}
return s;
}
UiText* ui_text_new(UiContext *ctx,
char *name) {
UiText *t = ui_malloc(ctx,
sizeof(UiText));
memset(t,
0,
sizeof(UiText));
if(name) {
uic_reg_var(ctx, name,
UI_VAR_TEXT, t);
}
return t;
}
UiRange* ui_range_new(UiContext *ctx,
char *name) {
UiRange *r = ui_malloc(ctx,
sizeof(UiRange));
memset(r,
0,
sizeof(UiRange));
if(name) {
uic_reg_var(ctx, name,
UI_VAR_RANGE, r);
}
return r;
}
UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx,
char *name) {
UiGeneric *g = ui_malloc(ctx,
sizeof(UiGeneric));
memset(g,
0,
sizeof(UiGeneric));
if(name) {
uic_reg_var(ctx, name,
UI_VAR_GENERIC, g);
}
return g;
}
void ui_int_set(UiInteger* i,
int64_t value) {
if (i && i->set) {
i->set(i, value);
}
}
int64_t ui_int_get(UiInteger* i) {
if (i) {
return i->get ? i->get(i) : i->value;
}
else {
return 0;
}
}
void ui_double_set(UiDouble* d,
double value) {
if (d && d->set) {
d->set(d, value);
}
}
double ui_double_get(UiDouble* d) {
if (d) {
return d->get ? d->get(d) : d->value;
}
else {
return 0;
}
}
void ui_string_set(UiString* s,
const char* value) {
if (s && s->set) {
s->set(s, value);
}
}
char* ui_string_get(UiString* s) {
if (s) {
return s->get ? s->get(s) : s->value.ptr;
}
else {
return 0;
}
}
void ui_text_set(UiText* s,
const char* value) {
if (s && s->set) {
s->set(s, value);
}
}
char* ui_text_get(UiText* s) {
if (s) {
return s->get ? s->get(s) : s->value.ptr;
}
else {
return 0;
}
}
void uic_int_copy(UiInteger *from, UiInteger *to) {
to->get = from->get;
to->set = from->set;
to->obj = from->obj;
}
void uic_double_copy(UiDouble *from, UiDouble *to) {
to->get = from->get;
to->set = from->set;
to->obj = from->obj;
}
void uic_string_copy(UiString *from, UiString *to) {
to->get = from->get;
to->set = from->set;
to->obj = from->obj;
}
void uic_text_copy(UiText *from, UiText *to) {
to->get = from->get;
to->set = from->set;
to->getsubstr = from->getsubstr;
to->insert = from->insert;
to->setposition = from->setposition;
to->position = from->position;
to->selection = from->selection;
to->length = from->length;
to->remove = from->remove;
to->obj = from->obj;
}
void uic_range_copy(UiRange *from, UiRange *to) {
to->get = from->get;
to->set = from->set;
to->setrange = from->setrange;
to->setextent = from->setextent;
to->obj = from->obj;
}
void uic_list_copy(UiList *from, UiList *to) {
to->update = from->update;
to->obj = from->obj;
}
void uic_generic_copy(UiGeneric *from, UiGeneric *to) {
to->get = from->get;
to->get_type = from->get_type;
to->set = from->set;
to->obj = from->obj;
}
void uic_int_save(UiInteger *i) {
if(!i->obj)
return;
i->value = i->get(i);
}
void uic_double_save(UiDouble *d) {
if(!d->obj)
return;
d->value = d->get(d);
}
void uic_string_save(UiString *s) {
if(!s->obj)
return;
s->get(s);
}
void uic_text_save(UiText *t) {
if(!t->obj)
return;
t->get(t);
t->position(t);
}
void uic_range_save(UiRange *r) {
if(!r->obj)
return;
r->get(r);
}
void uic_generic_save(UiGeneric *g) {
if(!g->obj)
return;
g->get(g);
}
void uic_int_unbind(UiInteger *i) {
i->get =
NULL;
i->set =
NULL;
i->obj =
NULL;
}
void uic_double_unbind(UiDouble *d) {
d->get =
NULL;
d->set =
NULL;
d->obj =
NULL;
}
void uic_string_unbind(UiString *s) {
s->get =
NULL;
s->set =
NULL;
s->obj =
NULL;
}
void uic_text_unbind(UiText *t) {
t->set =
NULL;
t->get =
NULL;
t->getsubstr =
NULL;
t->insert =
NULL;
t->setposition =
NULL;
t->position =
NULL;
t->selection =
NULL;
t->length =
NULL;
t->remove =
NULL;
t->obj =
NULL;
t->undomgr =
NULL;
}
void uic_range_unbind(UiRange *r) {
r->get =
NULL;
r->set =
NULL;
r->setextent =
NULL;
r->setrange =
NULL;
r->obj =
NULL;
}
void uic_list_unbind(UiList *l) {
l->update =
NULL;
l->obj =
NULL;
}
void uic_generic_unbind(UiGeneric *g) {
g->get =
NULL;
g->get_type =
NULL;
g->set =
NULL;
g->obj =
NULL;
}
UIEXPORT UiListSelection ui_list_getselection(UiList *list) {
if (list->getselection) {
return list->getselection(list);
}
return (UiListSelection){
0,
NULL };
}
UIEXPORT void ui_list_setselection(UiList *list,
int index) {
if (list->setselection && index >=
0) {
UiListSelection sel;
sel.count =
1;
sel.rows = &index;
list->setselection(list, sel);
}
}
UIEXPORT void ui_listselection_free(UiListSelection selection) {
if (selection.rows) {
free(selection.rows);
}
}
UIEXPORT UiStr ui_str(
char *cstr) {
return (UiStr) { cstr,
NULL };
}
UIEXPORT UiStr ui_str_free(
char *str,
void (*freefunc)(
void *v)) {
return (UiStr) { str, freefunc };
}
UIEXPORT UiFileList ui_filelist_copy(UiFileList list) {
char **newlist = calloc(
sizeof(
char*), list.nfiles);
for (
int i =
0; i < list.nfiles; i++) {
newlist[i] = strdup(list.files[i]);
}
return (UiFileList) { newlist, list.nfiles };
}
UIEXPORT void ui_filelist_free(UiFileList list) {
for (
int i =
0; i < list.nfiles; i++) {
free(list.files[i]);
}
free(list.files);
}
typedef struct UiObserverDestructor {
UiList *list;
UiObserver *observer;
} UiObserverDestructor;
static void observer_destructor(UiObserverDestructor *destr) {
UiObserver *remove_obs = destr->observer;
UiObserver *obs = destr->list->observers;
UiObserver *prev =
NULL;
while(obs) {
if(obs == remove_obs) {
if(prev) {
prev->next = obs->next;
}
else {
destr->list->observers = obs->next;
}
break;
}
prev = obs;
obs = obs->next;
}
free(remove_obs);
}
void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObserver *observer) {
CxMempool *mp = ctx->mp;
UiObserverDestructor *destr = cxMalloc(mp->allocator,
sizeof(UiObserverDestructor));
destr->list = list;
destr->observer = observer;
cxMempoolSetDestructor(destr, (cx_destructor_func)observer_destructor);
}