ui/common/menu.c

Mon, 22 May 2023 21:21:20 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 22 May 2023 21:21:20 +0200
branch
newapi
changeset 176
bc63cb601f6d
parent 175
2cb06c231057
child 205
b1ac0dd1d38b
permissions
-rw-r--r--

port motif code to ucx 3

/*
 * 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 <stdarg.h>

#include <cx/linked_list.h>
#include <cx/array_list.h>

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;
}

mercurial