# HG changeset patch # User Olaf Wintermann # Date 1684777467 -7200 # Node ID 2cb06c231057d62586fb3677d04a737d6609c00d # Parent 0358f1d9c5064c45ff6521ec3e35a8b76188f639 move some menu code to common diff -r 0358f1d9c506 -r 2cb06c231057 ui/common/menu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/common/menu.c Mon May 22 19:44:27 2023 +0200 @@ -0,0 +1,253 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2023 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "menu.h" + +#include +#include + +static UiMenu *menus_begin; +static UiMenu *menus_end; +static CxList *current; + +static void add_menu(UiMenu *menu) { + cx_linked_list_add( + (void**)&menus_begin, + (void**)&menus_end, + offsetof(UiMenu, item.prev), + offsetof(UiMenu, item.next), + menu); +} + +static void add_item(UiMenuItemI *item) { + UiMenu *menu = cxListAt(current, 0); + cx_linked_list_add( + (void**)&menu->items_begin, + (void**)&menu->items_end, + offsetof(UiMenu, item.prev), + offsetof(UiMenu, item.next), + item); +} + +void ui_menu(char *label) { + if(!current) { + current = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); + } else { + // free current menu hierarchy + cxListClear(current); + } + + // create menu + UiMenu *menu = malloc(sizeof(UiMenu)); + menu->item.prev = NULL; + menu->item.next = NULL; + menu->item.type = UI_MENU; + + menu->label = label; + menu->items_begin = NULL; + menu->items_end = NULL; + menu->parent = NULL; + + add_menu(menu); + cxListAdd(current, menu); +} + +void ui_submenu(char *label) { + UiMenu *menu = malloc(sizeof(UiMenu)); + menu->item.prev = NULL; + menu->item.next = NULL; + menu->item.type = UI_MENU_SUBMENU; + + menu->label = label; + menu->items_begin = NULL; + menu->items_end = NULL; + menu->parent = NULL; + + // add submenu to current menu + add_item((UiMenuItemI*)menu); + + // set the submenu to current menu + cxListInsert(current, 0, menu); +} + +void ui_submenu_end() { + if(current->size < 2) { + return; + } + cxListRemove(current, 0); +} + +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.prev = NULL; + item->item.next = NULL; + item->item.type = UI_MENU_ITEM; + + 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) { + if(!item->groups) { + item->groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 8); + } + cxListAdd(item->groups, &group); + } + va_end(ap); + + add_item((UiMenuItemI*)item); +} + +void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) { + if(!current) { + return; + } + + UiStMenuItem *item = malloc(sizeof(UiStMenuItem)); + item->item.prev = NULL; + item->item.next = NULL; + item->item.type = UI_MENU_STOCK_ITEM; + + 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) { + if(!item->groups) { + item->groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 8); + } + cxListAdd(item->groups, &group); + } + va_end(ap); + + add_item((UiMenuItemI*)item); +} + +void ui_menuseparator() { + if(!current) { + return; + } + + UiMenuItemI *item = malloc(sizeof(UiMenuItemI)); + item->prev = NULL; + item->next = NULL; + item->type = UI_MENU_SEPARATOR; + + add_item((UiMenuItemI*)item); +} + +void ui_checkitem(char *label, ui_callback f, void *userdata) { + if(!current) { + return; + } + + UiCheckItem *item = malloc(sizeof(UiCheckItem)); + item->item.prev = NULL; + item->item.next = NULL; + item->item.type = UI_MENU_CHECK_ITEM; + item->label = label; + item->callback = f; + item->userdata = userdata; + + add_item((UiMenuItemI*)item); +} + +void ui_checkitem_nv(char *label, char *vname) { + if(!current) { + return; + } + + UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV)); + item->item.prev = NULL; + item->item.next = NULL; + item->item.type = UI_MENU_CHECK_ITEM_NV; + item->varname = vname; + item->label = label; + + add_item((UiMenuItemI*)item); +} + +void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) { + if(!current) { + return; + } + + UiMenuItemList *item = malloc(sizeof(UiMenuItemList)); + item->item.prev = NULL; + item->item.next = NULL; + item->item.type = UI_MENU_ITEM_LIST; + item->callback = f; + item->userdata = userdata; + item->list = items; + + add_item((UiMenuItemI*)item); +} + +void ui_menuitem_list_nv(const char *varname, ui_callback f, void *userdata) { + if(!current) { + return; + } + + UiMenuItemListNV *item = malloc(sizeof(UiMenuItemListNV)); + item->item.prev = NULL; + item->item.next = NULL; + item->item.type = UI_MENU_ITEM_LIST; + item->callback = f; + item->userdata = userdata; + item->varname = varname; + + add_item((UiMenuItemI*)item); +} + + + +UiMenu* uic_get_menu_list(void) { + return menus_begin; +} diff -r 0358f1d9c506 -r 2cb06c231057 ui/common/menu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/common/menu.h Mon May 22 19:44:27 2023 +0200 @@ -0,0 +1,127 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2023 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UIC_MENU_H +#define UIC_MENU_H + +#include "../ui/menu.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UiMenuItemI UiMenuItemI; +typedef struct UiMenu UiMenu; +typedef struct UiMenuItem UiMenuItem; +typedef struct UiStMenuItem UiStMenuItem; +typedef struct UiCheckItem UiCheckItem; +typedef struct UiCheckItemNV UiCheckItemNV; +typedef struct UiMenuItemList UiMenuItemList; +typedef struct UiMenuItemListNV UiMenuItemListNV; + +enum UiMenuItemType { + UI_MENU = 0, + UI_MENU_SUBMENU, + UI_MENU_ITEM, + UI_MENU_STOCK_ITEM, + UI_MENU_CHECK_ITEM, + UI_MENU_CHECK_ITEM_NV, + UI_MENU_ITEM_LIST, + UI_MENU_ITEM_LIST_NV, + UI_MENU_SEPARATOR +}; + +typedef enum UiMenuItemType UiMenuItemType; + +struct UiMenuItemI { + UiMenuItemI *prev; + UiMenuItemI *next; + UiMenuItemType type; +}; + +struct UiMenu { + UiMenuItemI item; + char *label; + UiMenuItemI *items_begin; + UiMenuItemI *items_end; + UiMenu *parent; +}; + +struct UiMenuItem { + UiMenuItemI item; + ui_callback callback; + char *label; + void *userdata; + CxList *groups; +}; + +struct UiStMenuItem { + UiMenuItemI item; + ui_callback callback; + char *stockid; + void *userdata; + CxList *groups; +}; + +struct UiCheckItem { + UiMenuItemI item; + char *label; + ui_callback callback; + void *userdata; +}; + +struct UiCheckItemNV { + UiMenuItemI item; + char *label; + char *varname; +}; + +struct UiMenuItemList { + UiMenuItemI item; + ui_callback callback; + void *userdata; + UiList *list; +}; + +struct UiMenuItemListNV { + UiMenuItemI item; + ui_callback callback; + void *userdata; + const char *varname; +}; + +UiMenu* uic_get_menu_list(void); + +#ifdef __cplusplus +} +#endif + +#endif /* UIC_MENU_H */ + diff -r 0358f1d9c506 -r 2cb06c231057 ui/common/objs.mk --- a/ui/common/objs.mk Mon May 22 16:17:26 2023 +0200 +++ b/ui/common/objs.mk Mon May 22 19:44:27 2023 +0200 @@ -33,6 +33,7 @@ COMMON_OBJ += document.o COMMON_OBJ += object.o COMMON_OBJ += types.o +COMMON_OBJ += menu.o COMMON_OBJ += properties.o COMMON_OBJ += ucx_properties.o diff -r 0358f1d9c506 -r 2cb06c231057 ui/gtk/menu.c --- a/ui/gtk/menu.c Mon May 22 16:17:26 2023 +0200 +++ b/ui/gtk/menu.c Mon May 22 19:44:27 2023 +0200 @@ -34,6 +34,7 @@ #include "menu.h" #include "toolkit.h" #include "../common/context.h" +#include "../common/menu.h" #include "../ui/properties.h" #include "../ui/window.h" #include "container.h" @@ -41,207 +42,22 @@ #include #include -static UiMenu *menus_begin; -static UiMenu *menus_end; -static CxList *current; -static void add_menu(UiMenu *menu) { - cx_linked_list_add( - (void**)&menus_begin, - (void**)&menus_end, - offsetof(UiMenu, item.prev), - offsetof(UiMenu, item.next), - menu); -} - -static void add_item(UiMenuItemI *item) { - UiMenu *menu = cxListAt(current, 0); - cx_linked_list_add( - (void**)&menu->items_begin, - (void**)&menu->items_end, - offsetof(UiMenu, item.prev), - offsetof(UiMenu, item.next), - item); -} - -void ui_menu(char *label) { - if(!current) { - current = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); - } else { - // free current menu hierarchy - cxListClear(current); - } - - // create menu - UiMenu *menu = malloc(sizeof(UiMenu)); - menu->item.prev = NULL; - menu->item.next = NULL; - menu->item.add_to = (ui_menu_add_f)add_menu_widget; - - menu->label = label; - menu->items_begin = NULL; - menu->items_end = NULL; - menu->parent = NULL; - - add_menu(menu); - cxListAdd(current, menu); -} - -void ui_submenu(char *label) { - UiMenu *menu = malloc(sizeof(UiMenu)); - menu->item.prev = NULL; - menu->item.next = NULL; - menu->item.add_to = (ui_menu_add_f)add_menu_widget; - - menu->label = label; - menu->items_begin = NULL; - menu->items_end = NULL; - menu->parent = NULL; - - // add submenu to current menu - add_item((UiMenuItemI*)menu); - - // set the submenu to current menu - cxListInsert(current, 0, menu); -} - -void ui_submenu_end() { - if(current->size < 2) { - return; - } - cxListRemove(current, 0); -} - -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.prev = NULL; - item->item.next = NULL; - 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) { - if(!item->groups) { - item->groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 8); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - add_item((UiMenuItemI*)item); -} - -void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) { - if(!current) { - return; - } - - UiStMenuItem *item = malloc(sizeof(UiStMenuItem)); - item->item.prev = NULL; - item->item.next = NULL; - 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) { - if(!item->groups) { - item->groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 8); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - add_item((UiMenuItemI*)item); -} - -void ui_menuseparator() { - if(!current) { - return; - } - - UiMenuItemI *item = malloc(sizeof(UiMenuItemI)); - item->prev = NULL; - item->next = NULL; - item->add_to = (ui_menu_add_f)add_menuseparator_widget; - - add_item((UiMenuItemI*)item); -} - -void ui_checkitem(char *label, ui_callback f, void *userdata) { - if(!current) { - return; - } - - UiCheckItem *item = malloc(sizeof(UiCheckItem)); - item->item.prev = NULL; - item->item.next = NULL; - item->item.add_to = (ui_menu_add_f)add_checkitem_widget; - item->label = label; - item->callback = f; - item->userdata = userdata; - - add_item((UiMenuItemI*)item); -} - -void ui_checkitem_nv(char *label, char *vname) { - if(!current) { - return; - } - - UiCheckItemNV *item = malloc(sizeof(UiCheckItemNV)); - item->item.prev = NULL; - item->item.next = NULL; - item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget; - item->varname = vname; - item->label = label; - - add_item((UiMenuItemI*)item); -} - -void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) { - if(!current) { - return; - } - - UiMenuItemList *item = malloc(sizeof(UiMenuItemList)); - item->item.prev = NULL; - item->item.next = NULL; - item->item.add_to = (ui_menu_add_f)add_menuitem_list_widget; - item->callback = f; - item->userdata = userdata; - item->list = items; - - add_item((UiMenuItemI*)item); -} +static ui_menu_add_f createMenuItem[] = { + /* UI_MENU */ add_menu_widget, + /* UI_MENU_SUBMENU */ add_menu_widget, + /* UI_MENU_ITEM */ add_menuitem_widget, + /* UI_MENU_STOCK_ITEM */ add_menuitem_st_widget, + /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, + /* UI_MENU_CHECK_ITEM_NV */ add_checkitemnv_widget, + /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_ITEM_LIST_NV */ NULL, // TODO + /* UI_MENU_SEPARATOR */ add_menuseparator_widget +}; // private menu functions GtkWidget *ui_create_menubar(UiObject *obj) { + UiMenu *menus_begin = uic_get_menu_list(); if(menus_begin == NULL) { return NULL; } @@ -251,7 +67,7 @@ UiMenu *ls = menus_begin; while(ls) { UiMenu *menu = ls; - menu->item.add_to(mb, 0, &menu->item, obj); + add_menu_widget(mb, 0, &menu->item, obj); ls = (UiMenu*)ls->item.next; } @@ -269,7 +85,7 @@ UiMenuItemI *it = menu->items_begin; int index = 0; while(it) { - it->add_to(menu_widget, index, it, obj); + createMenuItem[it->type](menu_widget, index, it, obj); it = it->next; index++; diff -r 0358f1d9c506 -r 2cb06c231057 ui/gtk/menu.h --- a/ui/gtk/menu.h Mon May 22 16:17:26 2023 +0200 +++ b/ui/gtk/menu.h Mon May 22 19:44:27 2023 +0200 @@ -30,6 +30,7 @@ #define MENU_H #include "../ui/menu.h" +#include "../common/menu.h" #include #include "toolkit.h" @@ -37,67 +38,10 @@ extern "C" { #endif -typedef struct UiMenuItemI UiMenuItemI; -typedef struct UiMenu UiMenu; -typedef struct UiMenuItem UiMenuItem; -typedef struct UiStMenuItem UiStMenuItem; -typedef struct UiCheckItem UiCheckItem; -typedef struct UiCheckItemNV UiCheckItemNV; -typedef struct UiMenuItemList UiMenuItemList; typedef struct UiActiveMenuItemList UiActiveMenuItemList; -typedef GtkWidget*(*ui_menu_add_f)(GtkWidget *, int, UiMenuItemI*, UiObject*); - -struct UiMenuItemI { - UiMenuItemI *prev; - UiMenuItemI *next; - ui_menu_add_f add_to; -}; - -struct UiMenu { - UiMenuItemI item; - char *label; - UiMenuItemI *items_begin; - UiMenuItemI *items_end; - UiMenu *parent; -}; - -struct UiMenuItem { - UiMenuItemI item; - ui_callback callback; - char *label; - void *userdata; - CxList *groups; -}; - -struct UiStMenuItem { - UiMenuItemI item; - ui_callback callback; - char *stockid; - void *userdata; - CxList *groups; -}; - -struct UiCheckItem { - UiMenuItemI item; - char *label; - ui_callback callback; - void *userdata; -}; - -struct UiCheckItemNV { - UiMenuItemI item; - char *label; - char *varname; -}; - -struct UiMenuItemList { - UiMenuItemI item; - ui_callback callback; - void *userdata; - UiList *list; -}; +typedef void(*ui_menu_add_f)(GtkWidget *, int, UiMenuItemI*, UiObject*); struct UiActiveMenuItemList { UiObject *object;