diff --git a/new/ui.idl b/new/ui.idl index 56c4600b..4f6d288b 100644 --- a/new/ui.idl +++ b/new/ui.idl @@ -131,12 +131,12 @@ interface Tab from Control { func NewTab(void) *Tab; interface Menu { - func AddItem(name *const char) *MenuItem; - func AddCheckItem(name *const char) *MenuItem; - func AddQuitItem(void) *MenuItem; - func AddPreferencesItem(void) *MenuItem; - func AddAboutItem(void) *MenuItem; - func AddSeparator(void); + func AppendItem(name *const char) *MenuItem; + func AppendCheckItem(name *const char) *MenuItem; + func AppendQuitItem(void) *MenuItem; + func AppendPreferencesItem(void) *MenuItem; + func AppendAboutItem(void) *MenuItem; + func AppendSeparator(void); }; func NewMenu(name *const char) *Menu; diff --git a/new/unix/GNUmakeinc.mk b/new/unix/GNUmakeinc.mk index 1826c876..01c740b2 100644 --- a/new/unix/GNUmakeinc.mk +++ b/new/unix/GNUmakeinc.mk @@ -3,6 +3,7 @@ osCFILES = \ unix/alloc.c \ unix/main.c \ + unix/menu.c \ unix/oscontainer.c \ unix/text.c \ unix/util.c \ diff --git a/new/unix/menu.c b/new/unix/menu.c new file mode 100644 index 00000000..87eaa10f --- /dev/null +++ b/new/unix/menu.c @@ -0,0 +1,179 @@ +// 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); +} +*/ \ No newline at end of file