--- a/ui/motif/menu.c Thu Dec 12 20:01:43 2024 +0100 +++ b/ui/motif/menu.c Mon Jan 06 22:22:55 2025 +0100 @@ -36,8 +36,278 @@ #include "stock.h" #include "container.h" #include "../common/context.h" +#include "../common/menu.h" +#include "../common/types.h" #include "../ui/window.h" #include <cx/linked_list.h> #include <cx/array_list.h> + +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; + } + + Widget menubar = XmCreateMenuBar(window, "menubar", NULL, 0); + XtManageChild(menubar); + + UiMenu *ls = menus_begin; + while(ls) { + UiMenu *menu = ls; + add_menu_widget(menubar, 0, &menu->item, obj); + ls = (UiMenu*)ls->item.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++; + } +} + +void add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenu *menu = (UiMenu*)item; + Arg args[4]; + int n = 0; + + XmString s = NULL; + if(menu->label) { + s = XmStringCreateLocalized((char*)menu->label); + XtSetArg(args[n], XmNlabelString, s); n++; + } + + Widget submenu = XmVaCreateSimplePulldownMenu(parent, "menu_pulldown", i, NULL, NULL); + XtSetArg(args[n], XmNsubMenuId, submenu); n++; + Widget menuItem = XtCreateManagedWidget( + "menuitem", + xmCascadeButtonWidgetClass, + parent, + args, + n); + + + if(s) { + XmStringFree(s); + } + + ui_add_menu_items(submenu, i, menu, obj); +} + +void add_menuitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuItem *it = (UiMenuItem*)item; + + XmString s = NULL; + Arg args[4]; + int n = 0; + if(it->label) { + s = XmStringCreateLocalized((char*)it->label); + XtSetArg(args[n], XmNlabelString, s); n++; + } + + Widget mitem = XtCreateManagedWidget( + "menubutton", + xmPushButtonWidgetClass, + parent, + args, + n); + if(s) { + XmStringFree(s); + } + + 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, + eventdata); + XtAddCallback( + mitem, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); + } + + ui_set_widget_groups(obj->ctx, mitem, it->groups); +} + +void add_menuseparator_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { + Widget s = XmCreateSeparatorGadget (p, "menuseparator", NULL, 0); + XtManageChild(s); +} + +void add_checkitem_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuCheckItem *it = (UiMenuCheckItem*)item; + + 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, + p, + args, + n); + if(s) { + XmStringFree(s); + } + + ui_bind_togglebutton(obj, checkbox, it->varname, NULL, it->callback, it->userdata, 0); + + ui_set_widget_groups(obj->ctx, checkbox, it->groups); +} + +void add_radioitem_widget(Widget p, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuRadioItem *it = (UiMenuRadioItem*)item; + + 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++; + + Widget button = XmCreateToggleButton(p, "menuradiobutton", args, n); + XtManageChild(button); + + ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, 0); +} + +void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuItemList *il = (UiMenuItemList*)item; + const CxAllocator *a = obj->ctx->allocator; + + UiActiveMenuItemList *ls = cxMalloc( + a, + sizeof(UiActiveMenuItemList)); + ls->object = obj; + ls->menu = p; + ls->index = i; + ls->oldcount = 0; + ls->getvalue = il->getvalue; + ls->callback = il->callback; + 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); +} + +void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { + XmString s = NULL; + Arg args[4]; + int n; + + UiList *ls; + if(list->var && list->var->value) { + ls = list->var->value; + } else { + return; + } + + if(list->oldcount > 0) { + Widget *children; + int nc; + + XtVaGetValues( + list->menu, + XmNchildren, + &children, + XmNnumChildren, + &nc, + NULL); + + for(int i=0;i<list->oldcount;i++) { + XtDestroyWidget(children[list->index + i]); + } + } + + void* elm = ui_list_first(ls); + int i = 0; + if(elm && list->addseparator) { + XtSetArg(args[0], XmNpositionIndex, list->index); + Widget s = XmCreateSeparatorGadget(list->menu, "menuseparator", args, 1); + XtManageChild(s); + 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, + n); + if(s) { + XmStringFree(s); + } + + if(list->callback) { + 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, + eventdata); + XtAddCallback( + mitem, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); + } + + elm = ui_list_next(ls); + i++; + } + + list->oldcount = i; +}