#include "menu.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <cx/linked_list.h>
#include <cx/array_list.h>
static UiMenuBuilder *current_builder;
static UiMenuBuilder global_builder;
static int menu_item_counter =
0;
void uic_menu_init(
void) {
global_builder.current = cxLinkedListCreate(cxDefaultAllocator,
NULL,
CX_STORE_POINTERS);
current_builder = &global_builder;
}
static void add_menu(UiMenu *menu) {
cx_linked_list_add(
(
void**)¤t_builder->menus_begin,
(
void**)¤t_builder->menus_end,
offsetof(UiMenu, item.prev),
offsetof(UiMenu, item.next),
menu);
}
static void add_item(UiMenuItemI *item) {
UiMenu *menu = cxListAt(current_builder->current,
0);
cx_linked_list_add(
(
void**)&menu->items_begin,
(
void**)&menu->items_end,
offsetof(UiMenu, item.prev),
offsetof(UiMenu, item.next),
item);
}
static void mitem_set_id(UiMenuItemI *item) {
snprintf(item->id,
8,
"%x", menu_item_counter++);
}
static char* nl_strdup(
const char* s) {
return s ? strdup(s) :
NULL;
}
int* uic_copy_groups(
const int* groups,
size_t *ngroups) {
*ngroups =
0;
if (!groups) {
return NULL;
}
size_t n;
for (n =
0; groups[n] > -
1; n++) { }
if (ngroups >
0) {
int* newarray = calloc(n+
1,
sizeof(
int));
memcpy(newarray, groups, n *
sizeof(
int));
newarray[n] = -
1;
*ngroups = n;
return newarray;
}
return NULL;
}
void ui_menu_create(
const char *label) {
UiMenu *menu = malloc(
sizeof(UiMenu));
mitem_set_id(&menu->item);
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;
menu->end =
0;
if (cxListSize(current_builder->current) ==
0) {
add_menu(menu);
}
else {
add_item((UiMenuItemI*)menu);
}
uic_add_menu_to_stack(menu);
}
UIEXPORT void ui_menu_end(
void) {
cxListRemove(current_builder->current,
0);
if(cxListSize(current_builder->current) ==
0) {
current_builder = &global_builder;
}
}
void ui_menuitem_create(UiMenuItemArgs args) {
UiMenuItem* item = malloc(
sizeof(UiMenuItem));
mitem_set_id(&item->item);
item->item.prev =
NULL;
item->item.next =
NULL;
item->item.type =
UI_MENU_ITEM;
item->label = nl_strdup(args.label);
item->stockid = nl_strdup(args.stockid);
item->icon = nl_strdup(args.icon);
item->userdata = args.onclickdata;
item->callback = args.onclick;
item->groups = uic_copy_groups(args.groups, &item->ngroups);
add_item((UiMenuItemI*)item);
}
void ui_menuseparator() {
UiMenuItemI *item = malloc(
sizeof(UiMenuItemI));
item->id[
0] =
0;
item->prev =
NULL;
item->next =
NULL;
item->type =
UI_MENU_SEPARATOR;
add_item((UiMenuItemI*)item);
}
void ui_menu_toggleitem_create(UiMenuToggleItemArgs args) {
UiMenuCheckItem *item = malloc(
sizeof(UiMenuCheckItem));
mitem_set_id(&item->item);
item->item.prev =
NULL;
item->item.next =
NULL;
item->item.type =
UI_MENU_CHECK_ITEM;
item->label = nl_strdup(args.label);
item->stockid = nl_strdup(args.stockid);
item->icon = nl_strdup(args.icon);
item->varname = nl_strdup(args.varname);
item->userdata = args.onchangedata;
item->callback = args.onchange;
item->groups = uic_copy_groups(args.groups, &item->ngroups);
add_item((UiMenuItemI*)item);
}
void ui_menu_radioitem_create(UiMenuToggleItemArgs args) {
UiMenuCheckItem* item = malloc(
sizeof(UiMenuCheckItem));
mitem_set_id(&item->item);
item->item.prev =
NULL;
item->item.next =
NULL;
item->item.type =
UI_MENU_CHECK_ITEM;
item->label = nl_strdup(args.label);
item->stockid = nl_strdup(args.stockid);
item->icon = nl_strdup(args.icon);
item->varname = nl_strdup(args.varname);
item->userdata = args.onchangedata;
item->callback = args.onchange;
item->groups = uic_copy_groups(args.groups, &item->ngroups);
add_item((UiMenuItemI*)item);
}
void ui_menu_itemlist_create(UiMenuItemListArgs args) {
UiMenuItemList*item = malloc(
sizeof(UiMenuItemList));
mitem_set_id(&item->item);
item->item.prev =
NULL;
item->item.next =
NULL;
item->item.type =
UI_MENU_ITEM_LIST;
item->getvalue = args.getvalue;
item->callback = args.onselect;
item->userdata = args.onselectdata;
item->varname = nl_strdup(args.varname);
add_item((UiMenuItemI*)item);
}
void ui_menu_checkitemlist_create(UiMenuItemListArgs args) {
UiMenuItemList* item = malloc(
sizeof(UiMenuItemList));
mitem_set_id(&item->item);
item->item.prev =
NULL;
item->item.next =
NULL;
item->item.type =
UI_MENU_CHECKITEM_LIST;
item->callback = args.onselect;
item->userdata = args.onselectdata;
item->varname = nl_strdup(args.varname);
add_item((UiMenuItemI*)item);
}
void ui_menu_radioitemlist_create(UiMenuItemListArgs args) {
UiMenuItemList* item = malloc(
sizeof(UiMenuItemList));
mitem_set_id(&item->item);
item->item.prev =
NULL;
item->item.next =
NULL;
item->item.type =
UI_MENU_RADIOITEM_LIST;
item->callback = args.onselect;
item->userdata = args.onselectdata;
item->varname = nl_strdup(args.varname);
add_item((UiMenuItemI*)item);
}
void uic_add_menu_to_stack(UiMenu* menu) {
cxListInsert(current_builder->current,
0, menu);
}
UiMenu* uic_get_menu_list(
void) {
return current_builder->menus_begin;
}
UIEXPORT void ui_menu_close(
void) {
UiMenu* menu = cxListAt(current_builder->current,
0);
menu->end =
1;
}
UIEXPORT int ui_menu_is_open(
void) {
UiMenu* menu = cxListAt(current_builder->current,
0);
if (menu->end) {
ui_menu_end();
return 0;
}
return 1;
}
void ui_contextmenu_builder(UiMenuBuilder **out_builder) {
UiMenuBuilder *builder = malloc(
sizeof(UiMenuBuilder));
builder->menus_begin =
NULL;
builder->menus_end =
NULL;
builder->current = cxLinkedListCreate(cxDefaultAllocator,
NULL,
CX_STORE_POINTERS);
current_builder = builder;
*out_builder = builder;
ui_menu_create(
NULL);
}
static void free_menuitem(UiMenuItemI *item) {
switch(item->type) {
default:
break;
case UI_MENU: {
UiMenu *menu = (UiMenu*)item;
UiMenuItemI *m = menu->items_begin;
while(m) {
UiMenuItemI *next = m->next;
free_menuitem(m);
m = next;
}
break;
}
case UI_MENU_ITEM: {
UiMenuItem *i = (UiMenuItem*)item;
free(i->groups);
free(i->label);
free(i->stockid);
free(i->icon);
break;
}
case UI_MENU_CHECK_ITEM: {
UiMenuCheckItem *i = (UiMenuCheckItem*)item;
free(i->groups);
free(i->label);
free(i->stockid);
free(i->icon);
free(i->varname);
break;
}
case UI_MENU_RADIO_ITEM: {
UiMenuRadioItem *i = (UiMenuRadioItem*)item;
free(i->groups);
free(i->label);
free(i->stockid);
free(i->icon);
break;
}
case UI_MENU_ITEM_LIST: {
break;
}
case UI_MENU_CHECKITEM_LIST: {
break;
}
case UI_MENU_RADIOITEM_LIST: {
break;
}
}
free(item);
}
void ui_menubuilder_free(UiMenuBuilder *builder) {
UiMenuItemI *m = &builder->menus_begin->item;
while(m) {
UiMenuItemI *next = m->next;
free_menuitem(m);
m = next;
}
cxListDestroy(builder->current);
free(builder);
}