diff -r c563220d9aea -r 5d4419042d9b ui/common/types.c --- a/ui/common/types.c Sun Dec 07 12:24:12 2025 +0100 +++ b/ui/common/types.c Sun Dec 07 14:39:03 2025 +0100 @@ -252,6 +252,15 @@ #define UI_MODEL_DEFAULT_ALLOC_SIZE 16 + +static void model_notify_observer(UiModel *model, int insert, int delete) { + UiModelChangeObserver *obs = model->observer; + while(obs) { + obs->update(model, obs->userdata, insert, delete); + obs = obs->next; + } +} + UiModel* ui_model_new(UiContext *ctx) { UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel)); info->ctx = ctx; @@ -262,16 +271,21 @@ return info; } -void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width) { +void ui_model_add_column(UiModel *model, UiModelType type, const char *title, int width) { + UiContext *ctx = model->ctx; if(model->columns >= model->alloc) { model->alloc += UI_MODEL_DEFAULT_ALLOC_SIZE; model->types = ui_realloc(ctx, model->types, model->alloc * sizeof(UiModelType)); model->titles = ui_realloc(ctx, model->titles, model->alloc * sizeof(char*)); model->columnsize = ui_realloc(ctx, model->columnsize, model->alloc * sizeof(int)); } - model->types[model->columns] = type; - model->titles[model->columns] = ui_strdup(ctx, title); - model->columnsize[model->columns] = width; + int index = model->columns; + model->types[index] = type; + model->titles[index] = ui_strdup(ctx, title); + model->columnsize[index] = width; + + model_notify_observer(model, index, -1); + model->columns++; } @@ -299,18 +313,63 @@ model->ref++; } -void ui_model_unref(UiModel *model) { +void ui_model_unref(UiModel *model) { if(--model->ref == 0) { ui_model_free(model); } } +void ui_model_add_observer(UiModel *model, ui_model_update_func update, void *data) { + UiModelChangeObserver *observer = ui_malloc(model->ctx, sizeof(UiModelChangeObserver)); + observer->update = update; + observer->userdata = data; + observer->next = NULL; + + if(model->observer) { + UiModelChangeObserver *last = model->observer; + while(last->next) { + last = last->next; + } + last->next = observer; + } else { + model->observer = observer; + } +} + +void ui_model_remove_observer(UiModel *model, void *data) { + if(model->observer) { + UiModelChangeObserver *obs = model->observer; + UiModelChangeObserver *prev = NULL; + while(obs) { + if(obs->userdata == data) { + // remove + if(prev) { + prev->next = obs->next; + } else { + model->observer = obs->next; + } + // free + ui_free(model->ctx, obs); + break; + } + prev = obs; + obs = obs->next; + } + } +} + void ui_model_free(UiModel *mi) { UiContext *ctx = mi->ctx; const CxAllocator* a = ctx->allocator; for(int i=0;icolumns;i++) { ui_free(ctx, mi->titles[i]); } + UiModelChangeObserver *obs = mi->observer; + while(obs) { + UiModelChangeObserver *n = obs->next; + cxFree(a, obs); + obs = n; + } cxFree(a, mi->types); cxFree(a, mi->titles); cxFree(a, mi->columnsize);