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