]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/menu.cpp
osx new layout
[wxWidgets.git] / src / osx / carbon / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
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 // ============================================================================
13 // headers & declarations
14 // ============================================================================
15
16 // wxWidgets headers
17 // -----------------
18
19 #include "wx/wxprec.h"
20
21 #include "wx/menu.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/log.h"
25 #include "wx/app.h"
26 #include "wx/utils.h"
27 #include "wx/frame.h"
28 #include "wx/menuitem.h"
29 #endif
30
31 #include "wx/osx/private.h"
32 #include "wx/stockitem.h"
33
34 // other standard headers
35 // ----------------------
36 #include <string.h>
37
38 // under carbon there's no such thing as a MenuItemRef, everything is done
39 // on the 'parent' menu via index APIs (first line having index 1 !)
40 // so to make things still work, we store the wxMenuItemImpl instance as a
41 // RefCon at the respective menu line
42
43 class wxMenuItemCarbonImpl : public wxMenuItemImpl
44 {
45 public :
46 wxMenuItemCarbonImpl( wxMenuItem* peer ) : wxMenuItemImpl(peer)
47 {
48 // the parent menu ref is only set, once the item has been attached
49 m_parentMenuRef = NULL;
50 }
51
52 ~wxMenuItemCarbonImpl();
53
54 void SetBitmap( const wxBitmap& bitmap )
55 {
56 MenuItemIndex i = FindMenuItemIndex() ;
57 if ( i > 0 )
58 {
59 if ( bitmap.Ok() )
60 {
61 #if wxUSE_BMPBUTTON
62 ControlButtonContentInfo info ;
63 wxMacCreateBitmapButton( &info , bitmap ) ;
64 if ( info.contentType != kControlNoContent )
65 {
66 if ( info.contentType == kControlContentIconRef )
67 SetMenuItemIconHandle( m_parentMenuRef, i ,
68 kMenuIconRefType , (Handle) info.u.iconRef ) ;
69 else if ( info.contentType == kControlContentCGImageRef )
70 SetMenuItemIconHandle( m_parentMenuRef, i ,
71 kMenuCGImageRefType , (Handle) info.u.imageRef ) ;
72 }
73 wxMacReleaseBitmapButton( &info ) ;
74 #endif
75 }
76 }
77 }
78
79 void Enable( bool enable )
80 {
81 MenuItemIndex i = FindMenuItemIndex() ;
82 if ( i > 0 )
83 {
84
85 if ( GetWXPeer()->GetId() == wxApp::s_macPreferencesMenuItemId)
86 {
87 if ( enable )
88 EnableMenuCommand( NULL , kHICommandPreferences ) ;
89 else
90 DisableMenuCommand( NULL , kHICommandPreferences ) ;
91 }
92 else if ( GetWXPeer()->GetId() == wxApp::s_macExitMenuItemId)
93 {
94 if ( enable )
95 EnableMenuCommand( NULL , kHICommandQuit ) ;
96 else
97 DisableMenuCommand( NULL , kHICommandQuit ) ;
98 }
99
100 if ( enable )
101 EnableMenuItem(m_parentMenuRef , i);
102 else
103 DisableMenuItem(m_parentMenuRef , i);
104
105 if ( GetWXPeer()->IsSubMenu() )
106 {
107 UMAEnableMenuItem( GetWXPeer()->GetSubMenu()->GetHMenu() , 0 , enable ) ;
108 }
109 }
110 }
111
112 void Check( bool check )
113 {
114 MenuItemIndex i = FindMenuItemIndex() ;
115 if ( i > 0 )
116 {
117 if ( check )
118 ::SetItemMark( m_parentMenuRef, i, 0x12 ) ; // checkmark
119 else
120 ::SetItemMark( m_parentMenuRef, i, 0 ) ; // no mark
121 }
122 }
123
124 void Hide( bool hide )
125 {
126 MenuItemIndex i = FindMenuItemIndex() ;
127 if ( i > 0 )
128 {
129 if ( hide )
130 ChangeMenuItemAttributes( m_parentMenuRef, i, kMenuItemAttrHidden, 0 );
131 else
132 ChangeMenuItemAttributes( m_parentMenuRef, i, 0 , kMenuItemAttrHidden );
133 }
134 }
135
136 void SetLabel( const wxString& text, wxAcceleratorEntry *entry )
137 {
138 MenuItemIndex i = FindMenuItemIndex() ;
139 if ( i > 0 )
140 {
141 SetMenuItemTextWithCFString( m_parentMenuRef, i, wxCFStringRef(text));
142 UMASetMenuItemShortcut( m_parentMenuRef, i , entry ) ;
143 }
144 }
145
146 void * GetHMenuItem() { return NULL; }
147
148 // Carbon Only
149
150 void AttachToParent( MenuRef parentMenuRef, MenuItemIndex index )
151 {
152 m_parentMenuRef = parentMenuRef;
153 if ( m_parentMenuRef && index > 0 )
154 SetMenuItemRefCon( m_parentMenuRef, index, (URefCon) this );
155 }
156
157 MenuItemIndex FindMenuItemIndex()
158 {
159 MenuItemIndex hit = 0 ;
160 if ( m_parentMenuRef )
161 {
162 for ( MenuItemIndex i = 1 ; i <= CountMenuItems(m_parentMenuRef) ; ++i )
163 {
164 URefCon storedRef = 0;
165 GetMenuItemRefCon(m_parentMenuRef, i, &storedRef );
166 if ( storedRef == (URefCon) this )
167 {
168 hit = i;
169 break;
170 }
171 }
172 }
173 return hit;
174 }
175 protected :
176 MenuRef m_parentMenuRef;
177 } ;
178
179 //
180 // wxMenuImpl
181 //
182
183 class wxMenuCarbonImpl : public wxMenuImpl
184 {
185 public :
186 wxMenuCarbonImpl( wxMenu* peer , MenuRef menu) : wxMenuImpl(peer), m_osxMenu(menu)
187 {
188 }
189
190 virtual ~wxMenuCarbonImpl();
191
192
193 virtual void InsertOrAppend(wxMenuItem *pItem, size_t pos)
194 {
195 // MacOS counts menu items from 1 and inserts after, therefore having the
196 // same effect as wx 0 based and inserting before, we must correct pos
197 // after however for updates to be correct
198
199 MenuItemIndex index = pos;
200 if ( pos == (size_t) -1 )
201 index = CountMenuItems(m_osxMenu);
202
203 if ( pItem->IsSeparator() )
204 {
205 InsertMenuItemTextWithCFString( m_osxMenu, CFSTR(""), index, kMenuItemAttrSeparator, 0);
206 // now switch to the Carbon 1 based counting
207 index += 1 ;
208 }
209 else
210 {
211 InsertMenuItemTextWithCFString( m_osxMenu, CFSTR("placeholder"), index, 0, 0 );
212
213 // now switch to the Carbon 1 based counting
214 index += 1 ;
215 if ( pItem->IsSubMenu() )
216 {
217 MenuRef submenu = pItem->GetSubMenu()->GetHMenu();
218 SetMenuItemHierarchicalMenu(m_osxMenu, index, submenu);
219 // carbon is using the title of the submenu, eg in the menubar
220 SetMenuTitleWithCFString(submenu, wxCFStringRef(wxStripMenuCodes(pItem->GetLabel())));
221 }
222 else
223 {
224 SetMenuItemCommandID( m_osxMenu, index , wxIdToMacCommand(pItem->GetId()) ) ;
225 }
226 }
227
228 wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
229 impl->AttachToParent( m_osxMenu, index );
230 // only now can all settings be updated correctly
231 pItem->UpdateItemText();
232 pItem->UpdateItemStatus();
233 pItem->UpdateItemBitmap();
234 }
235
236 virtual void Remove( wxMenuItem *pItem )
237 {
238 wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
239 if ( impl )
240 {
241 MenuItemIndex i = impl->FindMenuItemIndex();
242 if ( i > 0 )
243 {
244 DeleteMenuItem(m_osxMenu , i);
245 impl->AttachToParent( NULL, 0 );
246 }
247
248 delete entry;
249 }
250 }
251
252 virtual void MakeRoot()
253 {
254 SetRootMenu( m_osxMenu );
255 }
256
257 virtual void SetTitle( const wxString& text )
258 {
259 SetMenuTitleWithCFString(m_osxMenu, wxCFStringRef(text));
260 }
261
262 WXHMENU GetHMenu() { return m_osxMenu; }
263
264 static wxMenuImpl* Create( wxMenu* peer, const wxString& title );
265 static wxMenuImpl* CreateRootMenu( wxMenu* peer );
266 protected :
267 wxCFRef<MenuRef> m_osxMenu;
268 } ;
269
270 // static const short kwxMacAppleMenuId = 1 ;
271
272 // Find an item given the Macintosh Menu Reference
273
274 WX_DECLARE_HASH_MAP(WXHMENU, wxMenu*, wxPointerHash, wxPointerEqual, MacMenuMap);
275
276 static MacMenuMap wxWinMacMenuList;
277
278 wxMenu *wxFindMenuFromMacMenu(WXHMENU inMenuRef)
279 {
280 MacMenuMap::iterator node = wxWinMacMenuList.find(inMenuRef);
281
282 return (node == wxWinMacMenuList.end()) ? NULL : node->second;
283 }
284
285 void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu) ;
286 void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu)
287 {
288 // adding NULL MenuRef is (first) surely a result of an error and
289 // (secondly) breaks menu command processing
290 wxCHECK_RET( inMenuRef != (WXHMENU) NULL, wxT("attempt to add a NULL MenuRef to menu list") );
291
292 wxWinMacMenuList[inMenuRef] = menu;
293 }
294
295 void wxRemoveMacMenuAssociation(wxMenu *menu) ;
296 void wxRemoveMacMenuAssociation(wxMenu *menu)
297 {
298 // iterate over all the elements in the class
299 MacMenuMap::iterator it;
300 for ( it = wxWinMacMenuList.begin(); it != wxWinMacMenuList.end(); ++it )
301 {
302 if ( it->second == menu )
303 {
304 wxWinMacMenuList.erase(it);
305 break;
306 }
307 }
308 }
309
310 wxMenuCarbonImpl::~wxMenuCarbonImpl()
311 {
312 wxRemoveMacMenuAssociation( GetWXPeer() );
313 }
314
315 wxMenuImpl* wxMenuImpl::Create( wxMenu* peer, const wxString& title )
316 {
317 // create the menu
318 static SInt16 s_macNextMenuId = 3;
319 WXHMENU menu = NULL;
320 CreateNewMenu( s_macNextMenuId++ , 0 , &menu ) ;
321 if ( !menu )
322 {
323 wxLogLastError(wxT("CreateNewMenu failed"));
324 return NULL;
325 }
326
327 wxMenuImpl* c = new wxMenuCarbonImpl( peer, menu );
328 c->SetTitle(title);
329 wxAssociateMenuWithMacMenu( menu , peer ) ;
330 return c;
331 }
332
333 //
334 //
335 //
336
337 wxMenuItemCarbonImpl::~wxMenuItemCarbonImpl()
338 {
339 }
340
341
342 wxMenuItemImpl* wxMenuItemImpl::Create( wxMenuItem* peer,
343 wxMenu * WXUNUSED(pParentMenu),
344 int WXUNUSED(id),
345 const wxString& WXUNUSED(text),
346 wxAcceleratorEntry *WXUNUSED(entry),
347 const wxString& WXUNUSED(strHelp),
348 wxItemKind WXUNUSED(kind),
349 wxMenu *WXUNUSED(pSubMenu) )
350 {
351 wxMenuItemImpl* c = NULL;
352
353 c = new wxMenuItemCarbonImpl( peer );
354 return c;
355 }
356
357 void wxInsertMenuItemsInMenu(wxMenu* menu, MenuRef wm, MenuItemIndex insertAfter)
358 {
359 wxMenuItemList::compatibility_iterator node;
360 wxMenuItem *item;
361 wxMenu *subMenu = NULL ;
362 bool newItems = false;
363
364 for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
365 {
366 item = (wxMenuItem *)node->GetData();
367 subMenu = item->GetSubMenu() ;
368 if (subMenu)
369 {
370 wxInsertMenuItemsInMenu(subMenu, (MenuRef)subMenu->GetHMenu(), 0);
371 }
372 if ( item->IsSeparator() )
373 {
374 if ( wm && newItems)
375 InsertMenuItemTextWithCFString( wm,
376 CFSTR(""), insertAfter, kMenuItemAttrSeparator, 0);
377
378 newItems = false;
379 }
380 else
381 {
382 wxAcceleratorEntry*
383 entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
384
385 MenuItemIndex winListPos = (MenuItemIndex)-1;
386 OSStatus err = GetIndMenuItemWithCommandID(wm,
387 wxIdToMacCommand ( item->GetId() ), 1, NULL, &winListPos);
388
389 if ( wm && err == menuItemNotFoundErr )
390 {
391 // NB: the only way to determine whether or not we should add
392 // a separator is to know if we've added menu items to the menu
393 // before the separator.
394 newItems = true;
395 UMAInsertMenuItem(wm, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), insertAfter, entry);
396 SetMenuItemCommandID( wm , insertAfter+1 , wxIdToMacCommand ( item->GetId() ) ) ;
397 SetMenuItemRefCon( wm , insertAfter+1 , (URefCon) item ) ;
398 }
399
400 delete entry ;
401 }
402 }
403 }
404
405