mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 05:08:54 -07:00
Normalisation of callbacks for menus. App menu converted to new Menus.
This commit is contained in:
@@ -19,12 +19,6 @@ extern const unsigned char *defaultDialogIcons[];
|
||||
// MAIN DEBUG FLAG
|
||||
int debug;
|
||||
|
||||
// MenuItem map for the application menu
|
||||
struct hashmap_s menuItemMapForApplicationMenu;
|
||||
|
||||
// RadioGroup map for the application menu. Maps a menuitem id with its associated radio group items
|
||||
struct hashmap_s radioGroupMapForApplicationMenu;
|
||||
|
||||
// MenuItem map for the tray menu
|
||||
struct hashmap_s menuItemMapForTrayMenu;
|
||||
|
||||
@@ -136,8 +130,6 @@ struct Application {
|
||||
|
||||
// Menu
|
||||
Menu *applicationMenu;
|
||||
const char *menuAsJSON;
|
||||
JsonNode *processedMenu;
|
||||
|
||||
// Tray
|
||||
const char *trayMenuAsJSON;
|
||||
@@ -398,15 +390,6 @@ const char* createContextMenuMessage(const char *menuItemID, const char *givenCo
|
||||
return result;
|
||||
}
|
||||
|
||||
// Callback for menu items
|
||||
void menuItemPressedForApplicationMenu(id self, SEL cmd, id sender) {
|
||||
const char *menuItemID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||
// Notify the backend
|
||||
const char *message = concat("MC", menuItemID);
|
||||
messageFromWindowCallback(message);
|
||||
MEMFREE(message);
|
||||
}
|
||||
|
||||
// Callback for tray items
|
||||
void menuItemPressedForTrayMenu(id self, SEL cmd, id sender) {
|
||||
const char *menuItemID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||
@@ -428,25 +411,6 @@ void menuItemPressedForContextMenus(id self, SEL cmd, id sender) {
|
||||
MEMFREE(contextMenuMessage);
|
||||
}
|
||||
|
||||
// Callback for menu items
|
||||
void checkboxMenuItemPressedForApplicationMenu(id self, SEL cmd, id sender, struct hashmap_s *menuItemMap) {
|
||||
const char *menuItemID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||
|
||||
// Get the menu item from the menu item map
|
||||
id menuItem = (id)hashmap_get(&menuItemMapForApplicationMenu, (char*)menuItemID, strlen(menuItemID));
|
||||
|
||||
// Get the current state
|
||||
bool state = msg(menuItem, s("state"));
|
||||
|
||||
// Toggle the state
|
||||
msg(menuItem, s("setState:"), (state? NSControlStateValueOff : NSControlStateValueOn));
|
||||
|
||||
// Notify the backend
|
||||
const char *message = concat("MC", menuItemID);
|
||||
messageFromWindowCallback(message);
|
||||
MEMFREE(message);
|
||||
}
|
||||
|
||||
// Callback for tray menu items
|
||||
void checkboxMenuItemPressedForTrayMenu(id self, SEL cmd, id sender, struct hashmap_s *menuItemMap) {
|
||||
const char *menuItemID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||
@@ -487,43 +451,6 @@ void checkboxMenuItemPressedForContextMenus(id self, SEL cmd, id sender, struct
|
||||
MEMFREE(contextMenuMessage);
|
||||
}
|
||||
|
||||
// radioMenuItemPressedForApplicationMenu
|
||||
void radioMenuItemPressedForApplicationMenu(id self, SEL cmd, id sender) {
|
||||
const char *menuItemID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||
|
||||
// Get the menu item from the menu item map
|
||||
id menuItem = (id)hashmap_get(&menuItemMapForApplicationMenu, (char*)menuItemID, strlen(menuItemID));
|
||||
|
||||
// Check the menu items' current state
|
||||
bool selected = msg(menuItem, s("state"));
|
||||
|
||||
// If it's already selected, exit early
|
||||
if (selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get this item's radio group members and turn them off
|
||||
id *members = (id*)hashmap_get(&radioGroupMapForApplicationMenu, (char*)menuItemID, strlen(menuItemID));
|
||||
|
||||
// Uncheck all members of the group
|
||||
id thisMember = members[0];
|
||||
int count = 0;
|
||||
while(thisMember != NULL) {
|
||||
msg(thisMember, s("setState:"), NSControlStateValueOff);
|
||||
count = count + 1;
|
||||
thisMember = members[count];
|
||||
}
|
||||
|
||||
// check the selected menu item
|
||||
msg(menuItem, s("setState:"), NSControlStateValueOn);
|
||||
|
||||
// Notify the backend
|
||||
const char *message = concat("MC", menuItemID);
|
||||
messageFromWindowCallback(message);
|
||||
MEMFREE(message);
|
||||
}
|
||||
|
||||
|
||||
// radioMenuItemPressedForTrayMenu
|
||||
void radioMenuItemPressedForTrayMenu(id self, SEL cmd, id sender) {
|
||||
const char *menuItemID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||
@@ -650,22 +577,6 @@ void themeChanged(id self, SEL cmd, id sender) {
|
||||
// Debug(app, "willFinishLaunching called!");
|
||||
// }
|
||||
|
||||
void allocateMenuHashMaps(struct Application *app) {
|
||||
// Allocate new menuItem map
|
||||
if( 0 != hashmap_create((const unsigned)16, &menuItemMapForApplicationMenu)) {
|
||||
// Couldn't allocate map
|
||||
Fatal(app, "Not enough memory to allocate menuItemMapForApplicationMenu!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate the Radio Group Cache
|
||||
if( 0 != hashmap_create((const unsigned)4, &radioGroupMapForApplicationMenu)) {
|
||||
// Couldn't allocate map
|
||||
Fatal(app, "Not enough memory to allocate radioGroupMapForApplicationMenu!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void allocateTrayHashMaps(struct Application *app) {
|
||||
// Allocate new menuItem map
|
||||
if( 0 != hashmap_create((const unsigned)16, &menuItemMapForTrayMenu)) {
|
||||
@@ -749,8 +660,6 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
||||
|
||||
// Menu
|
||||
result->applicationMenu = NULL;
|
||||
result->menuAsJSON = NULL;
|
||||
result->processedMenu = NULL;
|
||||
|
||||
// Tray
|
||||
result->trayMenuAsJSON = NULL;
|
||||
@@ -780,37 +689,6 @@ int releaseNSObject(void *const context, struct hashmap_element_s *const e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void destroyMenu(struct Application *app) {
|
||||
|
||||
if( app->menuAsJSON == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Free menu item hashmap
|
||||
hashmap_destroy(&menuItemMapForApplicationMenu);
|
||||
|
||||
// Free radio group members
|
||||
if( hashmap_num_entries(&radioGroupMapForApplicationMenu) > 0 ) {
|
||||
if (0!=hashmap_iterate_pairs(&radioGroupMapForApplicationMenu, freeHashmapItem, NULL)) {
|
||||
Fatal(app, "failed to release hashmap entries!");
|
||||
}
|
||||
}
|
||||
|
||||
//Free radio groups hashmap
|
||||
hashmap_destroy(&radioGroupMapForApplicationMenu);
|
||||
|
||||
// Release processed menu
|
||||
if( app->processedMenu != NULL) {
|
||||
json_delete(app->processedMenu);
|
||||
app->processedMenu = NULL;
|
||||
}
|
||||
|
||||
// Remove the menu if we have one
|
||||
id menubar = msg(msg(c("NSApplication"), s("sharedApplication")), s("mainMenu"));
|
||||
Debug(app, "Destroying menubar: %p", menubar);
|
||||
msg(menubar, s("release"));
|
||||
}
|
||||
|
||||
void destroyContextMenus(struct Application *app) {
|
||||
|
||||
// Free menu item hashmap
|
||||
@@ -919,9 +797,6 @@ void DestroyApplication(struct Application *app) {
|
||||
msg( c("NSEvent"), s("removeMonitor:"), app->mouseUpMonitor);
|
||||
}
|
||||
|
||||
// Destroy the menu
|
||||
destroyMenu(app);
|
||||
|
||||
// Delete the application menu if we have one
|
||||
if( app->applicationMenu != NULL ) {
|
||||
DeleteMenu(app->applicationMenu);
|
||||
@@ -1411,7 +1286,6 @@ void SetDebug(void *applicationPointer, int flag) {
|
||||
|
||||
// SetMenu sets the initial menu for the application
|
||||
void SetMenu(struct Application *app, const char *menuAsJSON) {
|
||||
app->menuAsJSON = menuAsJSON;
|
||||
app->applicationMenu = NewApplicationMenu(menuAsJSON);
|
||||
}
|
||||
|
||||
@@ -1514,9 +1388,6 @@ void createDelegate(struct Application *app) {
|
||||
class_addMethod(delegateClass, s("applicationWillFinishLaunching:"), (IMP) willFinishLaunching, "v@:@");
|
||||
|
||||
// Menu Callbacks
|
||||
class_addMethod(delegateClass, s("menuCallbackForApplicationMenu:"), (IMP)menuItemPressedForApplicationMenu, "v@:@");
|
||||
class_addMethod(delegateClass, s("checkboxMenuCallbackForApplicationMenu:"), (IMP) checkboxMenuItemPressedForApplicationMenu, "v@:@");
|
||||
class_addMethod(delegateClass, s("radioMenuCallbackForApplicationMenu:"), (IMP) radioMenuItemPressedForApplicationMenu, "v@:@");
|
||||
class_addMethod(delegateClass, s("menuCallbackForTrayMenu:"), (IMP)menuItemPressedForTrayMenu, "v@:@");
|
||||
class_addMethod(delegateClass, s("checkboxMenuCallbackForTrayMenu:"), (IMP) checkboxMenuItemPressedForTrayMenu, "v@:@");
|
||||
class_addMethod(delegateClass, s("radioMenuCallbackForTrayMenu:"), (IMP) radioMenuItemPressedForTrayMenu, "v@:@");
|
||||
@@ -1525,7 +1396,7 @@ void createDelegate(struct Application *app) {
|
||||
class_addMethod(delegateClass, s("radioMenuCallbackForContextMenus:"), (IMP) radioMenuItemPressedForContextMenus, "v@:@");
|
||||
|
||||
// Refactoring menu handling
|
||||
class_addMethod(delegateClass, s("textMenuItemCallback:"), (IMP)textMenuItemCallback, "v@:@");
|
||||
class_addMethod(delegateClass, s("menuItemCallback:"), (IMP)menuItemCallback, "v@:@");
|
||||
|
||||
|
||||
// Script handler
|
||||
@@ -1855,7 +1726,7 @@ void parseMenu(struct Application *app, id parentMenu, JsonNode *menu, struct ha
|
||||
JsonNode *items = json_find_member(menu, "Items");
|
||||
if( items == NULL ) {
|
||||
// Parse error!
|
||||
Fatal(app, "Unable to find Items:", app->menuAsJSON);
|
||||
Fatal(app, "Unable to find Items in Menu");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1916,68 +1787,15 @@ struct hashmap_s *radioGroupMap) {
|
||||
|
||||
}
|
||||
|
||||
void parseMenuData(struct Application *app) {
|
||||
|
||||
// Allocate the hashmaps we need
|
||||
allocateMenuHashMaps(app);
|
||||
|
||||
// Create a new menu bar
|
||||
id menubar = createMenu(str(""));
|
||||
|
||||
// Parse the processed menu json
|
||||
app->processedMenu = json_decode(app->menuAsJSON);
|
||||
|
||||
if( app->processedMenu == NULL ) {
|
||||
// Parse error!
|
||||
Fatal(app, "Unable to parse Menu JSON: %s", app->menuAsJSON);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Pull out the Menu
|
||||
JsonNode *menuData = json_find_member(app->processedMenu, "Menu");
|
||||
if( menuData == NULL ) {
|
||||
// Parse error!
|
||||
Fatal(app, "Unable to find Menu data: %s", app->processedMenu);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
parseMenu(app, menubar, menuData, &menuItemMapForApplicationMenu,
|
||||
"checkboxMenuCallbackForApplicationMenu:", "radioMenuCallbackForApplicationMenu:", "menuCallbackForApplicationMenu:");
|
||||
|
||||
// Create the radiogroup cache
|
||||
JsonNode *radioGroups = json_find_member(app->processedMenu, "RadioGroups");
|
||||
if( radioGroups == NULL ) {
|
||||
// Parse error!
|
||||
Fatal(app, "Unable to find RadioGroups data: %s", app->processedMenu);
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate radio groups
|
||||
JsonNode *radioGroup;
|
||||
json_foreach(radioGroup, radioGroups) {
|
||||
// Get item label
|
||||
processRadioGroup(radioGroup, &menuItemMapForApplicationMenu, &radioGroupMapForApplicationMenu);
|
||||
}
|
||||
|
||||
// Apply the menu bar
|
||||
msg(msg(c("NSApplication"), s("sharedApplication")), s("setMainMenu:"), menubar);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// UpdateMenu replaces the current menu with the given one
|
||||
void UpdateMenu(struct Application *app, const char *menuAsJSON) {
|
||||
Debug(app, "Menu is now: %s", menuAsJSON);
|
||||
ON_MAIN_THREAD (
|
||||
|
||||
// Free up memory
|
||||
destroyMenu(app);
|
||||
|
||||
// Set the menu JSON
|
||||
app->menuAsJSON = menuAsJSON;
|
||||
parseMenuData(app);
|
||||
DeleteMenu(app->applicationMenu);
|
||||
Menu* newMenu = NewApplicationMenu(menuAsJSON);
|
||||
id menu = GetMenu(newMenu);
|
||||
app->applicationMenu = newMenu;
|
||||
msg(msg(c("NSApplication"), s("sharedApplication")), s("setMainMenu:"), menu);
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2378,11 +2196,6 @@ void Run(struct Application *app, int argc, char **argv) {
|
||||
msg(wkwebview, s("setValue:forKey:"), msg(c("NSNumber"), s("numberWithBool:"), 0), str("drawsBackground"));
|
||||
}
|
||||
|
||||
// If we have a menu, process it
|
||||
// if( app->menuAsJSON != NULL ) {
|
||||
// parseMenuData(app);
|
||||
// }
|
||||
|
||||
// If we have an application menu, process it
|
||||
if( app->applicationMenu != NULL ) {
|
||||
id menu = GetMenu(app->applicationMenu);
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
enum MenuItemType {Text = 0, Checkbox = 1, Radio = 2};
|
||||
enum MenuType {ApplicationMenu = 0};
|
||||
|
||||
extern void messageFromWindowCallback(const char *);
|
||||
|
||||
typedef struct {
|
||||
@@ -27,14 +30,13 @@ typedef struct {
|
||||
// The NSMenu for this menu
|
||||
id menu;
|
||||
|
||||
// The names of the menu callbacks
|
||||
SEL textMenuCallbackName;
|
||||
SEL checkboxMenuCallbackName;
|
||||
SEL radioMenuCallbackName;
|
||||
|
||||
// The commands for the menu callbacks
|
||||
const char *callbackCommand;
|
||||
|
||||
// This indicates if we are an Application Menu, tray menu or context menu
|
||||
enum MenuType menuType;
|
||||
|
||||
|
||||
} Menu;
|
||||
|
||||
// NewMenu creates a new Menu struct, saving the given menu structure as JSON
|
||||
@@ -48,14 +50,6 @@ Menu* NewMenu(const char *menuAsJSON) {
|
||||
// No title by default
|
||||
result->title = "";
|
||||
|
||||
// No callbacks by default
|
||||
result->textMenuCallbackName = NULL;
|
||||
result->checkboxMenuCallbackName = NULL;
|
||||
result->radioMenuCallbackName = NULL;
|
||||
|
||||
// Callback Commands
|
||||
result->callbackCommand = "";
|
||||
|
||||
// Initialise menuCallbackDataCache
|
||||
vec_init(&result->callbackDataCache);
|
||||
|
||||
@@ -73,10 +67,7 @@ Menu* NewMenu(const char *menuAsJSON) {
|
||||
|
||||
Menu* NewApplicationMenu(const char *menuAsJSON) {
|
||||
Menu *result = NewMenu(menuAsJSON);
|
||||
result->textMenuCallbackName = s("textMenuItemCallback:");
|
||||
result->checkboxMenuCallbackName = s("checkboxMenuCallbackForApplicationMenu:");
|
||||
result->radioMenuCallbackName = s("radioMenuCallbackForApplicationMenu:");
|
||||
result->callbackCommand = "MC";
|
||||
result->menuType = ApplicationMenu;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -84,15 +75,17 @@ typedef struct {
|
||||
id menuItem;
|
||||
Menu *menu;
|
||||
const char *menuID;
|
||||
enum MenuItemType menuItemType;
|
||||
} MenuItemCallbackData;
|
||||
|
||||
|
||||
MenuItemCallbackData* CreateMenuItemCallbackData(Menu *menu, id menuItem, const char *menuID) {
|
||||
MenuItemCallbackData* CreateMenuItemCallbackData(Menu *menu, id menuItem, const char *menuID, enum MenuItemType menuItemType) {
|
||||
MenuItemCallbackData* result = malloc(sizeof(MenuItemCallbackData));
|
||||
|
||||
result->menu = menu;
|
||||
result->menuID = menuID;
|
||||
result->menuItem = menuItem;
|
||||
result->menuItemType = menuItemType;
|
||||
|
||||
// Store reference to this so we can destroy later
|
||||
vec_push(&menu->callbackDataCache, result);
|
||||
@@ -100,6 +93,8 @@ MenuItemCallbackData* CreateMenuItemCallbackData(Menu *menu, id menuItem, const
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DeleteMenu(Menu *menu) {
|
||||
|
||||
// Free menu item hashmap
|
||||
@@ -121,15 +116,79 @@ void DeleteMenu(Menu *menu) {
|
||||
// Release the vector memory
|
||||
vec_deinit(&menu->callbackDataCache);
|
||||
|
||||
msg(menu->menu, s("release"));
|
||||
|
||||
free(menu);
|
||||
}
|
||||
|
||||
const char* createTextMenuMessage(MenuItemCallbackData *callbackData) {
|
||||
|
||||
switch( callbackData->menu->menuType ) {
|
||||
case ApplicationMenu:
|
||||
return concat("MC", callbackData->menuID);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* createCheckBoxMenuMessage(MenuItemCallbackData *callbackData) {
|
||||
|
||||
switch( callbackData->menu->menuType ) {
|
||||
case ApplicationMenu:
|
||||
return concat("MC", callbackData->menuID);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* createRadioMenuMessage(MenuItemCallbackData *callbackData) {
|
||||
|
||||
switch( callbackData->menu->menuType ) {
|
||||
case ApplicationMenu:
|
||||
return concat("MC", callbackData->menuID);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Callback for text menu items
|
||||
void textMenuItemCallback(id self, SEL cmd, id sender) {
|
||||
void menuItemCallback(id self, SEL cmd, id sender) {
|
||||
MenuItemCallbackData *callbackData = (MenuItemCallbackData *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||
const char *message;
|
||||
|
||||
// Update checkbox / radio item
|
||||
if( callbackData->menuItemType == Checkbox) {
|
||||
// Toggle state
|
||||
bool state = msg(callbackData->menuItem, s("state"));
|
||||
msg(callbackData->menuItem, s("setState:"), (state? NSControlStateValueOff : NSControlStateValueOn));
|
||||
} else if( callbackData->menuItemType == Radio ) {
|
||||
// Check the menu items' current state
|
||||
bool selected = msg(callbackData->menuItem, s("state"));
|
||||
|
||||
// If it's already selected, exit early
|
||||
if (selected) return;
|
||||
|
||||
// Get this item's radio group members and turn them off
|
||||
id *members = (id*)hashmap_get(&(callbackData->menu->radioGroupMap), (char*)callbackData->menuID, strlen(callbackData->menuID));
|
||||
|
||||
// Uncheck all members of the group
|
||||
id thisMember = members[0];
|
||||
int count = 0;
|
||||
while(thisMember != NULL) {
|
||||
msg(thisMember, s("setState:"), NSControlStateValueOff);
|
||||
count = count + 1;
|
||||
thisMember = members[count];
|
||||
}
|
||||
|
||||
// check the selected menu item
|
||||
msg(callbackData->menuItem, s("setState:"), NSControlStateValueOn);
|
||||
}
|
||||
|
||||
// Generate message to send to backend
|
||||
if( callbackData->menu->menuType == ApplicationMenu ) {
|
||||
message = concat("MC", callbackData->menuID);
|
||||
}
|
||||
|
||||
// TODO: Add other menu types here!
|
||||
|
||||
// Notify the backend
|
||||
const char *message = concat(callbackData->menu->callbackCommand, callbackData->menuID);
|
||||
messageFromWindowCallback(message);
|
||||
MEMFREE(message);
|
||||
}
|
||||
@@ -497,12 +556,15 @@ id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char
|
||||
// Store the item in the menu item map
|
||||
hashmap_put(&menu->menuItemMap, (char*)menuid, strlen(menuid), item);
|
||||
|
||||
id wrappedId = msg(c("NSValue"), s("valueWithPointer:"), menuid);
|
||||
// Create a MenuItemCallbackData
|
||||
MenuItemCallbackData *callback = CreateMenuItemCallbackData(menu, item, menuid, Radio);
|
||||
|
||||
id wrappedId = msg(c("NSValue"), s("valueWithPointer:"), callback);
|
||||
msg(item, s("setRepresentedObject:"), wrappedId);
|
||||
|
||||
id key = processAcceleratorKey(acceleratorkey);
|
||||
|
||||
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title), menu->radioMenuCallbackName, key);
|
||||
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title), s("menuItemCallback:"), key);
|
||||
|
||||
msg(item, s("setEnabled:"), !disabled);
|
||||
msg(item, s("autorelease"));
|
||||
@@ -514,14 +576,18 @@ id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char
|
||||
}
|
||||
|
||||
id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key) {
|
||||
|
||||
id item = ALLOC("NSMenuItem");
|
||||
|
||||
// Store the item in the menu item map
|
||||
hashmap_put(&menu->menuItemMap, (char*)menuid, strlen(menuid), item);
|
||||
|
||||
id wrappedId = msg(c("NSValue"), s("valueWithPointer:"), menuid);
|
||||
// Create a MenuItemCallbackData
|
||||
MenuItemCallbackData *callback = CreateMenuItemCallbackData(menu, item, menuid, Checkbox);
|
||||
|
||||
id wrappedId = msg(c("NSValue"), s("valueWithPointer:"), callback);
|
||||
msg(item, s("setRepresentedObject:"), wrappedId);
|
||||
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title), menu->checkboxMenuCallbackName, str(key));
|
||||
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title), s("menuItemCallback:"), str(key));
|
||||
msg(item, s("setEnabled:"), !disabled);
|
||||
msg(item, s("autorelease"));
|
||||
msg(item, s("setState:"), (checked ? NSControlStateValueOn : NSControlStateValueOff));
|
||||
@@ -533,14 +599,14 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char
|
||||
id item = ALLOC("NSMenuItem");
|
||||
|
||||
// Create a MenuItemCallbackData
|
||||
MenuItemCallbackData *callback = CreateMenuItemCallbackData(menu, item, menuid);
|
||||
MenuItemCallbackData *callback = CreateMenuItemCallbackData(menu, item, menuid, Text);
|
||||
|
||||
id wrappedId = msg(c("NSValue"), s("valueWithPointer:"), callback);
|
||||
msg(item, s("setRepresentedObject:"), wrappedId);
|
||||
|
||||
id key = processAcceleratorKey(acceleratorkey);
|
||||
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title),
|
||||
menu->textMenuCallbackName, key);
|
||||
s("menuItemCallback:"), key);
|
||||
|
||||
msg(item, s("setEnabled:"), !disabled);
|
||||
msg(item, s("autorelease"));
|
||||
@@ -557,8 +623,6 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char
|
||||
|
||||
void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
||||
|
||||
printf("Processing Menu Item! menu = %p, parentMenu = %p, item = %p\n", menu, parentMenu, item);
|
||||
|
||||
// Check if this item is hidden and if so, exit early!
|
||||
bool hidden = false;
|
||||
getJSONBool(item, "Hidden", &hidden);
|
||||
@@ -697,6 +761,40 @@ void processMenuData(Menu *menu, JsonNode *menuData) {
|
||||
}
|
||||
}
|
||||
|
||||
void processRadioGroupJSON(Menu *menu, JsonNode *radioGroup) {
|
||||
|
||||
int groupLength;
|
||||
getJSONInt(radioGroup, "Length", &groupLength);
|
||||
JsonNode *members = json_find_member(radioGroup, "Members");
|
||||
JsonNode *member;
|
||||
|
||||
// Allocate array
|
||||
size_t arrayLength = sizeof(id)*(groupLength+1);
|
||||
id memberList[arrayLength];
|
||||
|
||||
// Build the radio group items
|
||||
int count=0;
|
||||
json_foreach(member, members) {
|
||||
// Get menu by id
|
||||
id menuItem = (id)hashmap_get(&menu->menuItemMap, (char*)member->string_, strlen(member->string_));
|
||||
// Save Member
|
||||
memberList[count] = menuItem;
|
||||
count = count + 1;
|
||||
}
|
||||
// Null terminate array
|
||||
memberList[groupLength] = 0;
|
||||
|
||||
// Store the members
|
||||
json_foreach(member, members) {
|
||||
// Copy the memberList
|
||||
char *newMemberList = (char *)malloc(arrayLength);
|
||||
memcpy(newMemberList, memberList, arrayLength);
|
||||
// add group to each member of group
|
||||
hashmap_put(&menu->radioGroupMap, member->string_, strlen(member->string_), newMemberList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
id GetMenu(Menu *menu) {
|
||||
|
||||
menu->menu = createMenu(str(""));
|
||||
@@ -720,6 +818,20 @@ id GetMenu(Menu *menu) {
|
||||
// Save the reference so we can delete it later
|
||||
menu->processedMenu = processedMenu;
|
||||
|
||||
// Create the radiogroup cache
|
||||
JsonNode *radioGroups = json_find_member(menu->processedMenu, "RadioGroups");
|
||||
if( radioGroups == NULL ) {
|
||||
// Parse error!
|
||||
ABORT("Unable to find RadioGroups data: %s", menu->processedMenu);
|
||||
}
|
||||
|
||||
// Iterate radio groups
|
||||
JsonNode *radioGroup;
|
||||
json_foreach(radioGroup, radioGroups) {
|
||||
// Get item label
|
||||
processRadioGroupJSON(menu, radioGroup);
|
||||
}
|
||||
|
||||
return menu->menu;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user