#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;
static void *tmp_eventdata;
static int tmp_eventdata_type;
void uic_set_tmp_eventdata(
void *eventdata,
int type) {
tmp_eventdata = eventdata;
tmp_eventdata_type = type;
}
void* uic_get_tmp_eventdata(
void) {
return tmp_eventdata;
}
int uic_get_tmp_eventdata_type(
void) {
return tmp_eventdata_type;
}
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_states(
const int* states,
size_t *nstates) {
*nstates =
0;
if (!states) {
return NULL;
}
size_t n;
for (n =
0; states[n] >
-1; n++) { }
if (nstates >
0) {
int* newarray = calloc(n
+1,
sizeof(
int));
memcpy(newarray, states, n *
sizeof(
int));
newarray[n] =
-1;
*nstates = 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 = nl_strdup(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->icon = nl_strdup(args->icon);
item->userdata = args->onclickdata;
item->callback = args->onclick;
item->states = uic_copy_states(args->states, &item->nstates);
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->icon = nl_strdup(args->icon);
item->varname = nl_strdup(args->varname);
item->userdata = args->onchangedata;
item->callback = args->onchange;
item->states = uic_copy_states(args->nstates, &item->nstates);
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_RADIO_ITEM;
item->label = nl_strdup(args->label);
item->icon = nl_strdup(args->icon);
item->varname = nl_strdup(args->varname);
item->userdata = args->onchangedata;
item->callback = args->onchange;
item->states = uic_copy_states(args->nstates, &item->nstates);
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);
item->addseparator = args->addseparator;
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);
builder->ref =
1;
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;
free(menu->label);
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->states);
free(i->label);
free(i->icon);
break;
}
case UI_MENU_CHECK_ITEM: {
UiMenuCheckItem *i = (UiMenuCheckItem*)item;
free(i->states);
free(i->label);
free(i->icon);
free(i->varname);
break;
}
case UI_MENU_RADIO_ITEM: {
UiMenuRadioItem *i = (UiMenuRadioItem*)item;
free(i->states);
free(i->label);
free(i->icon);
free(i->varname);
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;
}
cxListFree(builder->current);
free(builder);
}
void ui_menubuilder_ref(UiMenuBuilder *builder) {
builder->ref++;
}
void ui_menubuilder_unref(UiMenuBuilder *builder) {
if(--builder->ref <=
0) {
ui_menubuilder_free(builder);
}
}