mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
Use menu descriptors instead of tags to locate menu items
This commit is contained in:
@@ -57,6 +57,7 @@
|
||||
- (NSConnection *)connection;
|
||||
- (NSDictionary *)actionDict;
|
||||
|
||||
- (void)queueMessage:(int)msgid properties:(NSDictionary *)props;
|
||||
- (BOOL)checkin;
|
||||
- (BOOL)openVimWindow;
|
||||
- (void)clearAll;
|
||||
@@ -84,15 +85,6 @@
|
||||
saving:(int)saving;
|
||||
- (int)presentDialogWithType:(int)type title:(char *)title message:(char *)msg
|
||||
buttons:(char *)btns textField:(char *)txtfield;
|
||||
- (void)addMenuWithTag:(int)tag parent:(int)parentTag name:(char *)name
|
||||
atIndex:(int)index;
|
||||
- (void)addMenuItemWithTag:(int)tag parent:(int)parentTag name:(char *)name
|
||||
tip:(char *)tip icon:(char *)icon
|
||||
keyEquivalent:(int)key modifiers:(int)mods
|
||||
action:(char *)action isAlternate:(int)isAlt
|
||||
atIndex:(int)index;
|
||||
- (void)removeMenuItemWithTag:(int)tag;
|
||||
- (void)enableMenuItemWithTag:(int)tag state:(int)enabled;
|
||||
- (void)showPopupMenuWithName:(char *)name atMouseLocation:(BOOL)mouse;
|
||||
- (void)showToolbar:(int)enable flags:(int)flags;
|
||||
- (void)createScrollbarWithIdentifier:(long)ident type:(int)type;
|
||||
|
||||
+16
-163
@@ -51,10 +51,12 @@ static unsigned MMServerMax = 1000;
|
||||
|
||||
// TODO: Move to separate file.
|
||||
static int eventModifierFlagsToVimModMask(int modifierFlags);
|
||||
static int vimModMaskToEventModifierFlags(int mods);
|
||||
static int eventModifierFlagsToVimMouseModMask(int modifierFlags);
|
||||
static int eventButtonNumberToVimMouseButton(int buttonNumber);
|
||||
static int specialKeyToNSKey(int key);
|
||||
|
||||
// In gui_macvim.m
|
||||
vimmenu_T *menu_for_descriptor(NSArray *desc);
|
||||
|
||||
|
||||
enum {
|
||||
MMBlinkStateNone = 0,
|
||||
@@ -76,6 +78,7 @@ static NSString *MMSymlinkWarningString =
|
||||
|
||||
|
||||
|
||||
|
||||
@interface MMBackend (Private)
|
||||
- (void)queueVimStateMessage;
|
||||
- (void)processInputQueue;
|
||||
@@ -226,6 +229,11 @@ static NSString *MMSymlinkWarningString =
|
||||
return actionDict;
|
||||
}
|
||||
|
||||
- (void)queueMessage:(int)msgid properties:(NSDictionary *)props
|
||||
{
|
||||
[self queueMessage:msgid data:[props dictionaryAsData]];
|
||||
}
|
||||
|
||||
- (BOOL)checkin
|
||||
{
|
||||
if (![self connection]) {
|
||||
@@ -740,78 +748,6 @@ static NSString *MMSymlinkWarningString =
|
||||
return retval;
|
||||
}
|
||||
|
||||
- (void)addMenuWithTag:(int)tag parent:(int)parentTag name:(char *)name
|
||||
atIndex:(int)index
|
||||
{
|
||||
//NSLog(@"addMenuWithTag:%d parent:%d name:%s atIndex:%d", tag, parentTag,
|
||||
// name, index);
|
||||
|
||||
int namelen = name ? strlen(name) : 0;
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
|
||||
[data appendBytes:&tag length:sizeof(int)];
|
||||
[data appendBytes:&parentTag length:sizeof(int)];
|
||||
[data appendBytes:&namelen length:sizeof(int)];
|
||||
if (namelen > 0) [data appendBytes:name length:namelen];
|
||||
[data appendBytes:&index length:sizeof(int)];
|
||||
|
||||
[self queueMessage:AddMenuMsgID data:data];
|
||||
}
|
||||
|
||||
- (void)addMenuItemWithTag:(int)tag parent:(int)parentTag name:(char *)name
|
||||
tip:(char *)tip icon:(char *)icon
|
||||
keyEquivalent:(int)key modifiers:(int)mods
|
||||
action:(char *)action isAlternate:(int)isAlt
|
||||
atIndex:(int)index
|
||||
{
|
||||
//NSLog(@"addMenuItemWithTag:%d parent:%d name:%s tip:%s atIndex:%d", tag,
|
||||
// parentTag, name, tip, index);
|
||||
|
||||
int namelen = name ? strlen(name) : 0;
|
||||
int tiplen = tip ? strlen(tip) : 0;
|
||||
int iconlen = icon ? strlen(icon) : 0;
|
||||
int eventFlags = vimModMaskToEventModifierFlags(mods);
|
||||
int actionlen = action ? strlen(action) : 0;
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
|
||||
key = specialKeyToNSKey(key);
|
||||
|
||||
[data appendBytes:&tag length:sizeof(int)];
|
||||
[data appendBytes:&parentTag length:sizeof(int)];
|
||||
[data appendBytes:&namelen length:sizeof(int)];
|
||||
if (namelen > 0) [data appendBytes:name length:namelen];
|
||||
[data appendBytes:&tiplen length:sizeof(int)];
|
||||
if (tiplen > 0) [data appendBytes:tip length:tiplen];
|
||||
[data appendBytes:&iconlen length:sizeof(int)];
|
||||
if (iconlen > 0) [data appendBytes:icon length:iconlen];
|
||||
[data appendBytes:&actionlen length:sizeof(int)];
|
||||
if (actionlen > 0) [data appendBytes:action length:actionlen];
|
||||
[data appendBytes:&index length:sizeof(int)];
|
||||
[data appendBytes:&key length:sizeof(int)];
|
||||
[data appendBytes:&eventFlags length:sizeof(int)];
|
||||
[data appendBytes:&isAlt length:sizeof(int)];
|
||||
|
||||
[self queueMessage:AddMenuItemMsgID data:data];
|
||||
}
|
||||
|
||||
- (void)removeMenuItemWithTag:(int)tag
|
||||
{
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
[data appendBytes:&tag length:sizeof(int)];
|
||||
|
||||
[self queueMessage:RemoveMenuItemMsgID data:data];
|
||||
}
|
||||
|
||||
- (void)enableMenuItemWithTag:(int)tag state:(int)enabled
|
||||
{
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
|
||||
[data appendBytes:&tag length:sizeof(int)];
|
||||
[data appendBytes:&enabled length:sizeof(int)];
|
||||
|
||||
[self queueMessage:EnableMenuItemMsgID data:data];
|
||||
}
|
||||
|
||||
- (void)showPopupMenuWithName:(char *)name atMouseLocation:(BOOL)mouse
|
||||
{
|
||||
int len = strlen(name);
|
||||
@@ -1659,14 +1595,12 @@ static NSString *MMSymlinkWarningString =
|
||||
//NSLog(@"[VimTask] Resizing shell to %dx%d.", cols, rows);
|
||||
gui_resize_shell(cols, rows);
|
||||
} else if (ExecuteMenuMsgID == msgid) {
|
||||
if (!data) return;
|
||||
const void *bytes = [data bytes];
|
||||
int tag = *((int*)bytes); bytes += sizeof(int);
|
||||
|
||||
vimmenu_T *menu = (vimmenu_T*)tag;
|
||||
// TODO! Make sure 'menu' is a valid menu pointer!
|
||||
if (menu) {
|
||||
gui_menu_cb(menu);
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithData:data];
|
||||
if (attrs) {
|
||||
NSArray *desc = [attrs objectForKey:@"descriptor"];
|
||||
vimmenu_T *menu = menu_for_descriptor(desc);
|
||||
if (menu)
|
||||
gui_menu_cb(menu);
|
||||
}
|
||||
} else if (ToggleToolbarMsgID == msgid) {
|
||||
[self handleToggleToolbar];
|
||||
@@ -2475,22 +2409,6 @@ static int eventModifierFlagsToVimModMask(int modifierFlags)
|
||||
return modMask;
|
||||
}
|
||||
|
||||
static int vimModMaskToEventModifierFlags(int mods)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (mods & MOD_MASK_SHIFT)
|
||||
flags |= NSShiftKeyMask;
|
||||
if (mods & MOD_MASK_CTRL)
|
||||
flags |= NSControlKeyMask;
|
||||
if (mods & MOD_MASK_ALT)
|
||||
flags |= NSAlternateKeyMask;
|
||||
if (mods & MOD_MASK_CMD)
|
||||
flags |= NSCommandKeyMask;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int eventModifierFlagsToVimMouseModMask(int modifierFlags)
|
||||
{
|
||||
int modMask = 0;
|
||||
@@ -2512,68 +2430,3 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber)
|
||||
return (buttonNumber >= 0 && buttonNumber < 3)
|
||||
? mouseButton[buttonNumber] : -1;
|
||||
}
|
||||
|
||||
static int specialKeyToNSKey(int key)
|
||||
{
|
||||
if (!IS_SPECIAL(key))
|
||||
return key;
|
||||
|
||||
static struct {
|
||||
int special;
|
||||
int nskey;
|
||||
} sp2ns[] = {
|
||||
{ K_UP, NSUpArrowFunctionKey },
|
||||
{ K_DOWN, NSDownArrowFunctionKey },
|
||||
{ K_LEFT, NSLeftArrowFunctionKey },
|
||||
{ K_RIGHT, NSRightArrowFunctionKey },
|
||||
{ K_F1, NSF1FunctionKey },
|
||||
{ K_F2, NSF2FunctionKey },
|
||||
{ K_F3, NSF3FunctionKey },
|
||||
{ K_F4, NSF4FunctionKey },
|
||||
{ K_F5, NSF5FunctionKey },
|
||||
{ K_F6, NSF6FunctionKey },
|
||||
{ K_F7, NSF7FunctionKey },
|
||||
{ K_F8, NSF8FunctionKey },
|
||||
{ K_F9, NSF9FunctionKey },
|
||||
{ K_F10, NSF10FunctionKey },
|
||||
{ K_F11, NSF11FunctionKey },
|
||||
{ K_F12, NSF12FunctionKey },
|
||||
{ K_F13, NSF13FunctionKey },
|
||||
{ K_F14, NSF14FunctionKey },
|
||||
{ K_F15, NSF15FunctionKey },
|
||||
{ K_F16, NSF16FunctionKey },
|
||||
{ K_F17, NSF17FunctionKey },
|
||||
{ K_F18, NSF18FunctionKey },
|
||||
{ K_F19, NSF19FunctionKey },
|
||||
{ K_F20, NSF20FunctionKey },
|
||||
{ K_F21, NSF21FunctionKey },
|
||||
{ K_F22, NSF22FunctionKey },
|
||||
{ K_F23, NSF23FunctionKey },
|
||||
{ K_F24, NSF24FunctionKey },
|
||||
{ K_F25, NSF25FunctionKey },
|
||||
{ K_F26, NSF26FunctionKey },
|
||||
{ K_F27, NSF27FunctionKey },
|
||||
{ K_F28, NSF28FunctionKey },
|
||||
{ K_F29, NSF29FunctionKey },
|
||||
{ K_F30, NSF30FunctionKey },
|
||||
{ K_F31, NSF31FunctionKey },
|
||||
{ K_F32, NSF32FunctionKey },
|
||||
{ K_F33, NSF33FunctionKey },
|
||||
{ K_F34, NSF34FunctionKey },
|
||||
{ K_F35, NSF35FunctionKey },
|
||||
{ K_DEL, NSBackspaceCharacter },
|
||||
{ K_BS, NSDeleteCharacter },
|
||||
{ K_HOME, NSHomeFunctionKey },
|
||||
{ K_END, NSEndFunctionKey },
|
||||
{ K_PAGEUP, NSPageUpFunctionKey },
|
||||
{ K_PAGEDOWN, NSPageDownFunctionKey }
|
||||
};
|
||||
|
||||
int i;
|
||||
for (i = 0; i < sizeof(sp2ns)/sizeof(sp2ns[0]); ++i) {
|
||||
if (sp2ns[i].special == key)
|
||||
return sp2ns[i].nskey;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+194
-21
@@ -64,18 +64,21 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
- (NSMenuItem *)recurseMenuItemForTag:(int)tag rootMenu:(NSMenu *)root;
|
||||
- (NSMenuItem *)menuItemForTag:(int)tag;
|
||||
- (NSMenu *)menuForTag:(int)tag;
|
||||
- (NSMenu *)parentMenuForDescriptor:(NSArray *)desc;
|
||||
- (NSMenu *)topLevelMenuForTitle:(NSString *)title;
|
||||
- (void)addMenuWithTag:(int)tag parent:(int)parentTag title:(NSString *)title
|
||||
atIndex:(int)idx;
|
||||
- (void)addMenuItemWithTag:(int)tag parent:(NSMenu *)parent
|
||||
title:(NSString *)title tip:(NSString *)tip
|
||||
keyEquivalent:(int)key modifiers:(int)mask
|
||||
action:(NSString *)action isAlternate:(int)isAlt
|
||||
atIndex:(int)idx;
|
||||
- (void)addMenuWithDescriptor:(NSArray *)desc atIndex:(int)index;
|
||||
- (void)addMenuItemWithDescriptor:(NSArray *)desc
|
||||
atIndex:(int)index
|
||||
tip:(NSString *)tip
|
||||
icon:(NSString *)icon
|
||||
keyEquivalent:(NSString *)keyEquivalent
|
||||
modifierMask:(int)modifierMask
|
||||
action:(NSString *)action
|
||||
isAlternate:(BOOL)isAlternate;
|
||||
- (NSToolbarItem *)toolbarItemForTag:(int)tag index:(int *)index;
|
||||
- (void)addToolbarItemToDictionaryWithTag:(int)tag label:(NSString *)title
|
||||
- (void)addToolbarItemToDictionaryWithLabel:(NSString *)title
|
||||
toolTip:(NSString *)tip icon:(NSString *)icon;
|
||||
- (void)addToolbarItemWithTag:(int)tag label:(NSString *)label
|
||||
- (void)addToolbarItemWithLabel:(NSString *)label
|
||||
tip:(NSString *)tip icon:(NSString *)icon
|
||||
atIndex:(int)idx;
|
||||
- (void)connectionDidDie:(NSNotification *)notification;
|
||||
@@ -656,6 +659,7 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
|
||||
[string release];
|
||||
} else if (AddMenuMsgID == msgid) {
|
||||
#if 0
|
||||
NSString *title = nil;
|
||||
const void *bytes = [data bytes];
|
||||
int tag = *((int*)bytes); bytes += sizeof(int);
|
||||
@@ -688,7 +692,13 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
}
|
||||
|
||||
[title release];
|
||||
#else
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithData:data];
|
||||
[self addMenuWithDescriptor:[attrs objectForKey:@"descriptor"]
|
||||
atIndex:[[attrs objectForKey:@"index"] intValue]];
|
||||
#endif
|
||||
} else if (AddMenuItemMsgID == msgid) {
|
||||
#if 0
|
||||
NSString *title = nil, *tip = nil, *icon = nil, *action = nil;
|
||||
const void *bytes = [data bytes];
|
||||
int tag = *((int*)bytes); bytes += sizeof(int);
|
||||
@@ -740,7 +750,19 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
[tip release];
|
||||
[icon release];
|
||||
[action release];
|
||||
#else
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithData:data];
|
||||
[self addMenuItemWithDescriptor:[attrs objectForKey:@"descriptor"]
|
||||
atIndex:[[attrs objectForKey:@"index"] intValue]
|
||||
tip:[attrs objectForKey:@"tip"]
|
||||
icon:[attrs objectForKey:@"icon"]
|
||||
keyEquivalent:[attrs objectForKey:@"keyEquivalent"]
|
||||
modifierMask:[[attrs objectForKey:@"modifierMask"] intValue]
|
||||
action:[attrs objectForKey:@"action"]
|
||||
isAlternate:[[attrs objectForKey:@"isAlternate"] boolValue]];
|
||||
#endif
|
||||
} else if (RemoveMenuItemMsgID == msgid) {
|
||||
#if 0
|
||||
const void *bytes = [data bytes];
|
||||
int tag = *((int*)bytes); bytes += sizeof(int);
|
||||
|
||||
@@ -767,7 +789,9 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
|
||||
// Reset cached menu, just to be on the safe side.
|
||||
lastMenuSearched = nil;
|
||||
#endif
|
||||
} else if (EnableMenuItemMsgID == msgid) {
|
||||
#if 0
|
||||
const void *bytes = [data bytes];
|
||||
int tag = *((int*)bytes); bytes += sizeof(int);
|
||||
int state = *((int*)bytes); bytes += sizeof(int);
|
||||
@@ -777,6 +801,7 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
item = [self menuItemForTag:tag];
|
||||
|
||||
[item setEnabled:state];
|
||||
#endif
|
||||
} else if (ShowToolbarMsgID == msgid) {
|
||||
const void *bytes = [data bytes];
|
||||
int enable = *((int*)bytes); bytes += sizeof(int);
|
||||
@@ -1052,6 +1077,36 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
return [[self menuItemForTag:tag] submenu];
|
||||
}
|
||||
|
||||
- (NSMenu *)parentMenuForDescriptor:(NSArray *)desc
|
||||
{
|
||||
if (!(desc && [desc count] > 0)) return nil;
|
||||
|
||||
NSString *rootName = [desc objectAtIndex:0];
|
||||
NSArray *rootItems = [rootName hasPrefix:@"PopUp"] ? popupMenuItems
|
||||
: mainMenuItems;
|
||||
|
||||
NSMenu *menu = nil;
|
||||
int i, count = [rootItems count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSMenuItem *item = [rootItems objectAtIndex:i];
|
||||
if ([[item title] isEqual:rootName]) {
|
||||
menu = [item submenu];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!menu) return nil;
|
||||
|
||||
count = [desc count] - 1;
|
||||
for (i = 1; i < count; ++i) {
|
||||
NSMenuItem *item = [menu itemWithTitle:[desc objectAtIndex:i]];
|
||||
menu = [item submenu];
|
||||
if (!menu) return nil;
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
- (NSMenu *)topLevelMenuForTitle:(NSString *)title
|
||||
{
|
||||
// Search only the top-level menus.
|
||||
@@ -1073,9 +1128,9 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)addMenuWithTag:(int)tag parent:(int)parentTag title:(NSString *)title
|
||||
atIndex:(int)idx
|
||||
- (void)addMenuWithDescriptor:(NSArray *)desc atIndex:(int)idx
|
||||
{
|
||||
#if 0
|
||||
NSMenu *parent = [self menuForTag:parentTag];
|
||||
NSMenuItem *item = [[NSMenuItem alloc] init];
|
||||
NSMenu *menu = [[NSMenu alloc] initWithTitle:title];
|
||||
@@ -1105,14 +1160,73 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
|
||||
[item release];
|
||||
[menu release];
|
||||
#else
|
||||
if (!(desc && [desc count] > 0)) return;
|
||||
|
||||
NSString *rootName = [desc objectAtIndex:0];
|
||||
if ([rootName isEqual:@"ToolBar"]) {
|
||||
// The toolbar only has one menu, we take this as a hint to create a
|
||||
// toolbar, then we return.
|
||||
if (!toolbar) {
|
||||
// NOTE! Each toolbar must have a unique identifier, else each
|
||||
// window will have the same toolbar.
|
||||
NSString *ident = [NSString stringWithFormat:@"%d", (int)self];
|
||||
toolbar = [[NSToolbar alloc] initWithIdentifier:ident];
|
||||
|
||||
[toolbar setShowsBaselineSeparator:NO];
|
||||
[toolbar setDelegate:self];
|
||||
[toolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
|
||||
[toolbar setSizeMode:NSToolbarSizeModeSmall];
|
||||
|
||||
[windowController setToolbar:toolbar];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// This is either a main menu item or a popup menu item.
|
||||
NSString *title = [desc lastObject];
|
||||
NSMenuItem *item = [[NSMenuItem alloc] init];
|
||||
NSMenu *menu = [[NSMenu alloc] initWithTitle:title];
|
||||
|
||||
[menu setAutoenablesItems:NO];
|
||||
[item setTitle:title];
|
||||
[item setSubmenu:menu];
|
||||
|
||||
NSMenu *parent = [self parentMenuForDescriptor:desc];
|
||||
if (parent) {
|
||||
if ([parent numberOfItems] <= idx) {
|
||||
[parent addItem:item];
|
||||
} else {
|
||||
[parent insertItem:item atIndex:idx];
|
||||
}
|
||||
} else {
|
||||
BOOL isPopup = [rootName hasPrefix:@"PopUp"];
|
||||
NSMutableArray *items = isPopup ? popupMenuItems : mainMenuItems;
|
||||
if ([items count] <= idx) {
|
||||
[items addObject:item];
|
||||
} else {
|
||||
[items insertObject:item atIndex:idx];
|
||||
}
|
||||
|
||||
shouldUpdateMainMenu = !isPopup;
|
||||
}
|
||||
|
||||
[item release];
|
||||
[menu release];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)addMenuItemWithTag:(int)tag parent:(NSMenu *)parent
|
||||
title:(NSString *)title tip:(NSString *)tip
|
||||
keyEquivalent:(int)key modifiers:(int)mask
|
||||
action:(NSString *)action isAlternate:(int)isAlt
|
||||
atIndex:(int)idx
|
||||
- (void)addMenuItemWithDescriptor:(NSArray *)desc
|
||||
atIndex:(int)idx
|
||||
tip:(NSString *)tip
|
||||
icon:(NSString *)icon
|
||||
keyEquivalent:(NSString *)keyEquivalent
|
||||
modifierMask:(int)modifierMask
|
||||
action:(NSString *)action
|
||||
isAlternate:(BOOL)isAlternate
|
||||
{
|
||||
#if 0
|
||||
if (parent) {
|
||||
NSMenuItem *item = nil;
|
||||
if (!title || ([title hasPrefix:@"-"] && [title hasSuffix:@"-"])) {
|
||||
@@ -1160,6 +1274,66 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
} else {
|
||||
NSLog(@"WARNING: Menu item '%@' (tag=%d) has no parent.", title, tag);
|
||||
}
|
||||
#else
|
||||
if (!(desc && [desc count] > 1)) return;
|
||||
|
||||
NSString *title = [desc lastObject];
|
||||
NSString *rootName = [desc objectAtIndex:0];
|
||||
|
||||
if ([rootName isEqual:@"ToolBar"]) {
|
||||
if (toolbar)
|
||||
[self addToolbarItemWithLabel:title tip:tip icon:icon atIndex:idx];
|
||||
return;
|
||||
}
|
||||
|
||||
NSMenu *parent = [self parentMenuForDescriptor:desc];
|
||||
if (!parent) {
|
||||
NSLog(@"WARNING: Menu item '%@' has no parent",
|
||||
[desc componentsJoinedByString:@"->"]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSMenuItem *item = nil;
|
||||
if (!title || ([title hasPrefix:@"-"] && [title hasSuffix:@"-"])) {
|
||||
item = [NSMenuItem separatorItem];
|
||||
} else {
|
||||
item = [[[NSMenuItem alloc] init] autorelease];
|
||||
[item setTitle:title];
|
||||
|
||||
if ([action isEqualToString:@"recentFilesDummy:"]) {
|
||||
// Remove the recent files menu item from its current menu
|
||||
// and put it in the current file menu. See -[MMAppController
|
||||
// applicationWillFinishLaunching for more information.
|
||||
//[[recentFilesMenuItem menu] removeItem:recentFilesMenuItem];
|
||||
//item = recentFilesMenuItem;
|
||||
recentFilesDummy = [item retain];
|
||||
} else {
|
||||
// TODO: Check that 'action' is a valid action (nothing will
|
||||
// happen if it isn't, but it would be nice with a warning).
|
||||
if ([action length] > 0)
|
||||
[item setAction:NSSelectorFromString(action)];
|
||||
else
|
||||
[item setAction:@selector(vimMenuItemAction:)];
|
||||
if ([tip length] > 0) [item setToolTip:tip];
|
||||
if ([keyEquivalent length] > 0) {
|
||||
[item setKeyEquivalent:keyEquivalent];
|
||||
[item setKeyEquivalentModifierMask:modifierMask];
|
||||
}
|
||||
[item setAlternate:isAlternate];
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE! The tag is used to idenfity which menu items were
|
||||
// added by Vim (tag != 0) and which were added by the AppKit
|
||||
// (tag == 0).
|
||||
[item setTag:-1];
|
||||
|
||||
if ([parent numberOfItems] <= idx) {
|
||||
[parent addItem:item];
|
||||
} else {
|
||||
[parent insertItem:item atIndex:idx];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSToolbarItem *)toolbarItemForTag:(int)tag index:(int *)index
|
||||
@@ -1179,7 +1353,7 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)addToolbarItemToDictionaryWithTag:(int)tag label:(NSString *)title
|
||||
- (void)addToolbarItemToDictionaryWithLabel:(NSString *)title
|
||||
toolTip:(NSString *)tip icon:(NSString *)icon
|
||||
{
|
||||
// If the item corresponds to a separator then do nothing, since it is
|
||||
@@ -1190,7 +1364,7 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
return;
|
||||
|
||||
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:title];
|
||||
[item setTag:tag];
|
||||
[item setTag:-1];
|
||||
[item setLabel:title];
|
||||
[item setToolTip:tip];
|
||||
[item setAction:@selector(vimMenuItemAction:)];
|
||||
@@ -1213,7 +1387,7 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
[item release];
|
||||
}
|
||||
|
||||
- (void)addToolbarItemWithTag:(int)tag label:(NSString *)label tip:(NSString
|
||||
- (void)addToolbarItemWithLabel:(NSString *)label tip:(NSString
|
||||
*)tip icon:(NSString *)icon atIndex:(int)idx
|
||||
{
|
||||
if (!toolbar) return;
|
||||
@@ -1234,8 +1408,7 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
[self addToolbarItemToDictionaryWithTag:tag label:label toolTip:tip
|
||||
icon:icon];
|
||||
[self addToolbarItemToDictionaryWithLabel:label toolTip:tip icon:icon];
|
||||
|
||||
int maxIdx = [[toolbar items] count];
|
||||
if (maxIdx < idx) idx = maxIdx;
|
||||
|
||||
@@ -614,12 +614,26 @@
|
||||
|
||||
- (IBAction)vimMenuItemAction:(id)sender
|
||||
{
|
||||
int tag = [sender tag];
|
||||
if (![sender isKindOfClass:[NSMenuItem class]]) return;
|
||||
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
[data appendBytes:&tag length:sizeof(int)];
|
||||
// TODO: Make into category on NSMenuItem which returns descriptor.
|
||||
NSMenuItem *item = (NSMenuItem*)sender;
|
||||
NSMutableArray *desc = [NSMutableArray arrayWithObject:[item title]];
|
||||
|
||||
[vimController sendMessage:ExecuteMenuMsgID data:data];
|
||||
NSMenu *menu = [item menu];
|
||||
while (menu) {
|
||||
[desc insertObject:[menu title] atIndex:0];
|
||||
menu = [menu supermenu];
|
||||
}
|
||||
|
||||
// The "MainMenu" item is part of the Cocoa menu and should not be part of
|
||||
// the descriptor.
|
||||
if ([[desc objectAtIndex:0] isEqual:@"MainMenu"])
|
||||
[desc removeObjectAtIndex:0];
|
||||
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithObject:desc
|
||||
forKey:@"descriptor"];
|
||||
[vimController sendMessage:ExecuteMenuMsgID data:[attrs dictionaryAsData]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
+185
-42
@@ -32,6 +32,15 @@ static float MMMaxFontSize = 100.0f;
|
||||
|
||||
|
||||
static NSFont *gui_macvim_font_with_name(char_u *name);
|
||||
static int specialKeyToNSKey(int key);
|
||||
static int vimModMaskToEventModifierFlags(int mods);
|
||||
|
||||
NSArray *descriptor_for_menu(vimmenu_T *menu);
|
||||
vimmenu_T *menu_for_descriptor(NSArray *desc);
|
||||
|
||||
@interface NSString (VimStrings)
|
||||
+ (id)stringWithVimString:(char_u *)s;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -606,6 +615,46 @@ clip_mch_set_selection(VimClipboard *cbd)
|
||||
// -- Menu ------------------------------------------------------------------
|
||||
|
||||
|
||||
NSArray *
|
||||
descriptor_for_menu(vimmenu_T *menu)
|
||||
{
|
||||
if (!menu) return nil;
|
||||
|
||||
NSMutableArray *desc = [NSMutableArray array];
|
||||
while (menu) {
|
||||
NSString *name = [NSString stringWithVimString:menu->dname];
|
||||
[desc insertObject:name atIndex:0];
|
||||
menu = menu->parent;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
vimmenu_T *
|
||||
menu_for_descriptor(NSArray *desc)
|
||||
{
|
||||
if (!(desc && [desc count] > 0)) return NULL;
|
||||
|
||||
vimmenu_T *menu = root_menu;
|
||||
int i, count = [desc count];
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSString *component = [desc objectAtIndex:i];
|
||||
while (menu) {
|
||||
NSString *name = [NSString stringWithVimString:menu->dname];
|
||||
if ([component isEqual:name]) {
|
||||
if (i+1 == count)
|
||||
return menu; // Matched all components, so return menu
|
||||
menu = menu->children;
|
||||
break;
|
||||
}
|
||||
menu = menu->next;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a sub menu to the menu bar.
|
||||
*/
|
||||
@@ -628,9 +677,12 @@ gui_mch_add_menu(vimmenu_T *menu, int idx)
|
||||
dname = CONVERT_TO_UTF8(dname);
|
||||
#endif
|
||||
|
||||
[[MMBackend sharedInstance]
|
||||
addMenuWithTag:(int)menu parent:parent name:(char*)dname
|
||||
atIndex:idx];
|
||||
NSArray *desc = descriptor_for_menu(menu);
|
||||
[[MMBackend sharedInstance] queueMessage:AddMenuMsgID properties:
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
desc, @"descriptor",
|
||||
[NSNumber numberWithInt:idx], @"index",
|
||||
nil]];
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
CONVERT_TO_UTF8_FREE(dname);
|
||||
@@ -649,40 +701,24 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx)
|
||||
char_u *icon = menu->iconfile ? menu->iconfile :
|
||||
menu->iconidx >= 0 ? menu->dname :
|
||||
NULL;
|
||||
//char *name = menu_is_separator(menu->name) ? NULL : (char*)menu->dname;
|
||||
char_u *name = menu->dname;
|
||||
char_u *tip = menu->strings[MENU_INDEX_TIP]
|
||||
? menu->strings[MENU_INDEX_TIP] : menu->actext;
|
||||
char_u *map_str = menu->strings[MENU_INDEX_NORMAL];
|
||||
char_u *mac_action = menu->mac_action;
|
||||
NSArray *desc = descriptor_for_menu(menu);
|
||||
NSString *keyEquivalent = [NSString stringWithFormat:@"%C",
|
||||
specialKeyToNSKey(menu->mac_key)];
|
||||
int modifierMask = vimModMaskToEventModifierFlags(menu->mac_mods);
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
icon = CONVERT_TO_UTF8(icon);
|
||||
name = CONVERT_TO_UTF8(name);
|
||||
tip = CONVERT_TO_UTF8(tip);
|
||||
map_str = CONVERT_TO_UTF8(map_str);
|
||||
mac_action = CONVERT_TO_UTF8(mac_action);
|
||||
#endif
|
||||
|
||||
[[MMBackend sharedInstance]
|
||||
addMenuItemWithTag:(int)menu
|
||||
parent:(int)menu->parent
|
||||
name:(char*)name
|
||||
tip:(char*)tip
|
||||
icon:(char*)icon
|
||||
keyEquivalent:menu->mac_key
|
||||
modifiers:menu->mac_mods
|
||||
action:(char*)mac_action
|
||||
isAlternate:menu->mac_alternate
|
||||
atIndex:idx];
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
CONVERT_TO_UTF8_FREE(icon);
|
||||
CONVERT_TO_UTF8_FREE(name);
|
||||
CONVERT_TO_UTF8_FREE(tip);
|
||||
CONVERT_TO_UTF8_FREE(map_str);
|
||||
CONVERT_TO_UTF8_FREE(mac_action);
|
||||
#endif
|
||||
[[MMBackend sharedInstance] queueMessage:AddMenuItemMsgID properties:
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
desc, @"descriptor",
|
||||
[NSNumber numberWithInt:idx], @"index",
|
||||
[NSString stringWithVimString:tip], @"tip",
|
||||
[NSString stringWithVimString:icon], @"icon",
|
||||
keyEquivalent, @"keyEquivalent",
|
||||
[NSNumber numberWithInt:modifierMask], @"modifierMask",
|
||||
[NSString stringWithVimString:menu->mac_action], @"action",
|
||||
[NSNumber numberWithBool:menu->mac_alternate], @"isAlternate",
|
||||
nil]];
|
||||
}
|
||||
|
||||
|
||||
@@ -692,7 +728,9 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx)
|
||||
void
|
||||
gui_mch_destroy_menu(vimmenu_T *menu)
|
||||
{
|
||||
[[MMBackend sharedInstance] removeMenuItemWithTag:(int)menu];
|
||||
NSArray *desc = descriptor_for_menu(menu);
|
||||
[[MMBackend sharedInstance] queueMessage:RemoveMenuItemMsgID properties:
|
||||
[NSDictionary dictionaryWithObject:desc forKey:@"descriptor"]];
|
||||
}
|
||||
|
||||
|
||||
@@ -705,12 +743,12 @@ gui_mch_menu_grey(vimmenu_T *menu, int grey)
|
||||
/* Only update menu if the 'grey' state has changed to avoid having to pass
|
||||
* lots of unnecessary data to MacVim. (Skipping this test makes MacVim
|
||||
* pause noticably on mode changes. */
|
||||
if (menu->was_grey != grey)
|
||||
{
|
||||
menu->was_grey = grey;
|
||||
[[MMBackend sharedInstance]
|
||||
enableMenuItemWithTag:(int)menu state:!grey];
|
||||
}
|
||||
if (menu->was_grey != grey) return;
|
||||
|
||||
menu->was_grey = grey;
|
||||
[[MMBackend sharedInstance] queueMessage:EnableMenuItemMsgID properties:
|
||||
[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:!grey]
|
||||
forKey:@"enable"]];
|
||||
}
|
||||
|
||||
|
||||
@@ -732,6 +770,7 @@ gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
|
||||
void
|
||||
gui_mch_show_popupmenu(vimmenu_T *menu)
|
||||
{
|
||||
#if 0
|
||||
char_u *name = menu->name;
|
||||
#ifdef FEAT_MBYTE
|
||||
name = CONVERT_TO_UTF8(name);
|
||||
@@ -743,7 +782,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu)
|
||||
#ifdef FEAT_MBYTE
|
||||
CONVERT_TO_UTF8_FREE(name);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -753,6 +792,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu)
|
||||
void
|
||||
gui_make_popup(char_u *path_name, int mouse_pos)
|
||||
{
|
||||
#if 0
|
||||
#ifdef FEAT_MBYTE
|
||||
path_name = CONVERT_TO_UTF8(path_name);
|
||||
#endif
|
||||
@@ -763,6 +803,7 @@ gui_make_popup(char_u *path_name, int mouse_pos)
|
||||
#ifdef FEAT_MBYTE
|
||||
CONVERT_TO_UTF8_FREE(path_name);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1886,3 +1927,105 @@ is_valid_macaction(char_u *action)
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
static int specialKeyToNSKey(int key)
|
||||
{
|
||||
if (!IS_SPECIAL(key))
|
||||
return key;
|
||||
|
||||
static struct {
|
||||
int special;
|
||||
int nskey;
|
||||
} sp2ns[] = {
|
||||
{ K_UP, NSUpArrowFunctionKey },
|
||||
{ K_DOWN, NSDownArrowFunctionKey },
|
||||
{ K_LEFT, NSLeftArrowFunctionKey },
|
||||
{ K_RIGHT, NSRightArrowFunctionKey },
|
||||
{ K_F1, NSF1FunctionKey },
|
||||
{ K_F2, NSF2FunctionKey },
|
||||
{ K_F3, NSF3FunctionKey },
|
||||
{ K_F4, NSF4FunctionKey },
|
||||
{ K_F5, NSF5FunctionKey },
|
||||
{ K_F6, NSF6FunctionKey },
|
||||
{ K_F7, NSF7FunctionKey },
|
||||
{ K_F8, NSF8FunctionKey },
|
||||
{ K_F9, NSF9FunctionKey },
|
||||
{ K_F10, NSF10FunctionKey },
|
||||
{ K_F11, NSF11FunctionKey },
|
||||
{ K_F12, NSF12FunctionKey },
|
||||
{ K_F13, NSF13FunctionKey },
|
||||
{ K_F14, NSF14FunctionKey },
|
||||
{ K_F15, NSF15FunctionKey },
|
||||
{ K_F16, NSF16FunctionKey },
|
||||
{ K_F17, NSF17FunctionKey },
|
||||
{ K_F18, NSF18FunctionKey },
|
||||
{ K_F19, NSF19FunctionKey },
|
||||
{ K_F20, NSF20FunctionKey },
|
||||
{ K_F21, NSF21FunctionKey },
|
||||
{ K_F22, NSF22FunctionKey },
|
||||
{ K_F23, NSF23FunctionKey },
|
||||
{ K_F24, NSF24FunctionKey },
|
||||
{ K_F25, NSF25FunctionKey },
|
||||
{ K_F26, NSF26FunctionKey },
|
||||
{ K_F27, NSF27FunctionKey },
|
||||
{ K_F28, NSF28FunctionKey },
|
||||
{ K_F29, NSF29FunctionKey },
|
||||
{ K_F30, NSF30FunctionKey },
|
||||
{ K_F31, NSF31FunctionKey },
|
||||
{ K_F32, NSF32FunctionKey },
|
||||
{ K_F33, NSF33FunctionKey },
|
||||
{ K_F34, NSF34FunctionKey },
|
||||
{ K_F35, NSF35FunctionKey },
|
||||
{ K_DEL, NSBackspaceCharacter },
|
||||
{ K_BS, NSDeleteCharacter },
|
||||
{ K_HOME, NSHomeFunctionKey },
|
||||
{ K_END, NSEndFunctionKey },
|
||||
{ K_PAGEUP, NSPageUpFunctionKey },
|
||||
{ K_PAGEDOWN, NSPageDownFunctionKey }
|
||||
};
|
||||
|
||||
int i;
|
||||
for (i = 0; i < sizeof(sp2ns)/sizeof(sp2ns[0]); ++i) {
|
||||
if (sp2ns[i].special == key)
|
||||
return sp2ns[i].nskey;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vimModMaskToEventModifierFlags(int mods)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (mods & MOD_MASK_SHIFT)
|
||||
flags |= NSShiftKeyMask;
|
||||
if (mods & MOD_MASK_CTRL)
|
||||
flags |= NSControlKeyMask;
|
||||
if (mods & MOD_MASK_ALT)
|
||||
flags |= NSAlternateKeyMask;
|
||||
if (mods & MOD_MASK_CMD)
|
||||
flags |= NSCommandKeyMask;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation NSString (VimStrings)
|
||||
+ (id)stringWithVimString:(char_u *)s
|
||||
{
|
||||
if (s) {
|
||||
#ifdef FEAT_MBYTE
|
||||
s = CONVERT_TO_UTF8(s);
|
||||
#endif
|
||||
NSString *string = [NSString stringWithUTF8String:(char*)s];
|
||||
#ifdef FEAT_MBYTE
|
||||
CONVERT_TO_UTF8_FREE(s);
|
||||
#endif
|
||||
return string;
|
||||
}
|
||||
|
||||
return [NSString string];
|
||||
}
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user