]>
Commit | Line | Data |
---|---|---|
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 | |
37 | IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler) | |
38 | IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler) | |
39 | #endif | |
40 | ||
519cb848 SC |
41 | // the (popup) menu title has this special id |
42 | static const int idMenuTitle = -2; | |
43 | static int formerHelpMenuItems = 0 ; | |
44 | ||
45 | const short kwxMacMenuBarResource = 1 ; | |
46 | const 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 | ||
56 | void 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 | ||
60 | static 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 | |
179 | short wxMenu::s_macNextMenuId = 2 ; | |
180 | ||
e9576ca5 SC |
181 | wxMenu::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. | |
207 | wxMenu::~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 | ||
229 | void 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 | |
235 | void 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 | ||
295 | void wxMenu::AppendSeparator() | |
296 | { | |
e9576ca5 SC |
297 | Append(new wxMenuItem(this, ID_SEPARATOR)); |
298 | } | |
299 | ||
300 | // Pullright item | |
301 | void 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 | |
308 | void 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 | ||
315 | void 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 |