]> git.saurik.com Git - wxWidgets.git/blame - src/mac/menu.cpp
Added wxStrnicmp and to wchar.h, not yet for Unicode mode.
[wxWidgets.git] / src / mac / menu.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
4// Author: AUTHOR
5// Modified by:
6// Created: ??/??/98
7// RCS-ID: $Id$
8// Copyright: (c) AUTHOR
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12
13// ============================================================================
14// headers & declarations
15// ============================================================================
16
17// wxWindows headers
18// -----------------
19
20#ifdef __GNUG__
21#pragma implementation "menu.h"
22#pragma implementation "menuitem.h"
23#endif
24
25#include "wx/menu.h"
26#include "wx/menuitem.h"
27#include "wx/log.h"
28#include "wx/utils.h"
29
519cb848
SC
30#include "wx/mac/uma.h"
31
e9576ca5
SC
32// other standard headers
33// ----------------------
34#include <string.h>
35
36#if !USE_SHARED_LIBRARY
37IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
38IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
39#endif
40
519cb848
SC
41// the (popup) menu title has this special id
42static const int idMenuTitle = -2;
43static int formerHelpMenuItems = 0 ;
44
45const short kwxMacMenuBarResource = 1 ;
46const short kwxMacAppleMenuId = 1 ;
47
e9576ca5
SC
48// ============================================================================
49// implementation
50// ============================================================================
51
519cb848
SC
52//
53// Helper Functions to get Mac Menus the way they should be ;-)
54//
55
56void wxMacCtoPString(const char* theCString, Str255 thePString);
57
58// remove inappropriate characters, if useShortcuts is false, the ampersand will not auto-generate a mac menu-shortcut
59
60static void wxMacBuildMenuString(StringPtr outMacItemText, char *outMacShortcutChar , short *outMacModifiers , const char *inItemName , bool useShortcuts )
61{
62 char *p = (char *) &outMacItemText[1] ;
63 short macModifiers = 0 ;
64 char macShortCut = 0 ;
65
66 if ( useShortcuts && !wxApp::s_macSupportPCMenuShortcuts )
67 useShortcuts = false ;
68
69 // we have problems with a leading hypen - it will be taken as a separator
70
71 while ( *inItemName == '-' )
72 inItemName++ ;
73
74 while( *inItemName )
75 {
76 switch ( *inItemName )
77 {
78 // special characters for macintosh menus -> use some replacement
79 case ';' :
80 *p++ = ',' ;
81 break ;
82 case '^' :
83 *p++ = ' ' ;
84 break ;
85 case '!' :
86 *p++ = ' ' ;
87 break ;
88 case '<' :
89 *p++ = ' ' ;
90 break ;
91 case '/' :
92 *p++ = '|' ;
93 break ;
94 case '(' :
95 *p++ = '[' ;
96 break ;
97 case ')' :
98 *p++ = ']' ;
99 break ;
100 // shortcuts
101 case '&' :
102 {
103 ++inItemName ;
104 if ( *inItemName )
105 {
106 *p++ = *inItemName ;
107 if ( useShortcuts )
108 macShortCut = *inItemName ;
109 }
110 else
111 --inItemName ;
112 }
113 break ;
114 // win-like accelerators
115 case '\t' :
116 {
117 ++inItemName ;
118 while( *inItemName )
119 {
120 if (strncmp("Ctrl+", inItemName, 5) == 0)
121 {
122 inItemName = inItemName + 5;
123 macShortCut = *inItemName;
124 }
125 else if (strncmp("Alt+", inItemName, 4) == 0)
126 {
127 inItemName = inItemName + 4;
128 macModifiers |= kMenuOptionModifier ;
129 macShortCut = *inItemName ;
130 }
131 else if (strncmp("Shift+", inItemName, 6) == 0)
132 {
133 inItemName = inItemName + 6;
134 macModifiers |= kMenuShiftModifier ;
135 macShortCut = *inItemName ;
136 }
137 else if (strncmp("F", inItemName, 1) == 0)
138 {
139 inItemName += strlen( inItemName ) ;
140 // no function keys at the moment
141 // macModifiers |= kMenuShiftModifier ;
142 // macShortCut = *inItemName ;
143 }
144 else
145 {
146 break ;
147 }
148 }
149
150 if ( *inItemName == 0 )
151 --inItemName ;
152
153 }
154 break ;
155 default :
156 *p++ = *inItemName ;
157 }
158 ++inItemName ;
159 }
160
161 outMacItemText[0] = (p - (char *)outMacItemText) - 1;
162 if ( outMacShortcutChar )
163 *outMacShortcutChar = macShortCut ;
164 if ( outMacModifiers )
165 *outMacModifiers = macModifiers ;
166 if ( macShortCut )
167 {
168 int pos = outMacItemText[0] ;
169 outMacItemText[++pos] = '/';
170 outMacItemText[++pos] = toupper( macShortCut );
171 outMacItemText[0] = pos ;
172 }
173}
174
e9576ca5
SC
175// Menus
176
177// Construct a menu with optional title (then use append)
519cb848
SC
178
179short wxMenu::s_macNextMenuId = 2 ;
180
e9576ca5
SC
181wxMenu::wxMenu(const wxString& title, const wxFunction func)
182{
183 m_title = title;
184 m_parent = NULL;
185 m_eventHandler = this;
186 m_noItems = 0;
187 m_menuBar = NULL;
519cb848 188 m_pInvokingWindow = NULL ;
e9576ca5
SC
189 m_clientData = (void*) NULL;
190 if (m_title != "")
191 {
519cb848 192 Append(idMenuTitle, m_title) ;
e9576ca5
SC
193 AppendSeparator() ;
194 }
195
196 Callback(func);
197
519cb848
SC
198 Str255 label;
199 wxMacBuildMenuString( label, NULL , NULL , title , false );
200 m_macMenuId = s_macNextMenuId++;
201 wxCHECK_RET( s_macNextMenuId < 236 , "menu ids > 235 cannot be used for submenus on mac" );
202 m_macMenuHandle = ::NewMenu(m_macMenuId, label);
203 m_macMenuEnabled = true ;
e9576ca5
SC
204}
205
206// The wxWindow destructor will take care of deleting the submenus.
207wxMenu::~wxMenu()
208{
e9576ca5
SC
209 wxNode *node = m_menuItems.First();
210 while (node)
211 {
212 wxMenuItem *item = (wxMenuItem *)node->Data();
213
214 // Delete child menus.
215 // Beware: they must not be appended to children list!!!
216 // (because order of delete is significant)
217 if (item->GetSubMenu())
218 item->DeleteSubMenu();
219
220 wxNode *next = node->Next();
221 delete item;
222 delete node;
223 node = next;
224 }
519cb848
SC
225 if (m_macMenuHandle)
226 ::DisposeMenu(m_macMenuHandle);
e9576ca5
SC
227}
228
229void wxMenu::Break()
230{
519cb848 231 // not available on the mac platform
e9576ca5
SC
232}
233
234// function appends a new item or submenu to the menu
235void wxMenu::Append(wxMenuItem *pItem)
236{
e9576ca5
SC
237 wxCHECK_RET( pItem != NULL, "can't append NULL item to the menu" );
238
239 m_menuItems.Append(pItem);
240
519cb848
SC
241 if ( pItem->IsSeparator() )
242 {
243 MacAppendMenu(m_macMenuHandle, "\p-");
244 }
245 else
246 {
247 wxMenu *pSubMenu = pItem->GetSubMenu() ;
248 if ( pSubMenu != NULL )
249 {
250 Str255 label;
251 wxCHECK_RET( pSubMenu->m_macMenuHandle != NULL , "invalid submenu added");
252 pSubMenu->m_parent = this ;
253 wxMacBuildMenuString( label , NULL , NULL , pItem->GetName() ,false);
254
255 // hardcoded adding of the submenu combination for mac
256
257 int theEnd = label[0] + 1;
258 if (theEnd > 251)
259 theEnd = 251; // mac allows only 255 characters
260 label[theEnd++] = '/';
261 label[theEnd++] = hMenuCmd;
262 label[theEnd++] = '!';
263 label[theEnd++] = pSubMenu->m_macMenuId;
264 label[theEnd] = 0x00;
265 label[0] = theEnd;
266
267 if (wxMenuBar::s_macInstalledMenuBar == m_menuBar)
268 {
269 ::InsertMenu( pSubMenu->m_macMenuHandle , -1 ) ;
270 }
271
272 ::AppendMenu(m_macMenuHandle, label);
273 }
274 else
275 {
276 Str255 label ;
277 wxMacBuildMenuString( label , NULL , NULL , pItem->GetName(), pItem->GetId() == wxApp::s_macAboutMenuItemId);
278 if ( label[0] == 0 )
279 {
280 // we cannot add empty menus on mac
281 label[0] = 1 ;
282 label[1] = ' ' ;
283 }
284 ::AppendMenu(m_macMenuHandle, label );
285 if ( pItem->GetId() == idMenuTitle )
286 {
287 UMADisableMenuItem( m_macMenuHandle , CountMItems( m_macMenuHandle ) ) ;
288 }
289 }
290 }
291
e9576ca5
SC
292 m_noItems++;
293}
294
295void wxMenu::AppendSeparator()
296{
e9576ca5
SC
297 Append(new wxMenuItem(this, ID_SEPARATOR));
298}
299
300// Pullright item
301void wxMenu::Append(int Id, const wxString& label, wxMenu *SubMenu,
302 const wxString& helpString)
303{
304 Append(new wxMenuItem(this, Id, label, helpString, FALSE, SubMenu));
305}
306
307// Ordinary menu item
308void wxMenu::Append(int Id, const wxString& label,
309 const wxString& helpString, bool checkable)
310{
311 // 'checkable' parameter is useless for Windows.
312 Append(new wxMenuItem(this, Id, label, helpString, checkable));
313}
314
315void wxMenu::Delete(int id)
316{
317 wxNode *node;
318 wxMenuItem *item;
319 int pos;
320
321 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) {
322 item = (wxMenuItem *)node->Data();
323 if (item->GetId() == id)
324 break;
325 }
326
327 if (!node)
519cb848
SC
328 return;
329
330 int index = pos + 1 ;
331
332 if (index < 1)
333 return;
334
335 wxMenu *pSubMenu = item->GetSubMenu();
336 if ( pSubMenu != NULL )
337 {
338 ::DeleteMenuItem( m_macMenuHandle , index);
339 pSubMenu->m_parent = NULL;
340 // TODO: Why isn't subMenu deleted here???
341 // Will put this in for now. Assuming this is supposed
342 // to delete the menu, not just remove it.
343 item->DeleteSubMenu();
344 }
345 else
346 {
347 ::DeleteMenuItem( m_macMenuHandle , index);
348 }
e9576ca5
SC
349
350 m_menuItems.DeleteNode(node);
519cb848 351