libui/new/unix/menu.c

179 lines
4.2 KiB
C

// 23 april 2015
#include "uipriv_unix.h"
static GArray *menus = NULL;
static gboolean menusFinalized = FALSE;
struct menu {
uiMenu m;
char *name;
GHashTable *gtkMenuItems; // map[GtkWindow]GtkMenuItem
GHashTable *gtkSubmenus; // map[GtkWindow]GtkMenu
GArray *items; // []struct menuItem
};
struct menuItem {
uiMenuItem mi;
char *name;
int type;
void (*onClicked)(uiMenuItem *, uiWindow *, void *);
void *onClickedData;
GtkWidget *baseItem; // for property binding
GHashTable *uiWindows; // map[GtkMenuItem]uiWindow
};
enum {
typeRegular,
typeCheckbox,
typeQuit,
typePreferences,
typeAbout,
typeSeparator,
};
#define NEWHASH() g_hash_table_new(g_direct_hash, g_direct_equal)
static uiMenuItem *newItem(struct menu *m, int type, const char *name)
{
struct menuItem *item;
if (menusFinalized)
complain("attempt to create a new menu item after menus have been finalized");
g_array_set_size(m->items, m->items->len + 1);
item = &g_array_index(m->items, struct menuItem, m->items->len - 1);
item->type = type;
switch (item->type) {
case typeQuit:
item->name = g_strdup("Quit");
break;
case typePreferences:
item->name = g_strdup("Preferences...");
break;
case typeAbout:
item->name = g_strdup("About");
break;
case typeSeparator:
break;
default:
item->name = g_strdup(name);
break;
}
switch (item->type) {
case typeCheckbox:
item->baseItem = gtk_check_menu_item_new_with_label(item->name);
break;
case typeSeparator:
item->baseItem = gtk_separator_menu_item_new();
break;
default:
item->baseItem = gtk_menu_item_new_with_label(item->name);
break;
}
item->uiWindows = NEWHASH();
// TODO vtable
return uiMenuItem(item);
}
uiMenuItem *menuAppendItem(uiMenu *mm, const char *name)
{
return newItem((struct menu *) mm, typeRegular, name);
}
uiMenuItem *menuAppendCheckItem(uiMenu *mm, const char *name)
{
return newItem((struct menu *) mm, typeCheckbox, name);
}
uiMenuItem *menuAppendQuitItem(uiMenu *mm)
{
// TODO check multiple quit items
// TODO conditionally add separator
newItem((struct menu *) mm, typeSeparator, NULL);
return newItem((struct menu *) mm, typeQuit, NULL);
}
uiMenuItem *menuAppendPreferencesItem(uiMenu *mm)
{
// TODO check multiple preferences items
// TODO conditionally add separator
newItem((struct menu *) mm, typeSeparator, NULL);
return newItem((struct menu *) mm, typePreferences, NULL);
}
uiMenuItem *menuAppendAboutItem(uiMenu *mm)
{
// TODO check multiple about items
// TODO conditionally add separator
newItem((struct menu *) mm, typeSeparator, NULL);
return newItem((struct menu *) mm, typeAbout, NULL);
}
void menuAppendSeparator(uiMenu *mm)
{
// TODO check multiple about items
newItem((struct menu *) mm, typeSeparator, NULL);
}
uiMenu *uiNewMenu(const char *name)
{
struct menu *m;
if (menusFinalized)
complain("attempt to create a new menu after menus have been finalized");
if (menus == NULL)
menus = g_array_new(FALSE, TRUE, sizeof (struct menu));
// thanks Company in irc.gimp.net/#gtk+
g_array_set_size(menus, menus->len + 1);
m = &g_array_index(menus, struct menu, menus->len - 1);
m->name = g_strdup(name);
m->gtkMenuItems = NEWHASH();
m->gtkSubmenus = NEWHASH();
m->items = g_array_new(FALSE, TRUE, sizeof (struct menuItem));
uiMenu(m)->AppendItem = menuAppendItem;
uiMenu(m)->AppendCheckItem = menuAppendCheckItem;
uiMenu(m)->AppendQuitItem = menuAppendQuitItem;
uiMenu(m)->AppendPreferencesItem = menuAppendPreferencesItem;
uiMenu(m)->AppendAboutItem = menuAppendAboutItem;
uiMenu(m)->AppendSeparator = menuAppendSeparator;
return uiMenu(m);
}
/*
void menuItemDestroy(struct menuItem *item)
{
// TODO checck that item->uiWindows is empty
g_hash_table_destroy(item->uiWindows);
gtk_widget_destroy(item->baseItem);
if (item->name != NULL)
g_free(item->name);
}
void menuDestroy(void)
{
guint i, j;
struct menu *m;
for (i = 0; i < menus->len; i++) {
m = &g_array_index(menus, struct menu, i);
for (j = 0; j < m->items->len; j++)
menuItemDestroy(&g_array_index(m->items, struct menuItem, j));
g_array_free(m->items, TRUE);
// TODO check that m->gtkSubmenus is empty
g_hash_table_destroy(m->gtkSubmenus);
// TODO check that m->gtkMenuItem is empty
g_hash_table_destroy(m->gtkMenuItem);
g_free(m->name);
}
g_array_free(menus, TRUE);
}
*/