#include <simgear/props/props_io.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGBinding.hxx>
+#include <simgear/misc/strutils.hxx>
#include <Main/fg_props.hxx>
using std::string;
using std::map;
using std::cout;
+using namespace simgear;
typedef std::map<NSMenuItem*, SGBindingList> MenuItemBindings;
CocoaMenuBarPrivate();
~CocoaMenuBarPrivate();
- bool labelIsSeparator(const std::string& s) const;
void menuFromProps(NSMenu* menu, SGPropertyNode* menuNode);
void fireBindingsForItem(NSMenuItem* item);
MenuItemBindings itemBindings;
};
+// prior to the 10.6 SDK, NSMenuDelegate was an informal protocol
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+@protocol NSMenuDelegate <NSObject>
+@end
+#endif
@interface CocoaMenuDelegate : NSObject <NSMenuDelegate> {
@private
return [NSString stringWithUTF8String:s.c_str()];
}
-class EnabledListener : public SGPropertyChangeListener
+static void setFunctionKeyShortcut(NSMenuItem* item, unichar shortcut)
{
-public:
- EnabledListener(NSMenuItem* i) :
- item(i)
- {}
+ unichar ch[1];
+ ch[0] = shortcut;
+ [item setKeyEquivalentModifierMask:NSFunctionKeyMask];
+ [item setKeyEquivalent:[NSString stringWithCharacters:ch length:1]];
+}
+
+static void setItemShortcutFromString(NSMenuItem* item, const string& s)
+{
+ const char* shortcut = "";
- virtual void valueChanged(SGPropertyNode *node)
- {
- BOOL b = node->getBoolValue();
- [item setEnabled:b];
+ bool hasCtrl = strutils::starts_with(s, "Ctrl-");
+ bool hasShift = strutils::starts_with(s, "Shift-");
+ bool hasAlt = strutils::starts_with(s, "Alt-");
+
+ int offset = 0; // character offset from start of string
+ if (hasShift) offset += 6;
+ if (hasCtrl) offset += 5;
+ if (hasAlt) offset += 4;
+
+ shortcut = s.c_str() + offset;
+ if (!strcmp(shortcut, "Esc"))
+ shortcut = "\e";
+
+ if (!strcmp(shortcut, "F11")) {
+ setFunctionKeyShortcut(item, NSF11FunctionKey);
+ return;
}
-private:
- NSMenuItem* item;
-};
-
+ if (!strcmp(shortcut, "F12")) {
+ setFunctionKeyShortcut(item, NSF12FunctionKey);
+ return;
+ }
+
+ [item setKeyEquivalent:[NSString stringWithCString:shortcut encoding:NSUTF8StringEncoding]];
+ NSUInteger modifiers = 0;
+ if (hasCtrl) modifiers |= NSControlKeyMask;
+ if (hasShift) modifiers |= NSShiftKeyMask;
+ if (hasAlt) modifiers |= NSAlternateKeyMask;
+
+ [item setKeyEquivalentModifierMask:modifiers];
+}
+namespace {
+ class CocoaAutoreleasePool
+ {
+ public:
+ CocoaAutoreleasePool()
+ {
+ pool = [[NSAutoreleasePool alloc] init];
+ }
+
+ ~CocoaAutoreleasePool()
+ {
+ [pool release];
+ }
+
+ private:
+ NSAutoreleasePool* pool;
+ };
+
+ class CocoaEnabledListener : public SGPropertyChangeListener
+ {
+ public:
+ CocoaEnabledListener(NSMenuItem* i) :
+ item(i)
+ {}
+
+
+ virtual void valueChanged(SGPropertyNode *node)
+ {
+ CocoaAutoreleasePool pool;
+ BOOL b = node->getBoolValue();
+ [item setEnabled:b];
+ }
+
+ private:
+ NSMenuItem* item;
+ };
+} // of anonymous namespace
FGCocoaMenuBar::CocoaMenuBarPrivate::CocoaMenuBarPrivate()
{
FGCocoaMenuBar::CocoaMenuBarPrivate::~CocoaMenuBarPrivate()
{
+ CocoaAutoreleasePool pool;
[delegate release];
}
-bool FGCocoaMenuBar::CocoaMenuBarPrivate::labelIsSeparator(const std::string& s) const
+static bool labelIsSeparator(NSString* s)
{
- for (unsigned int i=0; i<s.size(); ++i) {
- if (s[i] != '-') {
- return false;
- }
- }
-
- return true;
+ return [s hasPrefix:@"---"];
}
void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGPropertyNode* menuNode)
n->setBoolValue("enabled", true);
}
- string l = n->getStringValue("label");
- string::size_type pos = l.find("(");
- if (pos != string::npos) {
- l = l.substr(0, pos);
- }
+ string l = getLocalizedLabel(n);
+ NSString* label = stdStringToCocoa(strutils::simplify(l));
+ string shortcut = n->getStringValue("key");
- NSString* label = stdStringToCocoa(l);
- NSString* shortcut = @"";
NSMenuItem* item;
if (index >= [menu numberOfItems]) {
- if (labelIsSeparator(l)) {
+ if (labelIsSeparator(label)) {
item = [NSMenuItem separatorItem];
[menu addItem:item];
} else {
- item = [menu addItemWithTitle:label action:nil keyEquivalent:shortcut];
- n->getNode("enabled")->addChangeListener(new EnabledListener(item));
+ item = [menu addItemWithTitle:label action:nil keyEquivalent:@""];
+ if (!shortcut.empty()) {
+ setItemShortcutFromString(item, shortcut);
+ }
+
+ n->getNode("enabled")->addChangeListener(new CocoaEnabledListener(item));
[item setTarget:delegate];
[item setAction:@selector(itemAction:)];
}
void FGCocoaMenuBar::init()
{
+ CocoaAutoreleasePool pool;
+
NSMenu* mainBar = [[NSApplication sharedApplication] mainMenu];
SGPropertyNode_ptr props = fgGetNode("/sim/menubar/default",true);
}
BOOST_FOREACH(SGPropertyNode_ptr n, props->getChildren("menu")) {
- NSString* label = stdStringToCocoa(n->getStringValue("label"));
+ NSString* label = stdStringToCocoa(getLocalizedLabel(n));
NSMenuItem* item = [mainBar itemWithTitle:label];
NSMenu* menu;
p->menuFromProps(menu, n);
++index;
previousMenu = item;
+
+ // track menu enable/disable state
+ if (!n->hasValue("enabled")) {
+ n->setBoolValue("enabled", true);
+ }
+
+ n->getNode("enabled")->addChangeListener(new CocoaEnabledListener(item));
}
}
{
// no-op
}
+
+void cocoaOpenUrl(const std::string& url)
+{
+ CocoaAutoreleasePool pool;
+ NSURL* nsu = [NSURL URLWithString:stdStringToCocoa(url)];
+ [[NSWorkspace sharedWorkspace] openURL:nsu];
+}