From: Olaf Wintermann Date: Sun, 6 Apr 2025 12:48:43 +0000 (+0200) Subject: update toolkit X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=a25be3c089570cfcbd41d5b6fe5803a7b0c8b6d0;p=note.git update toolkit --- diff --git a/ui/common/context.c b/ui/common/context.c index 626f149..db9d850 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -58,6 +58,7 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) { memset(ctx, 0, sizeof(UiContext)); ctx->mp = mp; ctx->allocator = mp->allocator; + ctx->destroy_handler = cxArrayListCreate(ctx->allocator, NULL, sizeof(UiDestroyHandler), 16); ctx->obj = toplevel; ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16); @@ -82,6 +83,13 @@ UiContext* uic_root_context(UiContext *ctx) { return ctx->parent ? uic_root_context(ctx->parent) : ctx; } +void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data) { + UiDestroyHandler handler; + handler.destructor = func; + handler.data = data; + cxListAdd(ctx->destroy_handler, &handler); +} + void uic_context_prepare_close(UiContext *ctx) { cxListClear(ctx->groups); cxListClear(ctx->group_widgets); @@ -120,11 +128,12 @@ static void uic_context_unbind_vars(UiContext *ctx) { CxMapIterator mi = cxMapIterator(ctx->vars); cx_foreach(CxMapEntry*, entry, mi) { UiVar *var = entry->value; - if(var->from && var->from_ctx && var->from_ctx != ctx) { + // var->from && var->from_ctx && var->from_ctx != ctx + if(var->from) { uic_save_var2(var); uic_copy_binding(var, var->from, FALSE); - cxMapPut(var->from_ctx->vars_unbound, *entry->key, var->from); - var->from_ctx = ctx; + cxMapPut(var->from->from_ctx->vars_unbound, *entry->key, var->from); + var->from = NULL; } } @@ -209,6 +218,7 @@ UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) { var = ui_malloc(ctx, sizeof(UiVar)); var->type = type; var->value = uic_create_value(ctx, type); + var->original_value = NULL; var->from = NULL; var->from_ctx = ctx; @@ -227,6 +237,7 @@ UiVar* uic_create_value_var(UiContext* ctx, void* value) { var->from = NULL; var->from_ctx = ctx; var->value = value; + var->original_value = NULL; var->type = UI_VAR_SPECIAL; return var; } @@ -286,10 +297,19 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) { } void *fromvalue = from->value; + void *tovalue = to->value; // update var if(copytodoc) { - to->from = from; - to->from_ctx = from->from_ctx; + to->from = from; // from which UiVar are the bindings copied + from->original_value = fromvalue; // save original value otherwise it would be lost + // widgets store a reference to the UiVar with their value + // the UiVar object must be updated to contain the current value object + from->value = tovalue; + } else { + if(to->original_value) { + to->value = to->original_value; + tovalue = to->value; + } } ui_setop_enable(TRUE); @@ -301,7 +321,7 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) { case UI_VAR_SPECIAL: break; case UI_VAR_INTEGER: { UiInteger *f = fromvalue; - UiInteger *t = to->value; + UiInteger *t = tovalue; if(!f->obj) break; uic_int_copy(f, t); t->set(t, t->value); @@ -309,7 +329,7 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) { } case UI_VAR_DOUBLE: { UiDouble *f = fromvalue; - UiDouble *t = to->value; + UiDouble *t = tovalue; if(!f->obj) break; uic_double_copy(f, t); t->set(t, t->value); @@ -317,48 +337,32 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) { } case UI_VAR_STRING: { UiString *f = fromvalue; - UiString *t = to->value; + UiString *t = tovalue; if(!f->obj) break; uic_string_copy(f, t); char *tvalue = t->value.ptr ? t->value.ptr : ""; + char *fvalue = f->value.ptr ? f->value.ptr : ""; t->set(t, tvalue); break; } case UI_VAR_TEXT: { UiText *f = fromvalue; - UiText *t = to->value; + UiText *t = tovalue; if(!f->obj) break; uic_text_copy(f, t); t->restore(t); break; } - case UI_VAR_LIST: { - // TODO: not sure how correct this is - - UiList *f = from->value; - UiList *t = to->value; - if (f->obj) { - t->obj = f->obj; - t->update = f->update; - t->getselection = f->getselection; - t->setselection = f->setselection; - } - - UiVar tmp = *from; - *from = *to; - *to = tmp; - - UiList* t2 = to->value; - if(t->update) { - t->update(t, -1); - } - ui_notify(t2->observers, NULL); // TODO: why not t? - + case UI_VAR_LIST: { + UiList *f = fromvalue; + UiList *t = tovalue; + uic_list_copy(f, t); + ui_list_update(t); break; } case UI_VAR_RANGE: { UiRange *f = fromvalue; - UiRange *t = to->value; + UiRange *t = tovalue; if(!f->obj) break; uic_range_copy(f, t); t->setextent(t, t->extent); @@ -368,7 +372,7 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) { } case UI_VAR_GENERIC: { UiGeneric *f = fromvalue; - UiGeneric *t = to->value; + UiGeneric *t = tovalue; if(!f->obj) break; uic_generic_copy(f, t); t->set(t, t->value, t->type); @@ -473,6 +477,10 @@ void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) { } UIEXPORT void ui_context_destroy(UiContext *ctx) { + CxIterator i = cxListIterator(ctx->destroy_handler); + cx_foreach(UiDestroyHandler *, h, i) { + h->destructor(h->data); + } cxMempoolFree(ctx->mp); } diff --git a/ui/common/context.h b/ui/common/context.h index f07b6da..e0ce3de 100644 --- a/ui/common/context.h +++ b/ui/common/context.h @@ -40,10 +40,11 @@ extern "C" { #endif -typedef struct UiVar UiVar; -typedef struct UiListPtr UiListPtr; -typedef struct UiListVar UiListVar; -typedef struct UiGroupWidget UiGroupWidget; +typedef struct UiVar UiVar; +typedef struct UiListPtr UiListPtr; +typedef struct UiListVar UiListVar; +typedef struct UiGroupWidget UiGroupWidget; +typedef struct UiDestroyHandler UiDestroyHandler; typedef enum UiVarType { UI_VAR_SPECIAL = 0, @@ -61,6 +62,7 @@ struct UiContext { UiObject *obj; CxMempool *mp; const CxAllocator *allocator; + CxList *destroy_handler; void *document; CxList *documents; @@ -93,8 +95,9 @@ struct UiContext { // UiVar replacement, rename it to UiVar when finished struct UiVar { void *value; + void *original_value; UiVarType type; - UiVar *from; + UiVar *from; UiContext *from_ctx; }; @@ -105,11 +108,17 @@ struct UiGroupWidget { int numgroups; }; +struct UiDestroyHandler { + cx_destructor_func destructor; + void *data; +}; + void uic_init_global_context(void); UiContext* uic_context(UiObject *toplevel, CxMempool *mp); UiContext* uic_root_context(UiContext *ctx); +void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data); void uic_context_set_document(UiContext *ctx, void *document); // deprecated void uic_context_detach_document(UiContext *ctx); // deprecated @@ -117,6 +126,8 @@ void uic_context_prepare_close(UiContext *ctx); void uic_context_attach_document(UiContext *ctx, void *document); void uic_context_detach_document2(UiContext *ctx, void *document); +void uic_context_attach_context(UiContext *ctx, UiContext *doc_ctx); +void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx); void uic_context_detach_all(UiContext *ctx); UiVar* uic_get_var(UiContext *ctx, const char *name); diff --git a/ui/common/types.c b/ui/common/types.c index 8bd07a6..a704b85 100644 --- a/ui/common/types.c +++ b/ui/common/types.c @@ -452,6 +452,8 @@ void uic_range_copy(UiRange *from, UiRange *to) { void uic_list_copy(UiList *from, UiList *to) { to->update = from->update; + to->getselection = from->getselection; + to->setselection = from->setselection; to->obj = from->obj; } diff --git a/ui/gtk/container.c b/ui/gtk/container.c index 054a7ce..41c7924 100644 --- a/ui/gtk/container.c +++ b/ui/gtk/container.c @@ -1116,7 +1116,7 @@ static void remove_item(void *data, void *item) { static void update_itemlist(UiList *list, int c) { UiGtkItemListContainer *ct = list->obj; - + CxMap *new_items = cxHashMapCreateSimple(CX_STORE_POINTERS); new_items->collection.advanced_destructor = remove_item; new_items->collection.destructor_data = ct; @@ -1146,7 +1146,7 @@ static void update_itemlist(UiList *list, int c) { // add all items int index = 0; elm = list->first(list); - while(elm) { + while(elm) { CxHashKey key = cx_hash_key(&elm, sizeof(void*)); UiObject *item_obj = cxMapGet(ct->current_items, key); if(item_obj) { @@ -1225,7 +1225,7 @@ UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) { "destroy", G_CALLBACK(destroy_itemlist_container), container); - + return box; } diff --git a/ui/gtk/menu.c b/ui/gtk/menu.c index 085c4db..a54a34b 100644 --- a/ui/gtk/menu.c +++ b/ui/gtk/menu.c @@ -233,6 +233,20 @@ void add_checkitemnv_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject } */ +static void menuitem_list_remove_binding(void *obj) { + UiActiveMenuItemList *ls = obj; + UiList *list = ls->var->value; + CxList *bindings = list->obj; + if(bindings) { + (void)cxListFindRemove(bindings, obj); + if(cxListSize(bindings) == 0) { + cxListFree(bindings); + list->obj = NULL; + list->update = NULL; + } + } +} + void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { UiMenuItemList *il = (UiMenuItemList*)item; const CxAllocator *a = obj->ctx->allocator; @@ -247,21 +261,45 @@ void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObje ls->oldcount = 0; ls->getvalue = il->getvalue; - UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); - ls->list = var->value; + //UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST); + ls->var = var; + if(var) { + UiList *list = var->value; + list->update = ui_menulist_update; + list->getselection = NULL; + list->setselection = NULL; + + // It is possible, that the UiVar is from a global shared context, + // used by multiple windows. To support this usecase, the list->obj + // binding object is a list of all connected UiActiveMenuItemList. + CxList *bindings = list->obj; + if(!bindings) { + bindings = cxLinkedListCreate(var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS); + list->obj = bindings; + } + cxListAdd(bindings, ls); + + // The destruction of the toplevel obj must remove the menulist binding + uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls); + + ui_update_menuitem_list(ls); + } ls->callback = il->callback; ls->userdata = il->userdata; - - UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls); - ls->list->observers = ui_obsvlist_add(ls->list->observers, observer); - uic_list_register_observer_destructor(obj->ctx, ls->list, observer); - - ui_update_menuitem_list(NULL, ls); +} + +void ui_menulist_update(UiList *list, int ignored) { + CxList *bindings = list->obj; + CxIterator i = cxListIterator(bindings); + cx_foreach(UiActiveMenuItemList *, ls, i) { + ui_update_menuitem_list(ls); + } } -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { +void ui_update_menuitem_list(UiActiveMenuItemList *list) { // remove old items if(list->oldcount > 0) { int i = 0; @@ -276,7 +314,9 @@ void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { } } - void* elm = ui_list_first(list->list); + UiList *ls = list->var->value; + + void* elm = ui_list_first(ls); if(elm) { GtkWidget *widget = gtk_separator_menu_item_new(); gtk_menu_shell_insert(list->menu, widget, list->index); @@ -312,7 +352,7 @@ void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { event); } - elm = ui_list_next(list->list); + elm = ui_list_next(ls); i++; } @@ -506,6 +546,20 @@ void ui_gmenu_add_radioitem(GMenu *p, int index, UiMenuItemI *item, UiObject *ob } +static void menuitem_list_remove_binding(void *obj) { + UiActiveGMenuItemList *ls = obj; + UiList *list = ls->var->value; + CxList *bindings = list->obj; + if(bindings) { + (void)cxListFindRemove(bindings, obj); + if(cxListSize(bindings) == 0) { + cxListFree(bindings); + list->obj = NULL; + list->update = NULL; + } + } +} + void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { UiMenuItemList *il = (UiMenuItemList*)item; @@ -521,17 +575,34 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject ls->oldcount = 0; ls->getvalue = il->getvalue; - UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + //UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST); ls->var = var; - UiList *list = var->value; + if(var) { + UiList *list = var->value; + list->update = ui_menulist_update; + list->getselection = NULL; + list->setselection = NULL; + + // It is possible, that the UiVar is from a global shared context, + // used by multiple windows. To support this usecase, the list->obj + // binding object is a list of all connected UiActiveMenuItemList. + CxList *bindings = list->obj; + if(!bindings) { + bindings = cxLinkedListCreate(var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS); + list->obj = bindings; + } + cxListAdd(bindings, ls); + + // The destruction of the toplevel obj must remove the menulist binding + uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls); + + ui_update_gmenu_item_list(ls); + } ls->callback = il->callback; ls->userdata = il->userdata; - UiObserver *observer = ui_observer_new((ui_callback)ui_update_gmenu_item_list, ls); - list->observers = ui_obsvlist_add(list->observers, observer); - uic_list_register_observer_destructor(obj->ctx, list, observer); - GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i")); g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); snprintf(ls->action, 32, "win.%s", item->id); @@ -554,8 +625,6 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject "destroy", G_CALLBACK(ui_destroy_userdata), event); - - ui_update_gmenu_item_list(NULL, ls); } void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) { @@ -588,7 +657,15 @@ void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* par } -void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list) { +void ui_menulist_update(UiList *list, int ignored) { + CxList *bindings = list->obj; + CxIterator i = cxListIterator(bindings); + cx_foreach(UiActiveGMenuItemList *, ls, i) { + ui_update_gmenu_item_list(ls); + } +} + +void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) { // remove old items for(int i=0;ioldcount;i++) { g_menu_remove(list->menu, list->index); diff --git a/ui/gtk/menu.h b/ui/gtk/menu.h index b8bff03..dc6240c 100644 --- a/ui/gtk/menu.h +++ b/ui/gtk/menu.h @@ -55,10 +55,10 @@ struct UiActiveMenuItemList { GtkMenuShell *menu; int index; int oldcount; - UiList *list; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; + UiVar *var; + ui_getvaluefunc getvalue; + ui_callback callback; + void *userdata; }; void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj); @@ -72,7 +72,8 @@ void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject * void add_checkitemnv_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj); void add_menuitem_list_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj); -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list); +void ui_menulist_update(UiList *list, int ignored); +void ui_update_menuitem_list(UiActiveMenuItemList *list); void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event); void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event); int64_t ui_checkitem_get(UiInteger *i); @@ -108,7 +109,8 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event); void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event); -void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list); +void ui_menulist_update(UiList *list, int ignored); +void ui_update_gmenu_item_list(UiActiveGMenuItemList *list); #endif diff --git a/ui/motif/list.c b/ui/motif/list.c index 5da5a0b..f53cbb7 100644 --- a/ui/motif/list.c +++ b/ui/motif/list.c @@ -206,18 +206,19 @@ static void ui_dropdown_selection( UiListView *listview, XmComboBoxCallbackStruct *cb) { - UiListSelection sel = { 0, NULL }; - if(cb->item_position > 0) { - sel.count = 1; - sel.rows = malloc(sizeof(int)); - sel.rows[0] = cb->item_position-1; + int index = cb->item_position; + void *elm = NULL; + if(listview->var) { + UiList *list = listview->var->value; + elm = ui_list_get(list, index); } + UiEvent event; event.obj = listview->obj; event.window = event.obj->window; event.document = event.obj->ctx->document; - event.eventdata = &sel; - event.intval = 0; + event.eventdata = elm; + event.intval = index; if(listview->onactivate) { listview->onactivate(&event, listview->onactivatedata); } diff --git a/ui/motif/menu.c b/ui/motif/menu.c index 15fa182..c75d64a 100644 --- a/ui/motif/menu.c +++ b/ui/motif/menu.c @@ -202,6 +202,20 @@ void add_radioitem_widget(Widget p, int index, UiMenuItemI *item, UiObject *obj) ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, 0); } +static void menuitem_list_remove_binding(void *obj) { + UiActiveMenuItemList *ls = obj; + UiList *list = ls->var->value; + CxList *bindings = list->obj; + if(bindings) { + (void)cxListFindRemove(bindings, obj); + if(cxListSize(bindings) == 0) { + cxListFree(bindings); + list->obj = NULL; + list->update = NULL; + } + } +} + void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { UiMenuItemList *il = (UiMenuItemList*)item; const CxAllocator *a = obj->ctx->allocator; @@ -218,17 +232,40 @@ void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) ls->userdata = il->userdata; ls->addseparator = il->addseparator; - ls->var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); //uic_widget_var(obj->ctx, obj->ctx, NULL, il->varname, UI_VAR_LIST); - UiList *list = ls->var->value; - - UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls); - list->observers = ui_obsvlist_add(list->observers, observer); - uic_list_register_observer_destructor(obj->ctx, list, observer); - - ui_update_menuitem_list(NULL, ls); + //ls->var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + ls->var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST); + if(ls->var) { + UiList *list = ls->var->value; + list->update = ui_menulist_update; + list->getselection = NULL; + list->setselection = NULL; + + // It is possible, that the UiVar is from a global shared context, + // used by multiple windows. To support this usecase, the list->obj + // binding object is a list of all connected UiActiveMenuItemList. + CxList *bindings = list->obj; + if(!bindings) { + bindings = cxLinkedListCreate(ls->var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS); + list->obj = bindings; + } + cxListAdd(bindings, ls); + + // The destruction of the toplevel obj must remove the menulist binding + uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls); + + ui_update_menuitem_list(ls); + } +} + +void ui_menulist_update(UiList *list, int ignored) { + CxList *bindings = list->obj; + CxIterator i = cxListIterator(bindings); + cx_foreach(UiActiveMenuItemList *, ls, i) { + ui_update_menuitem_list(ls); + } } -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { +void ui_update_menuitem_list(UiActiveMenuItemList *list) { XmString s = NULL; Arg args[4]; int n; diff --git a/ui/motif/menu.h b/ui/motif/menu.h index 20f0a98..efa99ce 100644 --- a/ui/motif/menu.h +++ b/ui/motif/menu.h @@ -64,7 +64,8 @@ void add_radioitem_widget(Widget p, int index, UiMenuItemI *item, UiObject *obj) void add_checkitemnv_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj); void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj); -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list); +void ui_menulist_update(UiList *list, int ignored); +void ui_update_menuitem_list(UiActiveMenuItemList *list); #ifdef __cplusplus } diff --git a/ui/motif/text.c b/ui/motif/text.c index 82d75fc..bcb9be4 100644 --- a/ui/motif/text.c +++ b/ui/motif/text.c @@ -68,6 +68,9 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) { value->value.ptr = NULL; } + value->save = ui_textarea_save; + value->restore = ui_textarea_restore; + value->destroy = ui_textarea_text_destroy; value->set = ui_textarea_set; value->get = ui_textarea_get; value->getsubstr = ui_textarea_getsubstr; @@ -79,8 +82,8 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) { value->value.ptr = NULL; value->obj = widget; - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); + if(!value->data2) { + value->data2 = ui_create_undomgr(); } XtAddCallback( @@ -103,6 +106,25 @@ char* ui_textarea_get(UiText *text) { return str; } +void ui_textarea_save(UiText *text) { + (void)ui_textarea_get(text); +} + +void ui_textarea_restore(UiText *text) { + if(text->value.ptr) { + ui_textarea_set(text, text->value.ptr); + } +} + +void ui_textarea_text_destroy(UiText *text) { + if(text->value.free) { + text->value.free(text->value.ptr); + } + if(text->data2) { + ui_destroy_undomgr(text->data2); + } +} + void ui_textarea_set(UiText *text, const char *str) { XmTextSetString(text->obj, (char*)str); if(text->value.ptr) { @@ -201,13 +223,13 @@ void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data) { // TODO: bug, fix return; } - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); + if(!value->data2) { + value->data2 = ui_create_undomgr(); } XmTextVerifyCallbackStruct *txv = (XmTextVerifyCallbackStruct*)data; int type = txv->text->length > 0 ? UI_TEXTBUF_INSERT : UI_TEXTBUF_DELETE; - UiUndoMgr *mgr = value->undomgr; + UiUndoMgr *mgr = value->data2; if(!mgr->event) { return; } @@ -307,7 +329,7 @@ void ui_free_textbuf_op(UiTextBufOp *op) { void ui_text_undo(UiText *value) { - UiUndoMgr *mgr = value->undomgr; + UiUndoMgr *mgr = value->data2; if(mgr->cur) { UiTextBufOp *op = mgr->cur; @@ -328,7 +350,7 @@ void ui_text_undo(UiText *value) { } void ui_text_redo(UiText *value) { - UiUndoMgr *mgr = value->undomgr; + UiUndoMgr *mgr = value->data2; UiTextBufOp *elm = NULL; if(mgr->cur) { @@ -411,7 +433,9 @@ UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) { } char* ui_textfield_get(UiString *str) { - str->value.free(str->value.ptr); + if(str->value.free) { + str->value.free(str->value.ptr); + } char *value = XmTextFieldGetString(str->obj); str->value.ptr = value; str->value.free = (ui_freefunc)XtFree; @@ -420,8 +444,10 @@ char* ui_textfield_get(UiString *str) { void ui_textfield_set(UiString *str, const char *value) { XmTextFieldSetString(str->obj, (void*)value); + if(str->value.free) { + str->value.free(str->value.ptr); + } str->value.ptr = NULL; - str->value.free(str->value.ptr); } diff --git a/ui/motif/text.h b/ui/motif/text.h index d681b30..a7e4f85 100644 --- a/ui/motif/text.h +++ b/ui/motif/text.h @@ -64,6 +64,9 @@ typedef struct UiTextArea { int last_selection_state; } UiTextArea; +void ui_textarea_save(UiText *text); +void ui_textarea_restore(UiText *text); +void ui_textarea_text_destroy(UiText *text); char* ui_textarea_get(UiText *text); void ui_textarea_set(UiText *text, const char *str); char* ui_textarea_getsubstr(UiText *text, int begin, int end); diff --git a/ui/motif/widget.c b/ui/motif/widget.c index 4475e6e..e8b566a 100644 --- a/ui/motif/widget.c +++ b/ui/motif/widget.c @@ -69,3 +69,11 @@ UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) { return widget; } + +void ui_widget_set_size(UIWIDGET w, int width, int height) { + +} + +void ui_widget_redraw(UIWIDGET w) { + +} diff --git a/ui/qt/button.cpp b/ui/qt/button.cpp index 311c611..1ca6f4e 100644 --- a/ui/qt/button.cpp +++ b/ui/qt/button.cpp @@ -163,3 +163,64 @@ void ui_checkbox_set(UiInteger *value, int64_t i) { button->setChecked(true); } } + + +static void radiobutton_event(UiEvent *event, UiEventWrapper *wrapper) { + if(wrapper->var) { + UiInteger *value = wrapper->var->value; + event->eventdata = value; + event->intval = ui_get(value); + } +} + +UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + QString str = QString::fromUtf8(args.label); + QRadioButton *button = new QRadioButton(str); + button->setAutoExclusive(false); + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER); + if(var) { + UiInteger *value = (UiInteger*)var->value; + QButtonGroup *buttonGroup = (QButtonGroup*)value->obj; + if(!buttonGroup) { + buttonGroup = new QButtonGroup(); + value->obj = buttonGroup; + } + int id = buttonGroup->buttons().size()+1; + buttonGroup->addButton(button, id); + if(value->value == id) { + button->setChecked(true); + } + value->get = ui_radiobutton_get; + value->set = ui_radiobutton_set; + } + + UiEventWrapper *event = new UiEventWrapper(obj, args.onchange, args.onchangedata); + event->var = var; + event->customdata1 = button; + event->prepare_event = togglebutton_event; + button->connect(button, SIGNAL(clicked()), event, SLOT(slot())); + button->connect(button, SIGNAL(destroyed()), event, SLOT(destroy())); + + ctn->add(button, false); + + return button; +} + +int64_t ui_radiobutton_get(UiInteger *value) { + QButtonGroup *buttonGroup = (QButtonGroup*)value->obj; + value->value = buttonGroup->checkedId(); + return value->value; +} + +void ui_radiobutton_set(UiInteger *value, int64_t i) { + QButtonGroup *buttonGroup = (QButtonGroup*)value->obj; + QAbstractButton *button = buttonGroup->button(i); + if(button) { + button->setChecked(true); + value->value = i; + } +} diff --git a/ui/qt/toolkit.cpp b/ui/qt/toolkit.cpp index 3db9203..7f915c8 100644 --- a/ui/qt/toolkit.cpp +++ b/ui/qt/toolkit.cpp @@ -161,7 +161,7 @@ UiAction::UiAction(UiObject *obj, QString &label, ui_callback f, void *userdata) } UiAction::~UiAction() { - + // TODO: unbind var } void UiAction::trigger() { diff --git a/ui/qt/widget.cpp b/ui/qt/widget.cpp index 283043b..25fb84b 100644 --- a/ui/qt/widget.cpp +++ b/ui/qt/widget.cpp @@ -53,7 +53,7 @@ UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) { } void ui_widget_set_size(UIWIDGET w, int width, int height) { - w->resize(width >= 0 ? width : w->width(), height >= 0 ? w->height()); + w->resize(width >= 0 ? width : w->width(), height >= 0 ? height : w->height()); } void ui_widget_redraw(UIWIDGET w) {