--- a/ui/motif/menu.c Sun May 23 09:44:43 2021 +0200 +++ b/ui/motif/menu.c Sat Jan 04 16:38:48 2025 +0100 @@ -36,275 +36,89 @@ #include "stock.h" #include "container.h" #include "../common/context.h" +#include "../common/menu.h" +#include "../common/types.h" #include "../ui/window.h" -UcxList *menus; -UcxList *current; - -void ui_menu(char *label) { - // free current menu hierarchy - ucx_list_free(current); - - // create menu - UiMenu *menu = malloc(sizeof(UiMenu)); - menu->item.add_to = (ui_menu_add_f)add_menu_widget; - - menu->label = label; - menu->items = NULL; - menu->parent = NULL; - - current = ucx_list_prepend(NULL, menu); - menus = ucx_list_append(menus, menu); - -} - -void ui_submenu(char *label) { - UiMenu *menu = malloc(sizeof(UiMenu)); - menu->item.add_to = (ui_menu_add_f)add_menu_widget; - - menu->label = label; - menu->items = NULL; - menu->parent = NULL; - - // add submenu to current menu - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, menu); - - // set the submenu to current menu - current = ucx_list_prepend(current, menu); -} - -void ui_submenu_end() { - if(ucx_list_size(current) < 2) { - return; - } - current = ucx_list_remove(current, current); -} - -void ui_menuitem(char *label, ui_callback f, void *userdata) { - ui_menuitem_gr(label, f, userdata, -1); -} - -void ui_menuitem_st(char *stockid, ui_callback f, void *userdata) { - ui_menuitem_stgr(stockid, f, userdata, -1); -} - -void ui_menuitem_gr(char *label, ui_callback f, void *userdata, ...) { - if(!current) { - return; - } - - UiMenuItem *item = malloc(sizeof(UiMenuItem)); - item->item.add_to = (ui_menu_add_f)add_menuitem_widget; - - item->label = label; - item->userdata = userdata; - item->callback = f; - item->groups = NULL; - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group); - } - va_end(ap); - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - -void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) { - if(!current) { - return; - } - - UiStMenuItem *item = malloc(sizeof(UiStMenuItem)); - item->item.add_to = (ui_menu_add_f)add_menuitem_st_widget; - - item->stockid = stockid; - item->userdata = userdata; - item->callback = f; - item->groups = NULL; - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group); - } - va_end(ap); - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - -void ui_menuseparator() { - if(!current) { - return; - } - - UiMenuItemI *item = malloc(sizeof(UiMenuItemI)); - item->add_to = (ui_menu_add_f)add_menuseparator_widget; - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} +#include <cx/linked_list.h> +#include <cx/array_list.h> -void ui_checkitem(char *label, ui_callback f, void *userdata) { - if(!current) { +static ui_menu_add_f createMenuItem[] = { + /* UI_MENU */ add_menu_widget, + /* UI_MENU_ITEM */ add_menuitem_widget, + /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, + /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, + /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_SEPARATOR */ add_menuseparator_widget +}; + +void ui_create_menubar(UiObject *obj, Widget window) { + UiMenu *menus_begin = uic_get_menu_list(); + if(!menus_begin) { return; } - UiCheckItem *item = malloc(sizeof(UiCheckItem)); - item->item.add_to = (ui_menu_add_f)add_checkitem_widget; - item->label = label; - item->callback = f; - item->userdata = userdata; + Widget menubar = XmCreateMenuBar(window, "menubar", NULL, 0); + XtManageChild(menubar); - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - -void ui_checkitem_nv(char *label, char *vname) { - if(!current) { - return; + UiMenu *ls = menus_begin; + while(ls) { + UiMenu *menu = ls; + add_menu_widget(menubar, 0, &menu->item, obj); + ls = (UiMenu*)ls->item.next; } - - UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV)); - item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget; - item->varname = vname; - item->label = label; - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); } -void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) { - if(!current) { - return; - } - - UiMenuItemList *item = malloc(sizeof(UiMenuItemList)); - item->item.add_to = (ui_menu_add_f)add_menuitem_list_widget; - item->callback = f; - item->userdata = userdata; - item->list = items; - - UiMenu *cm = current->data; - cm->items = ucx_list_append(cm->items, item); -} - - -// private menu functions -void ui_create_menubar(UiObject *obj) { - if(!menus) { - return; - } - - Widget menubar = XmCreateMenuBar(obj->widget, "main_list", NULL, 0); - XtManageChild(menubar); - - UcxList *ls = menus; - int menu_index = 0; - while(ls) { - UiMenu *menu = ls->data; - menu_index += menu->item.add_to(menubar, menu_index, &menu->item, obj); - - ls = ls->next; +void ui_add_menu_items(Widget parent, int i, UiMenu *menu, UiObject *obj) { + UiMenuItemI *it = menu->items_begin; + int index = 0; + while(it) { + createMenuItem[it->type](parent, index, it, obj); + it = it->next; + index++; } } -int add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { +void add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { UiMenu *menu = (UiMenu*)item; + Arg args[4]; + int n = 0; - Widget menuItem = XtVaCreateManagedWidget( - menu->label, - xmCascadeButtonWidgetClass, - parent, - NULL); - Widget m = XmVaCreateSimplePulldownMenu(parent, menu->label, i, NULL, NULL); - - UcxList *ls = menu->items; - int menu_index = 0; - while(ls) { - UiMenuItemI *mi = ls->data; - menu_index += mi->add_to(m, menu_index, mi, obj); - ls = ls->next; + XmString s = NULL; + if(menu->label) { + s = XmStringCreateLocalized((char*)menu->label); + XtSetArg(args[n], XmNlabelString, s); n++; } - return 1; -} - -int add_menuitem_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiMenuItem *mi = (UiMenuItem*)item; - - Arg args[1]; - XmString label = XmStringCreateLocalized(mi->label); - XtSetArg(args[0], XmNlabelString, label); - - Widget mitem = XtCreateManagedWidget( - "menubutton", - xmPushButtonWidgetClass, + Widget submenu = XmVaCreateSimplePulldownMenu(parent, "menu_pulldown", i, NULL, NULL); + XtSetArg(args[n], XmNsubMenuId, submenu); n++; + Widget menuItem = XtCreateManagedWidget( + "menuitem", + xmCascadeButtonWidgetClass, parent, args, - 1); - XmStringFree(label); + n); + - if(mi->callback != NULL) { - UiEventData *event = ucx_mempool_malloc( - obj->ctx->mempool, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = mi->userdata; - event->callback = mi->callback; - event->value = 0; - XtAddCallback( - mitem, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); + if(s) { + XmStringFree(s); } - if(mi->groups) { - uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); - } - - return 1; + ui_add_menu_items(submenu, i, menu, obj); } -int add_menuitem_st_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { - UiStMenuItem *mi = (UiStMenuItem*)item; +void add_menuitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuItem *it = (UiMenuItem*)item; - UiStockItem *si = ui_get_stock_item(mi->stockid); - if(!si) { - fprintf(stderr, "UI Error: unknown stock id: %s\n", mi->stockid); - return 0; - } - - int n = 0; + XmString s = NULL; Arg args[4]; - XmString label = XmStringCreateLocalized(si->label); - XmString at = NULL; - - XtSetArg(args[n], XmNlabelString, label); - n++; - if(si->accelerator) { - XtSetArg(args[n], XmNaccelerator, si->accelerator); - n++; - } - if(si->accelerator_label) { - at = XmStringCreateLocalized(si->accelerator_label); - XtSetArg(args[n], XmNacceleratorText, at); - n++; + int n = 0; + if(it->label) { + s = XmStringCreateLocalized((char*)it->label); + XtSetArg(args[n], XmNlabelString, s); n++; } Widget mitem = XtCreateManagedWidget( @@ -313,150 +127,119 @@ parent, args, n); - XmStringFree(label); - if(at) { - XmStringFree(at); + if(s) { + XmStringFree(s); } - if(mi->callback != NULL) { - UiEventData *event = ucx_mempool_malloc( - obj->ctx->mempool, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = mi->userdata; - event->callback = mi->callback; - event->value = 0; + if(it->callback) { + UiEventData *eventdata = malloc(sizeof(UiEventData)); + eventdata->callback = it->callback; + eventdata->userdata = it->userdata; + eventdata->obj = obj; + eventdata->value = 0; XtAddCallback( mitem, XmNactivateCallback, (XtCallbackProc)ui_push_button_callback, - event); + eventdata); + XtAddCallback( + mitem, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); } - if(mi->groups) { - uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); - } - - return 1; + ui_set_widget_groups(obj->ctx, mitem, it->groups); } -int add_menuseparator_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - Widget s = XmCreateSeparatorGadget (parent, "menu_separator", NULL, 0); +void add_menuseparator_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { + Widget s = XmCreateSeparatorGadget (p, "menuseparator", NULL, 0); XtManageChild(s); - return 1; } -int add_checkitem_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiCheckItem *ci = (UiCheckItem*)item; +void add_checkitem_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuCheckItem *it = (UiMenuCheckItem*)item; - Arg args[3]; - XmString label = XmStringCreateLocalized(ci->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNvisibleWhenOff, 1); + Arg args[4]; + int n = 0; + XmString s = NULL; + if(it->label) { + s = XmStringCreateLocalized(it->label); + XtSetArg(args[n], XmNlabelString, s); n++; + } + + //XtSetArg(args[n], XmNvisibleWhenOff, 0); n++; Widget checkbox = XtCreateManagedWidget( "menutogglebutton", xmToggleButtonWidgetClass, - parent, + p, args, - 2); - XmStringFree(label); - - if(ci->callback) { - UiEventData *event = ucx_mempool_malloc( - obj->ctx->mempool, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = ci->userdata; - event->callback = ci->callback; - XtAddCallback( - checkbox, - XmNvalueChangedCallback, - (XtCallbackProc)ui_toggle_button_callback, - event); + n); + if(s) { + XmStringFree(s); } - return 1; + ui_bind_togglebutton(obj, checkbox, it->varname, NULL, it->callback, it->userdata, 0); + + ui_set_widget_groups(obj->ctx, checkbox, it->groups); } -int add_checkitemnv_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiCheckItemNV *ci = (UiCheckItemNV*)item; +void add_radioitem_widget(Widget p, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuRadioItem *it = (UiMenuRadioItem*)item; - Arg args[3]; - XmString label = XmStringCreateLocalized(ci->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNvisibleWhenOff, 1); - Widget checkbox = XtCreateManagedWidget( - "menutogglebutton", - xmToggleButtonWidgetClass, - parent, - args, - 2); - XmStringFree(label); + Arg args[4]; + int n = 0; + XmString s = NULL; + if(it->label) { + s = XmStringCreateLocalized(it->label); + XtSetArg(args[n], XmNlabelString, s); n++; + } + XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY_ROUND); n++; - UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER); - if(var) { - UiInteger *value = var->value; - value->obj = checkbox; - value->get = ui_toggle_button_get; - value->set = ui_toggle_button_set; - value = 0; - } else { - // TODO: error - } + Widget button = XmCreateToggleButton(p, "menuradiobutton", args, n); + XtManageChild(button); - return 1; + ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, 0); } -int add_menuitem_list_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ +void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { UiMenuItemList *il = (UiMenuItemList*)item; - UcxMempool *mp = obj->ctx->mempool; + const CxAllocator *a = obj->ctx->allocator; - UiActiveMenuItemList *ls = ucx_mempool_malloc( - mp, + UiActiveMenuItemList *ls = cxMalloc( + a, sizeof(UiActiveMenuItemList)); - ls->object = obj; - ls->menu = parent; + ls->menu = p; ls->index = i; ls->oldcount = 0; - ls->list = il->list; + ls->getvalue = il->getvalue; ls->callback = il->callback; ls->userdata = il->userdata; + ls->addseparator = il->addseparator; - ls->list->observers = ui_add_observer( - ls->list->observers, - (ui_callback)ui_update_menuitem_list, - ls); + 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); - - return 0; } void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { + XmString s = NULL; Arg args[4]; + int n; - // remove old items + UiList *ls; + if(list->var && list->var->value) { + ls = list->var->value; + } else { + return; + } + if(list->oldcount > 0) { Widget *children; int nc; @@ -474,153 +257,57 @@ } } - char *str = ui_list_first(list->list); - if(str) { - // add separator + void* elm = ui_list_first(ls); + int i = 0; + if(elm && list->addseparator) { XtSetArg(args[0], XmNpositionIndex, list->index); - Widget s = XmCreateSeparatorGadget (list->menu, "menu_separator", args, 1); + Widget s = XmCreateSeparatorGadget(list->menu, "menuseparator", args, 1); XtManageChild(s); + i++; } - int i = 1; - while(str) { - XmString label = XmStringCreateLocalized(str); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNpositionIndex, list->index + i); - + + ui_getvaluefunc getvalue = list->getvalue; + int pos = list->index; + while(elm) { + n = 0; + char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); + if(label) { + s = XmStringCreateLocalized(label); + XtSetArg(args[n], XmNlabelString, s); n++; + } + XtSetArg(args[n], XmNpositionIndex, pos+i); n++; + Widget mitem = XtCreateManagedWidget( "menubutton", xmPushButtonWidgetClass, list->menu, args, - 2); - XmStringFree(label); - + n); + if(s) { + XmStringFree(s); + } + if(list->callback) { - // TODO: use mempool - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = list->object; - event->userdata = list->userdata; - event->callback = list->callback; - event->value = i - 1; - + UiEventData *eventdata = malloc(sizeof(UiEventData)); + eventdata->callback = list->callback; + eventdata->userdata = list->userdata; + eventdata->obj = list->object; + eventdata->value = 0; XtAddCallback( - mitem, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); + mitem, + XmNactivateCallback, + (XtCallbackProc)ui_push_button_callback, + eventdata); + XtAddCallback( + mitem, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); } - str = ui_list_next(list->list); + elm = ui_list_next(ls); i++; } list->oldcount = i; } - -void ui_menu_event_wrapper(Widget widget, XtPointer udata, XtPointer cdata) { - UiEventData *event = udata; - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.intval = 0; - event->callback(&e, event->userdata); -} - - -/* - * widget menu functions - */ - -static void ui_popup_handler(Widget widget, XtPointer data, XEvent *event, Boolean *c) { - Widget menu = data; - XmMenuPosition(menu, (XButtonPressedEvent *)event); - XtManageChild(menu); - - *c = FALSE; -} - -UIMENU ui_contextmenu(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - if(ct->current) { - return ui_contextmenu_w(obj, ct->current); - } else { - return NULL; // TODO: warn - } -} - -UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { - UiContainer *ct = uic_get_current_container(obj); - - Widget menu = XmCreatePopupMenu(widget, "popup_menu", NULL, 0); - ct->menu = menu; - - XtAddEventHandler(widget, ButtonPressMask, FALSE, ui_popup_handler, menu); - - return menu; -} - -void ui_contextmenu_popup(UIMENU menu) { - -} - -void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) { - ui_widget_menuitem_gr(obj, label, f, userdata, -1); -} - -void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; - } - - // add groups - UcxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - ucx_list_append(groups, (void*)(intptr_t)group); - } - va_end(ap); - - // create menuitem - Arg args[4]; - XmString labelstr = XmStringCreateLocalized(label); - XtSetArg(args[0], XmNlabelString, labelstr); - - Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); - XtManageChild(item); - XmStringFree(labelstr); -} - -void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { - ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); -} - -void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; - } - - // add groups - UcxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - ucx_list_append(groups, (void*)(intptr_t)group); - } - va_end(ap); - - // create menuitem - UiStockItem *stockItem = ui_get_stock_item(stockid); - Arg args[4]; - XmString labelstr = XmStringCreateLocalized(stockItem->label); - XtSetArg(args[0], XmNlabelString, labelstr); - - Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); - XtManageChild(item); - XmStringFree(labelstr); -}