]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/menuitem.mm
follow up parent chain to properly support modal dialog parents, see #15383
[wxWidgets.git] / src / osx / cocoa / menuitem.mm
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/menuitem.mm
3 // Purpose: wxMenuItem implementation
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #include "wx/menuitem.h"
14 #include "wx/stockitem.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/app.h"
18 #include "wx/log.h"
19 #include "wx/menu.h"
20 #endif // WX_PRECOMP
21
22 #include "wx/osx/private.h"
23
24 // a mapping from wx ids to standard osx actions in order to support the native menu item handling
25 // if a new mapping is added, make sure the wxNonOwnedWindowController has a handler for this action as well
26
27 struct Mapping
28 {
29 int menuid;
30 SEL action;
31 };
32
33 Mapping sActionToWXMapping[] =
34 {
35 // as we don't have NSUndoManager support we must not use the native actions
36 #if 0
37 { wxID_UNDO, @selector(undo:) },
38 { wxID_REDO, @selector(redo:) },
39 #endif
40 { wxID_CUT, @selector(cut:) },
41 { wxID_COPY, @selector(copy:) },
42 { wxID_PASTE, @selector(paste:) },
43 { wxID_CLEAR, @selector(delete:) },
44 { wxID_SELECTALL, @selector(selectAll:) },
45 { 0, NULL }
46 };
47
48 int wxOSXGetIdFromSelector(SEL action )
49 {
50 int i = 0 ;
51 while ( sActionToWXMapping[i].action != nil )
52 {
53 if ( sActionToWXMapping[i].action == action )
54 return sActionToWXMapping[i].menuid;
55 ++i;
56 }
57
58 return 0;
59 }
60
61 SEL wxOSXGetSelectorFromID(int menuId )
62 {
63 int i = 0 ;
64 while ( sActionToWXMapping[i].action != nil )
65 {
66 if ( sActionToWXMapping[i].menuid == menuId )
67 return sActionToWXMapping[i].action;
68 ++i;
69 }
70
71 return nil;
72 }
73
74
75 @implementation wxNSMenuItem
76
77 - (id) initWithTitle:(NSString *)aString action:(SEL)aSelector keyEquivalent:(NSString *)charCode
78 {
79 self = [super initWithTitle:aString action:aSelector keyEquivalent:charCode];
80 return self;
81 }
82
83 - (void) clickedAction: (id) sender
84 {
85 wxUnusedVar(sender);
86 if ( impl )
87 {
88 wxMenuItem* menuitem = impl->GetWXPeer();
89 if ( menuitem->GetMenu()->HandleCommandProcess(menuitem) == false )
90 {
91 }
92 }
93 }
94
95 - (void) setEnabled:(BOOL) flag
96 {
97 [super setEnabled:flag];
98 }
99
100 - (BOOL)validateMenuItem:(NSMenuItem *) menuItem
101 {
102 wxUnusedVar(menuItem);
103 if( impl )
104 {
105 wxMenuItem* wxmenuitem = impl->GetWXPeer();
106 if ( wxmenuitem )
107 {
108 wxmenuitem->GetMenu()->HandleCommandUpdateStatus(wxmenuitem);
109 return wxmenuitem->IsEnabled();
110 }
111 }
112 return YES ;
113 }
114
115 - (void)setImplementation: (wxMenuItemImpl *) theImplementation
116 {
117 impl = theImplementation;
118 }
119
120 - (wxMenuItemImpl*) implementation
121 {
122 return impl;
123 }
124
125 @end
126
127 void wxMacCocoaMenuItemSetAccelerator( NSMenuItem* menuItem, wxAcceleratorEntry* entry )
128 {
129 if ( entry == NULL )
130 {
131 [menuItem setKeyEquivalent:@""];
132 return;
133 }
134
135 unsigned int modifiers = 0 ;
136 int key = entry->GetKeyCode() ;
137 if ( key )
138 {
139 if (entry->GetFlags() & wxACCEL_CTRL)
140 modifiers |= NSCommandKeyMask;
141
142 if (entry->GetFlags() & wxACCEL_RAW_CTRL)
143 modifiers |= NSControlKeyMask;
144
145 if (entry->GetFlags() & wxACCEL_ALT)
146 modifiers |= NSAlternateKeyMask ;
147
148 // this may be ignored later for alpha chars
149
150 if (entry->GetFlags() & wxACCEL_SHIFT)
151 modifiers |= NSShiftKeyMask ;
152
153 unichar shortcut = 0;
154 if ( key >= WXK_F1 && key <= WXK_F15 )
155 {
156 modifiers |= NSFunctionKeyMask ;
157 shortcut = NSF1FunctionKey + ( key - WXK_F1 );
158 }
159 else
160 {
161 switch ( key )
162 {
163 case WXK_CLEAR :
164 modifiers |= NSFunctionKeyMask;
165 shortcut = NSDeleteCharacter ;
166 break ;
167
168 case WXK_PAGEUP :
169 modifiers |= NSFunctionKeyMask;
170 shortcut = NSPageUpFunctionKey ;
171 break ;
172
173 case WXK_PAGEDOWN :
174 modifiers |= NSFunctionKeyMask;
175 shortcut = NSPageDownFunctionKey ;
176 break ;
177
178 case WXK_LEFT :
179 modifiers |= NSNumericPadKeyMask | NSFunctionKeyMask;
180 shortcut = NSLeftArrowFunctionKey ;
181 break ;
182
183 case WXK_UP :
184 modifiers |= NSNumericPadKeyMask | NSFunctionKeyMask;
185 shortcut = NSUpArrowFunctionKey ;
186 break ;
187
188 case WXK_RIGHT :
189 modifiers |= NSNumericPadKeyMask | NSFunctionKeyMask;
190 shortcut = NSRightArrowFunctionKey ;
191 break ;
192
193 case WXK_DOWN :
194 modifiers |= NSNumericPadKeyMask | NSFunctionKeyMask;
195 shortcut = NSDownArrowFunctionKey ;
196 break ;
197
198 case WXK_HOME :
199 modifiers |= NSFunctionKeyMask;
200 shortcut = NSHomeFunctionKey ;
201 break ;
202
203 case WXK_END :
204 modifiers |= NSFunctionKeyMask;
205 shortcut = NSEndFunctionKey ;
206 break ;
207
208 case WXK_NUMPAD_ENTER :
209 shortcut = NSEnterCharacter;
210 break;
211
212 case WXK_BACK :
213 case WXK_RETURN :
214 case WXK_TAB :
215 case WXK_ESCAPE :
216 default :
217 if(entry->GetFlags() & wxACCEL_SHIFT)
218 shortcut = toupper(key);
219 else
220 shortcut = tolower(key);
221 break ;
222 }
223 }
224
225 [menuItem setKeyEquivalent:[NSString stringWithCharacters:&shortcut length:1]];
226 [menuItem setKeyEquivalentModifierMask:modifiers];
227 }
228 }
229
230 @interface NSMenuItem(PossibleMethods)
231 - (void)setHidden:(BOOL)hidden;
232 @end
233
234 class wxMenuItemCocoaImpl : public wxMenuItemImpl
235 {
236 public :
237 wxMenuItemCocoaImpl( wxMenuItem* peer, NSMenuItem* item ) : wxMenuItemImpl(peer), m_osxMenuItem(item)
238 {
239 if ( ![m_osxMenuItem isSeparatorItem] )
240 [(wxNSMenuItem*)m_osxMenuItem setImplementation:this];
241 }
242
243 ~wxMenuItemCocoaImpl();
244
245 void SetBitmap( const wxBitmap& bitmap )
246 {
247 [m_osxMenuItem setImage:bitmap.GetNSImage()];
248 }
249
250 void Enable( bool enable )
251 {
252 [m_osxMenuItem setEnabled:enable];
253 }
254
255 void Check( bool check )
256 {
257 [m_osxMenuItem setState:( check ? NSOnState : NSOffState) ];
258 }
259
260 void Hide( bool hide )
261 {
262 // NB: setHidden is new as of 10.5 so we should not call it below there
263 if ([m_osxMenuItem respondsToSelector:@selector(setHidden:)])
264 [m_osxMenuItem setHidden:hide ];
265 else
266 wxLogDebug("wxMenuItemCocoaImpl::Hide not yet supported under OS X < 10.5");
267 }
268
269 void SetLabel( const wxString& text, wxAcceleratorEntry *entry )
270 {
271 wxCFStringRef cfText(text);
272 [m_osxMenuItem setTitle:cfText.AsNSString()];
273
274 wxMacCocoaMenuItemSetAccelerator( m_osxMenuItem, entry );
275 }
276
277 bool DoDefault();
278
279 void * GetHMenuItem() { return m_osxMenuItem; }
280
281 protected :
282 NSMenuItem* m_osxMenuItem ;
283 } ;
284
285 wxMenuItemCocoaImpl::~wxMenuItemCocoaImpl()
286 {
287 if ( ![m_osxMenuItem isSeparatorItem] )
288 [(wxNSMenuItem*)m_osxMenuItem setImplementation:nil];
289 [m_osxMenuItem release];
290 }
291
292 bool wxMenuItemCocoaImpl::DoDefault()
293 {
294 bool handled=false;
295 int menuid = m_peer->GetId();
296
297 NSApplication *theNSApplication = [NSApplication sharedApplication];
298 if (menuid == wxID_OSX_HIDE)
299 {
300 [theNSApplication hide:nil];
301 handled=true;
302 }
303 else if (menuid == wxID_OSX_HIDEOTHERS)
304 {
305 [theNSApplication hideOtherApplications:nil];
306 handled=true;
307 }
308 else if (menuid == wxID_OSX_SHOWALL)
309 {
310 [theNSApplication unhideAllApplications:nil];
311 handled=true;
312 }
313 else if (menuid == wxApp::s_macExitMenuItemId)
314 {
315 wxTheApp->ExitMainLoop();
316 }
317 return handled;
318 }
319
320 wxMenuItemImpl* wxMenuItemImpl::Create( wxMenuItem* peer, wxMenu *pParentMenu,
321 int menuid,
322 const wxString& text,
323 wxAcceleratorEntry *entry,
324 const wxString& WXUNUSED(strHelp),
325 wxItemKind kind,
326 wxMenu *pSubMenu )
327 {
328 wxMenuItemImpl* c = NULL;
329 NSMenuItem* item = nil;
330
331 if ( kind == wxITEM_SEPARATOR )
332 {
333 item = [[NSMenuItem separatorItem] retain];
334 }
335 else
336 {
337 wxCFStringRef cfText(text);
338 SEL selector = nil;
339 bool targetSelf = false;
340 if ( (pParentMenu == NULL || !pParentMenu->GetNoEventsMode()) && pSubMenu == NULL )
341 {
342 selector = wxOSXGetSelectorFromID(menuid);
343
344 if ( selector == nil )
345 {
346 selector = @selector(clickedAction:);
347 targetSelf = true;
348 }
349 }
350
351 wxNSMenuItem* menuitem = [ [ wxNSMenuItem alloc ] initWithTitle:cfText.AsNSString() action:selector keyEquivalent:@""];
352 if ( targetSelf )
353 [menuitem setTarget:menuitem];
354
355 if ( pSubMenu )
356 {
357 pSubMenu->GetPeer()->SetTitle( text );
358 [menuitem setSubmenu:pSubMenu->GetHMenu()];
359 }
360 else
361 {
362 wxMacCocoaMenuItemSetAccelerator( menuitem, entry );
363 }
364 item = menuitem;
365 }
366 c = new wxMenuItemCocoaImpl( peer, item );
367 return c;
368 }