--- a/ui/qt/menu.cpp Tue Feb 25 21:11:00 2025 +0100 +++ b/ui/qt/menu.cpp Sat Apr 05 16:46:11 2025 +0200 @@ -35,391 +35,203 @@ #include "menu.h" #include "toolkit.h" #include "../common/context.h" +#include "../common/menu.h" #include "../ui/properties.h" #include "../ui/window.h" #include "stock.h" #include "container.h" -static UcxList *menus; -static UcxList *current; - -/* -------------------------- UiMenu -------------------------- */ - -UiMenu::UiMenu(char* label) { - this->items = NULL; - this->label = label; -} -void UiMenu::addMenuItem(UiMenuItemI* item) { - items = ucx_list_append(items, item); -} +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 UiMenu::addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu) { - QMenu *m = NULL; - if(menubar) { - m = menubar->addMenu(label); - } else { - m = menu->addMenu(label); - } - - UCX_FOREACH(elm, items) { - UiMenuItemI *item = (UiMenuItemI*)elm->data; - item->addTo(obj, NULL, m); +/* + * create all menu child items + */ +static void add_menu_items(QMenu *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++; } } - -/* -------------------------- UiMenuItem -------------------------- */ - -UiMenuItem::UiMenuItem(char* label, ui_callback f, void* userdata) { - this->label = label; - this->callback = f; - this->userdata = userdata; - this->groups = NULL; +void add_menu_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenu *m = (UiMenu*)item; + QMenu *menu = parent->addMenu(m->label); + add_menu_items(menu, i, m, obj); } -void UiMenuItem::addGroup(int group) { - groups = ucx_list_append(groups, (void*)(intptr_t)group); -} - -void UiMenuItem::setCheckable(bool c) { - checkable = c; -} - -void UiMenuItem::addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu) { +static UiAction* create_action( + UiObject *obj, + const char *icon, + const char *label, + ui_callback callback, + void *userdata, + int *states) +{ QString str = QString::fromUtf8(label); UiAction *action = new UiAction(obj, str, callback, userdata); - action->setCheckable(checkable); - if(checkable) { - action->setChecked(false); + if(icon) { + action->setIcon(QIcon::fromTheme(icon)); + action->setIconVisibleInMenu(true); } - menu->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); + + if(states) { + size_t nstates = uic_group_array_size(states); + uic_add_group_widget_i(obj->ctx, action, (ui_enablefunc)ui_action_enable, states, nstates); + action->setEnabled(false); + } + + return action; } - -/* -------------------------- UiStMenuItem -------------------------- */ - -UiStMenuItem::UiStMenuItem(char* stockid, ui_callback f, void* userdata) { - this->stockid = stockid; - this->callback = f; - this->userdata = userdata; - this->groups = NULL; -} - -void UiStMenuItem::addGroup(int group) { - groups = ucx_list_append(groups, (void*)(intptr_t)group); -} - -void UiStMenuItem::addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu) { - UiStockItem *stockItem = ui_get_stock_item(stockid); - - QString str = QString::fromUtf8(stockItem->label); - UiAction *action = new UiAction(obj, str, callback, userdata); - action->setIcon(QIcon::fromTheme(stockItem->icon_name)); - action->setIconVisibleInMenu(true); - menu->addAction(action); - //UiEventWrapper *ev = new UiEventWrapper(callback, userdata); +void add_menuitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuItem *it = (UiMenuItem*)item; + UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->groups); + parent->addAction(action); QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); } - -/* -------------------------- UiMenuSeparator -------------------------- */ - -void UiMenuSeparator::addTo(UiObject* obj, QMenuBar* menubar, QMenu* menu) { - menu->addSeparator(); +void add_menuseparator_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + parent->addSeparator(); } - -/* -------------------------- UiCheckItemNV -------------------------- */ - -UiCheckItemNV::UiCheckItemNV(char* label, char* varname) { - this->label = label; - this->varname = varname; +void add_checkitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuCheckItem *it = (UiMenuCheckItem*)item; + + UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->groups); + parent->addAction(action); + action->setCheckable(true); + action->prepare_event = ui_checkableaction_prepare_event; + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, it->varname, UI_VAR_INTEGER); + if(var) { + UiInteger *value = (UiInteger*)var->value; + value->obj = action; + value->get = ui_checkableaction_get; + value->set = ui_checkableaction_set; + + action->setChecked((bool)value->value); + } + action->var = var; } -void UiCheckItemNV::addTo(UiObject* obj, QMenuBar* menubar, QMenu* menu) { - QString str = QString::fromUtf8(label); - UiAction *action = new UiAction(obj, str, NULL, NULL); +void add_radioitem_widget(QMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuRadioItem *it = (UiMenuRadioItem*)item; + + UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->groups); + parent->addAction(action); action->setCheckable(true); - menu->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); + action->prepare_event = ui_actiongroup_prepare_event; - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_INTEGER); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, it->varname, UI_VAR_INTEGER); if(var) { UiInteger *value = (UiInteger*)var->value; - action->setChecked(value->value); - value->obj = action; - value->get = ui_checkitem_get; - value->set = ui_checkitem_set; - value = 0; - } else { - // TODO: error + QActionGroup *group = (QActionGroup*)value->obj; + if(!group) { + group = new QActionGroup(parent); + value->obj = group; + } + group->addAction(action); + value->get = ui_actiongroup_get; + value->set = ui_actiongroup_set; + if(value->value != 0) { + ui_actiongroup_set(value, value->value); + } + } + action->var; +} + +void ui_actiongroup_prepare_event(UiEvent *event, UiAction *action) { + if(action->var) { + UiInteger *value = (UiInteger*)action->var->value; + event->eventdata = value; + event->intval = value->get(value); } } - -/* -------------------------- UiAction -------------------------- */ - -UiAction::UiAction(UiObject *obj, QString &label, ui_callback f, void* userdata) : QAction(label, NULL) { - //QAction(label, NULL); - this->obj = obj; - this->callback = f; - this->userdata = userdata; -} - -void UiAction::trigger() { - if(!callback) { - return; +int64_t ui_actiongroup_get(UiInteger *value) { + QActionGroup *group = (QActionGroup*)value->obj; + auto actions = group->actions(); + int i = 1; + foreach(const QAction *action, actions) { + if(action->isChecked()) { + value->value = i; + break; + } + i++; } - - UiEvent e; - e.obj = obj; - e.window = obj->window; - e.document = obj->ctx->document; - e.eventdata = NULL; - - if(isCheckable()) { - e.intval = isChecked(); - } else { - e.intval = 0; - } - - callback(&e, userdata); + return value->value; } - -void ui_menu(char *label) { - // free current menu hierarchy - ucx_list_free(current); - - // create menu - UiMenu *menu = new UiMenu(label); - - current = ucx_list_prepend(NULL, menu); - menus = ucx_list_append(menus, menu); +void ui_actiongroup_set(UiInteger *value, int64_t i) { + QActionGroup *group = (QActionGroup*)value->obj; + auto actions = group->actions(); + if(i > 0) { + if(i-1 < actions.size()) { + actions[i]->setEnabled(true); + } + value->value = i; + } else { + foreach(QAction *action, actions) { + action->setEnabled(false); + } + value->value = 0; + } } -void ui_submenu(char *label) { - UiMenu *menu = new UiMenu(label); - - // add submenu to current menu - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(menu); +void add_menuitem_list_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { - // 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); - //UcxList *c = 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 = new UiMenuItem(label, f, userdata); - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->addGroup(group); - } - va_end(ap); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} - -void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) { - if(!current) { +void ui_add_menus(UiObject *obj, QMainWindow *window) { + UiMenu *menus_begin = uic_get_menu_list(); + if(menus_begin == NULL) { return; } - UiStMenuItem *item = new UiStMenuItem(stockid, f, userdata); - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->addGroup(group); - } - va_end(ap); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} - -void ui_menuseparator() { - if(!current) { - return; - } - - UiMenuSeparator *item = new UiMenuSeparator(); - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} - -void ui_checkitem(char *label, ui_callback f, void *userdata) { - if(!current) { - return; - } - - UiMenuItem *item = new UiMenuItem(label, f, userdata); - item->setCheckable(true); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} - -void ui_checkitem_nv(char *label, char *vname) { - if(!current) { - return; - } - - UiCheckItemNV *item = new UiCheckItemNV(label, vname); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} - -void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) { - -} - -void ui_add_menus(UiObject *obj, QMainWindow *window) { QMenuBar *mb = window->menuBar(); - UCX_FOREACH(elm, menus) { - UiMenu *menu = (UiMenu*)elm->data; - menu->addTo(obj, mb, NULL); + UiMenu *ls = menus_begin; + while(ls) { + if(ls->item.type == UI_MENU) { + QMenu *menu = mb->addMenu(ls->label); + add_menu_items(menu, 0, ls, obj); + } + ls = (UiMenu*)ls->item.next; } } -int ui_checkitem_get(UiInteger *i) { - QAction *action = (QAction*)i->obj; - i->value = action->isChecked(); - return i->value; -} - -void ui_checkitem_set(UiInteger *i, int value) { - QAction *action = (QAction*)i->obj; - i->value = value; - action->setChecked(value); -} - - -/* - * widget menu functions - */ - -UiContextMenuHandler::UiContextMenuHandler(QWidget *widget, QMenu* menu) { - this->widget = widget; - this->menu = menu; -} - -void UiContextMenuHandler::contextMenuEvent(const QPoint & pos) { - menu->popup(widget->mapToGlobal(pos)); -} -UIMENU ui_contextmenu(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - return ui_contextmenu_w(obj, ct->current); -} - -UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { - UiContainer *ct = uic_get_current_container(obj); - - QMenu *menu = new QMenu(widget); - widget->setContextMenuPolicy(Qt::CustomContextMenu); - - UiContextMenuHandler *handler = new UiContextMenuHandler(widget, menu); - QObject::connect( - widget, - SIGNAL(customContextMenuRequested(QPoint)), - handler, - SLOT(contextMenuEvent(QPoint))); - - ct->menu = menu; - - return menu; -} - -void ui_contextmenu_popup(UIMENU menu) { - +void ui_checkableaction_prepare_event(UiEvent *event, UiAction *action) { + if(action->var) { + event->eventdata = action->var->value; + } + event->intval = action->isChecked(); } -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 - QString str = QString::fromUtf8(label); - UiAction *action = new UiAction(obj, str, f, userdata); - ct->menu->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); +int64_t ui_checkableaction_get(UiInteger *value) { + UiAction *action= (UiAction*)value->obj; + value->value = action->isChecked(); + return value->value; } -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_checkableaction_set(UiInteger *value, int64_t i) { + UiAction *action = (UiAction*)value->obj; + value->value = i; + if(i != 0) { + action->setChecked((bool)i); + } } -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); - - QString str = QString::fromUtf8(stockItem->label); - UiAction *action = new UiAction(obj, str, f, userdata); - action->setIcon(QIcon::fromTheme(stockItem->icon_name)); - action->setIconVisibleInMenu(true); - ct->menu->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); -}