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