1 #include "FGCocoaMenuBar.hxx"
3 #include <Cocoa/Cocoa.h>
5 #include <boost/foreach.hpp>
7 #include <simgear/props/props.hxx>
8 #include <simgear/props/props_io.hxx>
9 #include <simgear/debug/logstream.hxx>
10 #include <simgear/structure/SGBinding.hxx>
12 #include <Main/fg_props.hxx>
20 typedef std::map<NSMenuItem*, SGBindingList> MenuItemBindings;
22 @class CocoaMenuDelegate;
24 class FGCocoaMenuBar::CocoaMenuBarPrivate
27 CocoaMenuBarPrivate();
28 ~CocoaMenuBarPrivate();
30 bool labelIsSeparator(const std::string& s) const;
31 void menuFromProps(NSMenu* menu, SGPropertyNode* menuNode);
33 void fireBindingsForItem(NSMenuItem* item);
36 CocoaMenuDelegate* delegate;
38 MenuItemBindings itemBindings;
42 @interface CocoaMenuDelegate : NSObject <NSMenuDelegate> {
44 FGCocoaMenuBar::CocoaMenuBarPrivate* peer;
47 @property (nonatomic, assign) FGCocoaMenuBar::CocoaMenuBarPrivate* peer;
50 @implementation CocoaMenuDelegate
54 - (void) itemAction:(id) sender
56 peer->fireBindingsForItem((NSMenuItem*) sender);
61 static NSString* stdStringToCocoa(const string& s)
63 return [NSString stringWithUTF8String:s.c_str()];
66 class EnabledListener : public SGPropertyChangeListener
69 EnabledListener(NSMenuItem* i) :
74 virtual void valueChanged(SGPropertyNode *node)
76 BOOL b = node->getBoolValue();
86 FGCocoaMenuBar::CocoaMenuBarPrivate::CocoaMenuBarPrivate()
88 delegate = [[CocoaMenuDelegate alloc] init];
92 FGCocoaMenuBar::CocoaMenuBarPrivate::~CocoaMenuBarPrivate()
97 bool FGCocoaMenuBar::CocoaMenuBarPrivate::labelIsSeparator(const std::string& s) const
99 for (unsigned int i=0; i<s.size(); ++i) {
108 void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGPropertyNode* menuNode)
111 BOOST_FOREACH(SGPropertyNode_ptr n, menuNode->getChildren("item")) {
112 if (!n->hasValue("enabled")) {
113 n->setBoolValue("enabled", true);
116 string l = n->getStringValue("label");
117 string::size_type pos = l.find("(");
118 if (pos != string::npos) {
119 l = l.substr(0, pos);
122 NSString* label = stdStringToCocoa(l);
123 NSString* shortcut = @"";
125 if (index >= [menu numberOfItems]) {
126 if (labelIsSeparator(l)) {
127 item = [NSMenuItem separatorItem];
130 item = [menu addItemWithTitle:label action:nil keyEquivalent:shortcut];
131 n->getNode("enabled")->addChangeListener(new EnabledListener(item));
132 [item setTarget:delegate];
133 [item setAction:@selector(itemAction:)];
136 item = [menu itemAtIndex:index];
137 [item setTitle:label];
140 BOOL enabled = n->getBoolValue("enabled");
141 [item setEnabled:enabled];
144 BOOST_FOREACH(SGPropertyNode_ptr binding, n->getChildren("binding")) {
145 // have to clone the bindings, since SGBinding takes ownership of the
146 // passed in node. Seems like something is wrong here, but following the
147 // PUI code for the moment.
148 SGPropertyNode* cloned(new SGPropertyNode);
149 copyProperties(binding, cloned);
150 bl.push_back(new SGBinding(cloned, globals->get_props()));
153 itemBindings[item] = bl;
155 } // of item iteration
158 void FGCocoaMenuBar::CocoaMenuBarPrivate::fireBindingsForItem(NSMenuItem *item)
160 MenuItemBindings::iterator it = itemBindings.find(item);
161 if (it == itemBindings.end()) {
165 BOOST_FOREACH(SGSharedPtr<SGBinding> b, it->second) {
170 FGCocoaMenuBar::FGCocoaMenuBar() :
171 p(new CocoaMenuBarPrivate)
176 FGCocoaMenuBar::~FGCocoaMenuBar()
181 void FGCocoaMenuBar::init()
183 NSMenu* mainBar = [[NSApplication sharedApplication] mainMenu];
184 SGPropertyNode_ptr props = fgGetNode("/sim/menubar/default",true);
187 NSMenuItem* previousMenu = [mainBar itemAtIndex:0];
188 if (![[previousMenu title] isEqualToString:@"FlightGear"]) {
189 [previousMenu setTitle:@"FlightGear"];
192 BOOST_FOREACH(SGPropertyNode_ptr n, props->getChildren("menu")) {
193 NSString* label = stdStringToCocoa(n->getStringValue("label"));
194 NSMenuItem* item = [mainBar itemWithTitle:label];
198 NSInteger insertIndex = [mainBar indexOfItem:previousMenu] + 1;
199 item = [mainBar insertItemWithTitle:label action:nil keyEquivalent:@"" atIndex:insertIndex];
200 item.tag = index + 400;
202 menu = [[NSMenu alloc] init];
204 [menu setAutoenablesItems:NO];
205 [mainBar setSubmenu:menu forItem:item];
211 // synchronise menu with properties
212 p->menuFromProps(menu, n);
218 bool FGCocoaMenuBar::isVisible() const
223 void FGCocoaMenuBar::show()
228 void FGCocoaMenuBar::hide()