]>
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 | ||
03e11df5 | 25 | #include "wx/app.h" |
e9576ca5 SC |
26 | #include "wx/menu.h" |
27 | #include "wx/menuitem.h" | |
03e11df5 | 28 | #include "wx/window.h" |
e9576ca5 SC |
29 | #include "wx/log.h" |
30 | #include "wx/utils.h" | |
31 | ||
519cb848 SC |
32 | #include "wx/mac/uma.h" |
33 | ||
e9576ca5 SC |
34 | // other standard headers |
35 | // ---------------------- | |
36 | #include <string.h> | |
37 | ||
2f1ae414 | 38 | #if !USE_SHARED_LIBRARY |
e9576ca5 SC |
39 | IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler) |
40 | IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler) | |
2f1ae414 | 41 | #endif |
e9576ca5 | 42 | |
519cb848 SC |
43 | // the (popup) menu title has this special id |
44 | static const int idMenuTitle = -2; | |
b03e4fcd | 45 | static MenuItemIndex firstUserHelpMenuItem = 0 ; |
519cb848 SC |
46 | |
47 | const short kwxMacMenuBarResource = 1 ; | |
48 | const short kwxMacAppleMenuId = 1 ; | |
49 | ||
e9576ca5 SC |
50 | // ============================================================================ |
51 | // implementation | |
52 | // ============================================================================ | |
53 | ||
519cb848 | 54 | |
e9576ca5 SC |
55 | // Menus |
56 | ||
57 | // Construct a menu with optional title (then use append) | |
519cb848 | 58 | |
f5c6eb5c | 59 | #ifdef __DARWIN__ |
82ca6dbc GD |
60 | short wxMenu::s_macNextMenuId = 3 ; |
61 | #else | |
519cb848 | 62 | short wxMenu::s_macNextMenuId = 2 ; |
82ca6dbc | 63 | #endif |
519cb848 | 64 | |
e7549107 | 65 | void wxMenu::Init() |
e9576ca5 | 66 | { |
e7549107 SC |
67 | m_doBreak = FALSE; |
68 | ||
69 | // create the menu | |
70 | Str255 label; | |
2f1ae414 | 71 | wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_title , false ); |
e7549107 | 72 | m_macMenuId = s_macNextMenuId++; |
72055702 | 73 | m_hMenu = ::NewMenu(m_macMenuId, label); |
e7549107 SC |
74 | |
75 | if ( !m_hMenu ) | |
76 | { | |
77 | wxLogLastError("CreatePopupMenu"); | |
78 | } | |
79 | ||
80 | // if we have a title, insert it in the beginning of the menu | |
81 | if ( !!m_title ) | |
e9576ca5 | 82 | { |
519cb848 | 83 | Append(idMenuTitle, m_title) ; |
e9576ca5 SC |
84 | AppendSeparator() ; |
85 | } | |
e7549107 | 86 | } |
e9576ca5 | 87 | |
e7549107 SC |
88 | wxMenu::~wxMenu() |
89 | { | |
76a5e5d2 SC |
90 | if (MAC_WXHMENU(m_hMenu)) |
91 | ::DisposeMenu(MAC_WXHMENU(m_hMenu)); | |
e9576ca5 | 92 | |
e7549107 SC |
93 | #if wxUSE_ACCEL |
94 | // delete accels | |
95 | WX_CLEAR_ARRAY(m_accels); | |
96 | #endif // wxUSE_ACCEL | |
e9576ca5 SC |
97 | } |
98 | ||
e7549107 | 99 | void wxMenu::Break() |
e9576ca5 | 100 | { |
e7549107 SC |
101 | // not available on the mac platform |
102 | } | |
e9576ca5 | 103 | |
e7549107 | 104 | #if wxUSE_ACCEL |
e9576ca5 | 105 | |
e7549107 SC |
106 | int wxMenu::FindAccel(int id) const |
107 | { | |
108 | size_t n, count = m_accels.GetCount(); | |
109 | for ( n = 0; n < count; n++ ) | |
110 | { | |
111 | if ( m_accels[n]->m_command == id ) | |
112 | return n; | |
e9576ca5 | 113 | } |
e7549107 SC |
114 | |
115 | return wxNOT_FOUND; | |
e9576ca5 SC |
116 | } |
117 | ||
e7549107 | 118 | void wxMenu::UpdateAccel(wxMenuItem *item) |
e9576ca5 | 119 | { |
e7549107 SC |
120 | // find the (new) accel for this item |
121 | wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText()); | |
122 | if ( accel ) | |
123 | accel->m_command = item->GetId(); | |
124 | ||
125 | // find the old one | |
126 | int n = FindAccel(item->GetId()); | |
127 | if ( n == wxNOT_FOUND ) | |
128 | { | |
129 | // no old, add new if any | |
130 | if ( accel ) | |
131 | m_accels.Add(accel); | |
132 | else | |
133 | return; // skipping RebuildAccelTable() below | |
134 | } | |
135 | else | |
136 | { | |
137 | // replace old with new or just remove the old one if no new | |
138 | delete m_accels[n]; | |
139 | if ( accel ) | |
140 | m_accels[n] = accel; | |
141 | else | |
3ef585df | 142 | m_accels.RemoveAt(n); |
e7549107 SC |
143 | } |
144 | ||
145 | if ( IsAttached() ) | |
146 | { | |
147 | m_menuBar->RebuildAccelTable(); | |
148 | } | |
e9576ca5 SC |
149 | } |
150 | ||
e7549107 SC |
151 | #endif // wxUSE_ACCEL |
152 | ||
e9576ca5 | 153 | // function appends a new item or submenu to the menu |
e7549107 SC |
154 | // append a new item or submenu to the menu |
155 | bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) | |
e9576ca5 | 156 | { |
e7549107 SC |
157 | wxASSERT_MSG( pItem != NULL, "can't append NULL item to the menu" ); |
158 | #if wxUSE_ACCEL | |
159 | UpdateAccel(pItem); | |
160 | #endif // wxUSE_ACCEL | |
e9576ca5 | 161 | |
519cb848 SC |
162 | if ( pItem->IsSeparator() ) |
163 | { | |
e7549107 SC |
164 | if ( pos == (size_t)-1 ) |
165 | { | |
76a5e5d2 | 166 | MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-"); |
e7549107 SC |
167 | } |
168 | else | |
169 | { | |
76a5e5d2 | 170 | MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos); |
e7549107 | 171 | } |
519cb848 SC |
172 | } |
173 | else | |
174 | { | |
175 | wxMenu *pSubMenu = pItem->GetSubMenu() ; | |
176 | if ( pSubMenu != NULL ) | |
177 | { | |
178 | Str255 label; | |
e7549107 SC |
179 | wxASSERT_MSG( pSubMenu->m_hMenu != NULL , "invalid submenu added"); |
180 | pSubMenu->m_menuParent = this ; | |
2f1ae414 | 181 | wxMenuItem::MacBuildMenuString( label , NULL , NULL , pItem->GetText() ,false); |
519cb848 | 182 | |
e7549107 | 183 | if (wxMenuBar::MacGetInstalledMenuBar() == m_menuBar) |
519cb848 | 184 | { |
76a5e5d2 | 185 | ::InsertMenu( MAC_WXHMENU( pSubMenu->m_hMenu ) , -1 ) ; |
519cb848 SC |
186 | } |
187 | ||
e7549107 SC |
188 | if ( pos == (size_t)-1 ) |
189 | { | |
76a5e5d2 | 190 | UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), label, pSubMenu->m_macMenuId); |
e7549107 SC |
191 | } |
192 | else | |
193 | { | |
76a5e5d2 | 194 | UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), label , pos, pSubMenu->m_macMenuId); |
e7549107 | 195 | } |
519cb848 SC |
196 | } |
197 | else | |
198 | { | |
199 | Str255 label ; | |
2f1ae414 SC |
200 | UInt8 modifiers ; |
201 | SInt16 key ; | |
202 | wxMenuItem::MacBuildMenuString( label, &key , &modifiers , pItem->GetText(), pItem->GetId() == wxApp::s_macAboutMenuItemId); | |
519cb848 SC |
203 | if ( label[0] == 0 ) |
204 | { | |
205 | // we cannot add empty menus on mac | |
206 | label[0] = 1 ; | |
207 | label[1] = ' ' ; | |
208 | } | |
e7549107 SC |
209 | if ( pos == (size_t)-1 ) |
210 | { | |
76a5e5d2 | 211 | UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), label,key,modifiers); |
e7549107 SC |
212 | } |
213 | else | |
214 | { | |
76a5e5d2 | 215 | UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), label , pos,key,modifiers); |
e7549107 | 216 | } |
519cb848 SC |
217 | if ( pItem->GetId() == idMenuTitle ) |
218 | { | |
e7549107 SC |
219 | if ( pos == (size_t)-1 ) |
220 | { | |
76a5e5d2 | 221 | UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , CountMenuItems(MAC_WXHMENU(m_hMenu) ) ) ; |
e7549107 SC |
222 | } |
223 | else | |
224 | { | |
76a5e5d2 | 225 | UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1 ) ; |
e7549107 | 226 | } |
519cb848 SC |
227 | } |
228 | } | |
229 | } | |
e7549107 SC |
230 | // if we're already attached to the menubar, we must update it |
231 | if ( IsAttached() ) | |
232 | { | |
233 | m_menuBar->Refresh(); | |
234 | } | |
235 | return TRUE ; | |
e9576ca5 SC |
236 | } |
237 | ||
e7549107 | 238 | bool wxMenu::DoAppend(wxMenuItem *item) |
e9576ca5 | 239 | { |
e7549107 | 240 | return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item); |
e9576ca5 SC |
241 | } |
242 | ||
e7549107 | 243 | bool wxMenu::DoInsert(size_t pos, wxMenuItem *item) |
e9576ca5 | 244 | { |
e7549107 | 245 | return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos); |
e9576ca5 SC |
246 | } |
247 | ||
e7549107 | 248 | wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) |
e9576ca5 | 249 | { |
e7549107 SC |
250 | // we need to find the items position in the child list |
251 | size_t pos; | |
252 | wxMenuItemList::Node *node = GetMenuItems().GetFirst(); | |
253 | for ( pos = 0; node; pos++ ) | |
254 | { | |
255 | if ( node->GetData() == item ) | |
256 | break; | |
e9576ca5 | 257 | |
e7549107 | 258 | node = node->GetNext(); |
e9576ca5 SC |
259 | } |
260 | ||
e7549107 SC |
261 | // DoRemove() (unlike Remove) can only be called for existing item! |
262 | wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); | |
519cb848 | 263 | |
e7549107 SC |
264 | #if wxUSE_ACCEL |
265 | // remove the corresponding accel from the accel table | |
266 | int n = FindAccel(item->GetId()); | |
267 | if ( n != wxNOT_FOUND ) | |
268 | { | |
269 | delete m_accels[n]; | |
519cb848 | 270 | |
3ef585df | 271 | m_accels.RemoveAt(n); |
e7549107 SC |
272 | } |
273 | //else: this item doesn't have an accel, nothing to do | |
274 | #endif // wxUSE_ACCEL | |
e9576ca5 | 275 | |
76a5e5d2 | 276 | ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1); |
e9576ca5 | 277 | |
e7549107 SC |
278 | if ( IsAttached() ) |
279 | { | |
280 | // otherwise, the chane won't be visible | |
281 | m_menuBar->Refresh(); | |
282 | } | |
e9576ca5 | 283 | |
e7549107 SC |
284 | // and from internal data structures |
285 | return wxMenuBase::DoRemove(item); | |
e9576ca5 SC |
286 | } |
287 | ||
e7549107 SC |
288 | // --------------------------------------------------------------------------- |
289 | // accelerator helpers | |
290 | // --------------------------------------------------------------------------- | |
e9576ca5 | 291 | |
e7549107 | 292 | #if wxUSE_ACCEL |
e9576ca5 | 293 | |
e7549107 SC |
294 | // create the wxAcceleratorEntries for our accels and put them into provided |
295 | // array - return the number of accels we have | |
296 | size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const | |
e9576ca5 | 297 | { |
e7549107 SC |
298 | size_t count = GetAccelCount(); |
299 | for ( size_t n = 0; n < count; n++ ) | |
300 | { | |
301 | *accels++ = *m_accels[n]; | |
302 | } | |
e9576ca5 | 303 | |
e7549107 | 304 | return count; |
e9576ca5 SC |
305 | } |
306 | ||
e7549107 | 307 | #endif // wxUSE_ACCEL |
e9576ca5 SC |
308 | |
309 | void wxMenu::SetTitle(const wxString& label) | |
310 | { | |
519cb848 | 311 | Str255 title ; |
e9576ca5 | 312 | m_title = label ; |
2f1ae414 | 313 | wxMenuItem::MacBuildMenuString( title, NULL , NULL , label , false ); |
76a5e5d2 | 314 | UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , title ) ; |
e9576ca5 | 315 | } |
e7549107 | 316 | bool wxMenu::ProcessCommand(wxCommandEvent & event) |
e9576ca5 SC |
317 | { |
318 | bool processed = FALSE; | |
319 | ||
e7549107 | 320 | #if WXWIN_COMPATIBILITY |
e9576ca5 SC |
321 | // Try a callback |
322 | if (m_callback) | |
323 | { | |
e7549107 SC |
324 | (void)(*(m_callback))(*this, event); |
325 | processed = TRUE; | |
e9576ca5 | 326 | } |
e7549107 | 327 | #endif WXWIN_COMPATIBILITY |
e9576ca5 SC |
328 | |
329 | // Try the menu's event handler | |
330 | if ( !processed && GetEventHandler()) | |
331 | { | |
e7549107 | 332 | processed = GetEventHandler()->ProcessEvent(event); |
e9576ca5 | 333 | } |
519cb848 | 334 | |
e7549107 SC |
335 | // Try the window the menu was popped up from (and up through the |
336 | // hierarchy) | |
337 | wxWindow *win = GetInvokingWindow(); | |
338 | if ( !processed && win ) | |
339 | processed = win->GetEventHandler()->ProcessEvent(event); | |
340 | ||
341 | return processed; | |
342 | } | |
343 | ||
344 | ||
345 | // --------------------------------------------------------------------------- | |
346 | // other | |
347 | // --------------------------------------------------------------------------- | |
348 | ||
e7549107 SC |
349 | wxWindow *wxMenu::GetWindow() const |
350 | { | |
351 | if ( m_invokingWindow != NULL ) | |
352 | return m_invokingWindow; | |
353 | else if ( m_menuBar != NULL) | |
03e11df5 | 354 | return (wxWindow *) m_menuBar->GetFrame(); |
e7549107 SC |
355 | |
356 | return NULL; | |
357 | } | |
519cb848 | 358 | |
519cb848 SC |
359 | // helper functions returning the mac menu position for a certain item, note that this is |
360 | // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0 | |
361 | ||
362 | int wxMenu::MacGetIndexFromId( int id ) | |
363 | { | |
e7549107 SC |
364 | size_t pos; |
365 | wxMenuItemList::Node *node = GetMenuItems().GetFirst(); | |
366 | for ( pos = 0; node; pos++ ) | |
519cb848 | 367 | { |
e7549107 SC |
368 | if ( node->GetData()->GetId() == id ) |
369 | break; | |
519cb848 | 370 | |
e7549107 SC |
371 | node = node->GetNext(); |
372 | } | |
373 | ||
519cb848 SC |
374 | if (!node) |
375 | return 0; | |
376 | ||
377 | return pos + 1 ; | |
378 | } | |
379 | ||
380 | int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem ) | |
381 | { | |
e7549107 SC |
382 | size_t pos; |
383 | wxMenuItemList::Node *node = GetMenuItems().GetFirst(); | |
384 | for ( pos = 0; node; pos++ ) | |
519cb848 | 385 | { |
e7549107 SC |
386 | if ( node->GetData() == pItem ) |
387 | break; | |
388 | ||
389 | node = node->GetNext(); | |
519cb848 SC |
390 | } |
391 | ||
392 | if (!node) | |
393 | return 0; | |
394 | ||
395 | return pos + 1 ; | |
396 | } | |
397 | ||
398 | void wxMenu::MacEnableMenu( bool bDoEnable ) | |
399 | { | |
519cb848 | 400 | if ( bDoEnable ) |
76a5e5d2 | 401 | UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ; |
519cb848 | 402 | else |
76a5e5d2 | 403 | UMADisableMenuItem(MAC_WXHMENU(m_hMenu) , 0 ) ; |
519cb848 SC |
404 | |
405 | ::DrawMenuBar() ; | |
406 | } | |
407 | ||
408 | bool wxMenu::MacMenuSelect( wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum ) | |
409 | { | |
8caf72d3 GD |
410 | int pos; |
411 | wxNode *node; | |
51abe921 | 412 | |
8caf72d3 GD |
413 | if ( m_macMenuId == macMenuId ) |
414 | { | |
415 | node = GetMenuItems().Nth(macMenuItemNum-1); | |
416 | if (node) | |
417 | { | |
418 | wxMenuItem *pItem = (wxMenuItem*)node->Data(); | |
419 | ||
420 | if (pItem->IsCheckable()) | |
421 | pItem->Check(! pItem->IsChecked()); | |
422 | ||
423 | wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId()); | |
424 | event.m_timeStamp = when; | |
425 | event.SetEventObject(handler); | |
426 | event.SetInt( pItem->GetId() ); | |
427 | { | |
428 | bool processed = false ; | |
429 | ||
51abe921 | 430 | #if WXWIN_COMPATIBILITY |
8caf72d3 GD |
431 | // Try a callback |
432 | if (m_callback) | |
433 | { | |
434 | (void) (*(m_callback)) (*this, event); | |
435 | processed = TRUE; | |
436 | } | |
51abe921 | 437 | #endif |
8caf72d3 GD |
438 | // Try the menu's event handler |
439 | if ( !processed && handler) | |
440 | { | |
441 | processed = handler->ProcessEvent(event); | |
442 | } | |
443 | ||
444 | // Try the window the menu was popped up from (and up | |
445 | // through the hierarchy) | |
446 | if ( !processed && GetInvokingWindow()) | |
447 | processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event); | |
448 | } | |
449 | return true ; | |
450 | } | |
451 | } | |
452 | else if ( macMenuId == kHMHelpMenuID ) | |
453 | { | |
454 | int menuItem = firstUserHelpMenuItem-1 ; | |
455 | for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++) | |
456 | { | |
457 | wxMenuItem * pItem = (wxMenuItem *) node->Data() ; | |
458 | ||
459 | wxMenu *pSubMenu = pItem->GetSubMenu() ; | |
460 | if ( pSubMenu != NULL ) | |
461 | { | |
462 | } | |
463 | else | |
464 | { | |
465 | if ( pItem->GetId() != wxApp::s_macAboutMenuItemId ) | |
466 | ++menuItem ; | |
467 | ||
468 | if ( menuItem == macMenuItemNum ) | |
469 | { | |
470 | wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, pItem->GetId()); | |
471 | event.m_timeStamp = when; | |
472 | event.SetEventObject(handler); | |
473 | event.SetInt( pItem->GetId() ); | |
474 | { | |
475 | bool processed = false ; | |
51abe921 | 476 | #if WXWIN_COMPATIBILITY |
8caf72d3 GD |
477 | // Try a callback |
478 | if (m_callback) | |
479 | { | |
480 | (void) (*(m_callback)) (*this, event); | |
481 | processed = TRUE; | |
482 | } | |
51abe921 | 483 | #endif |
8caf72d3 GD |
484 | // Try the menu's event handler |
485 | if ( !processed && handler) | |
486 | { | |
487 | processed = handler->ProcessEvent(event); | |
488 | } | |
489 | ||
490 | // Try the window the menu was popped up from (and up | |
491 | // through the hierarchy) | |
492 | if ( !processed && GetInvokingWindow()) | |
493 | processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event); | |
494 | } | |
495 | return true ; | |
496 | } | |
497 | } | |
498 | } | |
499 | } | |
500 | ||
501 | for (pos = 0, node = GetMenuItems().First(); node; node = node->Next(), pos++) | |
502 | { | |
503 | wxMenuItem * pItem = (wxMenuItem *) node->Data() ; | |
519cb848 | 504 | |
8caf72d3 GD |
505 | wxMenu *pSubMenu = pItem->GetSubMenu() ; |
506 | if ( pSubMenu != NULL ) | |
507 | { | |
508 | if ( pSubMenu->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) ) | |
509 | return true ; | |
510 | } | |
511 | } | |
512 | ||
513 | return false ; | |
e9576ca5 SC |
514 | } |
515 | ||
516 | // Menu Bar | |
519cb848 SC |
517 | |
518 | /* | |
519 | ||
520 | Mac Implementation note : | |
521 | ||
522 | The Mac has only one global menubar, so we attempt to install the currently | |
523 | active menubar from a frame, we currently don't take into account mdi-frames | |
524 | which would ask for menu-merging | |
525 | ||
526 | Secondly there is no mac api for changing a menubar that is not the current | |
527 | menubar, so we have to wait for preparing the actual menubar until the | |
528 | wxMenubar is to be used | |
529 | ||
530 | We can in subsequent versions use MacInstallMenuBar to provide some sort of | |
531 | auto-merge for MDI in case this will be necessary | |
532 | ||
533 | */ | |
534 | ||
535 | wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ; | |
536 | ||
e7549107 | 537 | void wxMenuBar::Init() |
e9576ca5 SC |
538 | { |
539 | m_eventHandler = this; | |
e9576ca5 | 540 | m_menuBarFrame = NULL; |
e9576ca5 SC |
541 | } |
542 | ||
51abe921 SC |
543 | wxMenuBar::wxMenuBar() |
544 | { | |
545 | Init(); | |
546 | } | |
547 | ||
548 | wxMenuBar::wxMenuBar( long WXUNUSED(style) ) | |
549 | { | |
550 | Init(); | |
551 | } | |
552 | ||
e7549107 SC |
553 | |
554 | wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[]) | |
e9576ca5 | 555 | { |
e7549107 SC |
556 | Init(); |
557 | ||
558 | m_titles.Alloc(count); | |
559 | ||
560 | for ( int i = 0; i < count; i++ ) | |
561 | { | |
562 | m_menus.Append(menus[i]); | |
563 | m_titles.Add(titles[i]); | |
564 | ||
565 | menus[i]->Attach(this); | |
566 | } | |
e9576ca5 SC |
567 | } |
568 | ||
569 | wxMenuBar::~wxMenuBar() | |
570 | { | |
519cb848 SC |
571 | if (s_macInstalledMenuBar == this) |
572 | { | |
573 | ::ClearMenuBar(); | |
574 | s_macInstalledMenuBar = NULL; | |
575 | } | |
576 | ||
e7549107 SC |
577 | } |
578 | ||
6d6da89c | 579 | void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect)) |
e7549107 SC |
580 | { |
581 | wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") ); | |
e9576ca5 | 582 | |
e7549107 | 583 | DrawMenuBar(); |
e9576ca5 SC |
584 | } |
585 | ||
51abe921 SC |
586 | #if wxUSE_ACCEL |
587 | ||
588 | void wxMenuBar::RebuildAccelTable() | |
589 | { | |
590 | // merge the accelerators of all menus into one accel table | |
591 | size_t nAccelCount = 0; | |
592 | size_t i, count = GetMenuCount(); | |
593 | for ( i = 0; i < count; i++ ) | |
594 | { | |
595 | nAccelCount += m_menus[i]->GetAccelCount(); | |
596 | } | |
597 | ||
598 | if ( nAccelCount ) | |
599 | { | |
600 | wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount]; | |
601 | ||
602 | nAccelCount = 0; | |
603 | for ( i = 0; i < count; i++ ) | |
604 | { | |
605 | nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]); | |
606 | } | |
607 | ||
608 | m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries); | |
609 | ||
610 | delete [] accelEntries; | |
611 | } | |
612 | } | |
613 | ||
614 | #endif // wxUSE_ACCEL | |
2b8a6962 | 615 | |
519cb848 SC |
616 | void wxMenuBar::MacInstallMenuBar() |
617 | { | |
2b8a6962 GD |
618 | if ( s_macInstalledMenuBar == this ) |
619 | return ; | |
41f38f4d | 620 | |
d9e054bc SC |
621 | wxStAppResource resload ; |
622 | ||
2b8a6962 GD |
623 | Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ; |
624 | wxString message ; | |
625 | wxCHECK_RET( menubar != NULL, "can't read MBAR resource" ); | |
626 | ::SetMenuBar( menubar ) ; | |
a3590de1 SC |
627 | #if TARGET_API_MAC_CARBON |
628 | ::DisposeMenuBar( menubar ) ; | |
629 | #else | |
2b8a6962 | 630 | ::DisposeHandle( menubar ) ; |
a3590de1 | 631 | #endif |
519cb848 | 632 | |
a3590de1 | 633 | #if TARGET_API_MAC_OS8 |
2b8a6962 | 634 | MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ; |
d9e054bc SC |
635 | if ( CountMenuItems( menu ) == 2 ) |
636 | { | |
2b8a6962 GD |
637 | ::AppendResMenu(menu, 'DRVR'); |
638 | } | |
a3590de1 | 639 | #endif |
519cb848 | 640 | |
2b8a6962 | 641 | for (size_t i = 0; i < m_menus.GetCount(); i++) |
519cb848 | 642 | { |
2b8a6962 GD |
643 | Str255 label; |
644 | wxNode *node; | |
645 | wxMenuItem *item; | |
646 | int pos ; | |
519cb848 SC |
647 | wxMenu* menu = m_menus[i] , *subMenu = NULL ; |
648 | ||
8208e181 | 649 | if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) |
519cb848 SC |
650 | { |
651 | MenuHandle mh = NULL ; | |
b03e4fcd SC |
652 | if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) != noErr ) |
653 | { | |
654 | continue ; | |
655 | } | |
a3590de1 SC |
656 | |
657 | for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i ) | |
658 | { | |
659 | DeleteMenuItem( mh , i ) ; | |
660 | } | |
519cb848 | 661 | |
2f1ae414 SC |
662 | for (pos = 0 , node = menu->GetMenuItems().First(); node; node = node->Next(), pos++) |
663 | { | |
519cb848 SC |
664 | item = (wxMenuItem *)node->Data(); |
665 | subMenu = item->GetSubMenu() ; | |
666 | if (subMenu) | |
667 | { | |
668 | // we don't support hierarchical menus in the help menu yet | |
669 | } | |
670 | else | |
671 | { | |
8208e181 | 672 | if ( item->IsSeparator() ) |
519cb848 | 673 | { |
8208e181 | 674 | if ( mh ) |
5bc0790f | 675 | MacAppendMenu(mh, "\p-" ); |
519cb848 | 676 | } |
519cb848 SC |
677 | else |
678 | { | |
8208e181 | 679 | Str255 label ; |
2f1ae414 SC |
680 | UInt8 modifiers ; |
681 | SInt16 key ; | |
682 | wxMenuItem::MacBuildMenuString( label, &key , &modifiers , item->GetText(), item->GetId() != wxApp::s_macAboutMenuItemId); // no shortcut in about menu | |
8208e181 SC |
683 | if ( label[0] == 0 ) |
684 | { | |
685 | // we cannot add empty menus on mac | |
686 | label[0] = 1 ; | |
687 | label[1] = ' ' ; | |
688 | } | |
689 | if ( item->GetId() == wxApp::s_macAboutMenuItemId ) | |
690 | { | |
72055702 | 691 | ::SetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , label ); |
2f1ae414 | 692 | UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 ); |
8208e181 SC |
693 | } |
694 | else | |
695 | { | |
696 | if ( mh ) | |
2f1ae414 | 697 | UMAAppendMenuItem(mh, label , key , modifiers ); |
8208e181 | 698 | } |
519cb848 SC |
699 | } |
700 | } | |
701 | } | |
702 | } | |
5b781a67 | 703 | else |
519cb848 | 704 | { |
2f1ae414 | 705 | wxMenuItem::MacBuildMenuString( label, NULL , NULL , m_titles[i] , false ); |
76a5e5d2 | 706 | UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ; |
9673f535 SC |
707 | wxArrayPtrVoid submenus ; |
708 | ||
2f1ae414 SC |
709 | for (pos = 0, node = menu->GetMenuItems().First(); node; node = node->Next(), pos++) |
710 | { | |
519cb848 SC |
711 | item = (wxMenuItem *)node->Data(); |
712 | subMenu = item->GetSubMenu() ; | |
713 | if (subMenu) | |
714 | { | |
9673f535 | 715 | submenus.Add(subMenu) ; |
519cb848 SC |
716 | } |
717 | } | |
76a5e5d2 | 718 | ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0); |
2b8a6962 | 719 | for ( size_t i = 0 ; i < submenus.GetCount() ; ++i ) |
9673f535 SC |
720 | { |
721 | wxMenu* submenu = (wxMenu*) submenus[i] ; | |
722 | wxNode *subnode; | |
723 | wxMenuItem *subitem; | |
724 | int subpos ; | |
725 | for ( subpos = 0 , subnode = submenu->GetMenuItems().First(); subnode; subnode = subnode->Next(), subpos++) | |
726 | { | |
727 | subitem = (wxMenuItem *)subnode->Data(); | |
728 | wxMenu* itsSubMenu = subitem->GetSubMenu() ; | |
729 | if (itsSubMenu) | |
730 | { | |
731 | submenus.Add(itsSubMenu) ; | |
732 | } | |
733 | } | |
76a5e5d2 | 734 | ::InsertMenu( MAC_WXHMENU(submenu->GetHMenu()) , -1 ) ; |
9673f535 | 735 | } |
519cb848 SC |
736 | } |
737 | } | |
72055702 | 738 | ::DrawMenuBar() ; |
519cb848 SC |
739 | s_macInstalledMenuBar = this; |
740 | } | |
741 | ||
e7549107 | 742 | void wxMenuBar::EnableTop(size_t pos, bool enable) |
e9576ca5 | 743 | { |
e7549107 SC |
744 | wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); |
745 | m_menus[pos]->MacEnableMenu( enable ) ; | |
746 | Refresh(); | |
e9576ca5 SC |
747 | } |
748 | ||
e7549107 | 749 | void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) |
e9576ca5 | 750 | { |
e7549107 | 751 | wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") ); |
e9576ca5 | 752 | |
e7549107 | 753 | m_titles[pos] = label; |
e9576ca5 | 754 | |
e7549107 SC |
755 | if ( !IsAttached() ) |
756 | { | |
e9576ca5 | 757 | return; |
e7549107 | 758 | } |
e9576ca5 | 759 | |
519cb848 | 760 | m_menus[pos]->SetTitle( label ) ; |
e7549107 | 761 | if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ? |
519cb848 | 762 | { |
e7549107 | 763 | ::SetMenuBar( GetMenuBar() ) ; |
519cb848 | 764 | ::InvalMenuBar() ; |
519cb848 | 765 | } |
e9576ca5 SC |
766 | } |
767 | ||
e7549107 | 768 | wxString wxMenuBar::GetLabelTop(size_t pos) const |
e9576ca5 | 769 | { |
e7549107 SC |
770 | wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString, |
771 | wxT("invalid menu index in wxMenuBar::GetLabelTop") ); | |
519cb848 | 772 | |
e7549107 | 773 | return m_titles[pos]; |
e9576ca5 SC |
774 | } |
775 | ||
e7549107 | 776 | int wxMenuBar::FindMenu(const wxString& title) |
e9576ca5 | 777 | { |
e7549107 | 778 | wxString menuTitle = wxStripMenuCodes(title); |
e9576ca5 | 779 | |
e7549107 SC |
780 | size_t count = GetMenuCount(); |
781 | for ( size_t i = 0; i < count; i++ ) | |
e9576ca5 | 782 | { |
e7549107 SC |
783 | wxString title = wxStripMenuCodes(m_titles[i]); |
784 | if ( menuTitle == title ) | |
785 | return i; | |
e9576ca5 | 786 | } |
e9576ca5 | 787 | |
e7549107 | 788 | return wxNOT_FOUND; |
e9576ca5 | 789 | |
e9576ca5 SC |
790 | } |
791 | ||
e7549107 SC |
792 | |
793 | // --------------------------------------------------------------------------- | |
794 | // wxMenuBar construction | |
795 | // --------------------------------------------------------------------------- | |
796 | ||
797 | // --------------------------------------------------------------------------- | |
798 | // wxMenuBar construction | |
799 | // --------------------------------------------------------------------------- | |
800 | ||
801 | wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) | |
e9576ca5 | 802 | { |
e7549107 SC |
803 | wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title); |
804 | if ( !menuOld ) | |
805 | return FALSE; | |
806 | m_titles[pos] = title; | |
e9576ca5 | 807 | |
e7549107 | 808 | if ( IsAttached() ) |
e9576ca5 | 809 | { |
e7549107 SC |
810 | if (s_macInstalledMenuBar == this) |
811 | { | |
72055702 | 812 | ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; |
e7549107 SC |
813 | { |
814 | Str255 label; | |
2f1ae414 | 815 | wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false ); |
76a5e5d2 | 816 | UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ; |
e7549107 SC |
817 | if ( pos == m_menus.GetCount() - 1) |
818 | { | |
76a5e5d2 | 819 | ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ; |
e7549107 SC |
820 | } |
821 | else | |
822 | { | |
76a5e5d2 | 823 | ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ; |
e7549107 SC |
824 | } |
825 | } | |
826 | } | |
e9576ca5 | 827 | |
e9576ca5 | 828 | |
e7549107 SC |
829 | #if wxUSE_ACCEL |
830 | if ( menuOld->HasAccels() || menu->HasAccels() ) | |
831 | { | |
832 | // need to rebuild accell table | |
833 | RebuildAccelTable(); | |
834 | } | |
835 | #endif // wxUSE_ACCEL | |
e9576ca5 | 836 | |
e7549107 | 837 | Refresh(); |
e9576ca5 | 838 | } |
e9576ca5 | 839 | |
e7549107 | 840 | return menuOld; |
e9576ca5 SC |
841 | } |
842 | ||
e7549107 | 843 | bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) |
e9576ca5 | 844 | { |
e7549107 SC |
845 | if ( !wxMenuBarBase::Insert(pos, menu, title) ) |
846 | return FALSE; | |
e9576ca5 | 847 | |
e7549107 | 848 | m_titles.Insert(title, pos); |
e9576ca5 | 849 | |
40325b26 SC |
850 | Str255 label ; |
851 | wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false ); | |
852 | UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ; | |
e7549107 SC |
853 | |
854 | if ( IsAttached() ) | |
e9576ca5 | 855 | { |
40325b26 | 856 | if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() ) |
e7549107 | 857 | { |
76a5e5d2 | 858 | ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ; |
e7549107 SC |
859 | } |
860 | else | |
861 | { | |
76a5e5d2 | 862 | ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ; |
e7549107 SC |
863 | } |
864 | ||
865 | #if wxUSE_ACCEL | |
866 | if ( menu->HasAccels() ) | |
e9576ca5 | 867 | { |
e7549107 SC |
868 | // need to rebuild accell table |
869 | RebuildAccelTable(); | |
e9576ca5 | 870 | } |
e7549107 | 871 | #endif // wxUSE_ACCEL |
e9576ca5 | 872 | |
e7549107 | 873 | Refresh(); |
e9576ca5 | 874 | } |
e7549107 SC |
875 | |
876 | return TRUE; | |
e9576ca5 SC |
877 | } |
878 | ||
519cb848 SC |
879 | void wxMenuBar::MacMenuSelect(wxEvtHandler* handler, long when , int macMenuId, int macMenuItemNum) |
880 | { | |
8caf72d3 GD |
881 | // first scan fast for direct commands, i.e. menus which have these commands directly in their own list |
882 | ||
883 | if ( macMenuId == kwxMacAppleMenuId && macMenuItemNum == 1 ) | |
884 | { | |
885 | wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxApp::s_macAboutMenuItemId ); | |
886 | event.m_timeStamp = when; | |
887 | event.SetEventObject(handler); | |
888 | event.SetInt( wxApp::s_macAboutMenuItemId ); | |
889 | handler->ProcessEvent(event); | |
890 | } | |
891 | else | |
892 | { | |
2b8a6962 | 893 | for (size_t i = 0; i < m_menus.GetCount() ; i++) |
8caf72d3 GD |
894 | { |
895 | if ( m_menus[i]->MacGetMenuId() == macMenuId || ( macMenuId == kHMHelpMenuID && ( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName ) ) ) | |
896 | { | |
897 | if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) ) | |
898 | return ; | |
899 | else | |
900 | { | |
901 | //TODO flag this as an error since it must contain the item | |
902 | return ; | |
903 | } | |
904 | } | |
905 | } | |
519cb848 | 906 | |
2b8a6962 | 907 | for (size_t i = 0; i < m_menus.GetCount(); i++) |
519cb848 SC |
908 | { |
909 | if ( m_menus[i]->MacMenuSelect( handler , when , macMenuId , macMenuItemNum ) ) | |
910 | { | |
911 | break ; | |
912 | } | |
51abe921 | 913 | } |
519cb848 SC |
914 | } |
915 | } | |
e9576ca5 | 916 | |
51abe921 SC |
917 | wxMenu *wxMenuBar::Remove(size_t pos) |
918 | { | |
919 | wxMenu *menu = wxMenuBarBase::Remove(pos); | |
920 | if ( !menu ) | |
921 | return NULL; | |
922 | ||
923 | if ( IsAttached() ) | |
924 | { | |
925 | if (s_macInstalledMenuBar == this) | |
926 | { | |
927 | ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; | |
928 | } | |
929 | ||
930 | menu->Detach(); | |
931 | ||
932 | #if wxUSE_ACCEL | |
933 | if ( menu->HasAccels() ) | |
934 | { | |
935 | // need to rebuild accell table | |
936 | RebuildAccelTable(); | |
937 | } | |
938 | #endif // wxUSE_ACCEL | |
939 | ||
940 | Refresh(); | |
941 | } | |
942 | ||
943 | m_titles.Remove(pos); | |
944 | ||
945 | return menu; | |
946 | } | |
947 | ||
948 | bool wxMenuBar::Append(wxMenu *menu, const wxString& title) | |
949 | { | |
950 | WXHMENU submenu = menu ? menu->GetHMenu() : 0; | |
951 | wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") ); | |
952 | ||
953 | if ( !wxMenuBarBase::Append(menu, title) ) | |
954 | return FALSE; | |
955 | ||
51abe921 | 956 | m_titles.Add(title); |
40325b26 SC |
957 | |
958 | Str255 label ; | |
959 | wxMenuItem::MacBuildMenuString( label, NULL , NULL , title , false ); | |
960 | UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , label ) ; | |
51abe921 SC |
961 | |
962 | if ( IsAttached() ) | |
963 | { | |
40325b26 SC |
964 | if (s_macInstalledMenuBar == this) |
965 | { | |
966 | ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ; | |
967 | } | |
51abe921 SC |
968 | |
969 | #if wxUSE_ACCEL | |
970 | if ( menu->HasAccels() ) | |
971 | { | |
972 | // need to rebuild accell table | |
973 | RebuildAccelTable(); | |
974 | } | |
975 | #endif // wxUSE_ACCEL | |
976 | ||
977 | Refresh(); | |
978 | } | |
979 | ||
980 | return TRUE; | |
981 | } | |
982 | ||
90b959ae | 983 | void wxMenuBar::Detach() |
2f1ae414 | 984 | { |
90b959ae SC |
985 | wxMenuBarBase::Detach() ; |
986 | } | |
2f1ae414 | 987 | |
90b959ae SC |
988 | void wxMenuBar::Attach(wxFrame *frame) |
989 | { | |
990 | wxMenuBarBase::Attach( frame ) ; | |
2f1ae414 SC |
991 | |
992 | #if wxUSE_ACCEL | |
993 | RebuildAccelTable(); | |
994 | #endif // wxUSE_ACCEL | |
995 | } | |
51abe921 SC |
996 | // --------------------------------------------------------------------------- |
997 | // wxMenuBar searching for menu items | |
998 | // --------------------------------------------------------------------------- | |
999 | ||
1000 | // Find the itemString in menuString, and return the item id or wxNOT_FOUND | |
1001 | int wxMenuBar::FindMenuItem(const wxString& menuString, | |
1002 | const wxString& itemString) const | |
1003 | { | |
1004 | wxString menuLabel = wxStripMenuCodes(menuString); | |
1005 | size_t count = GetMenuCount(); | |
1006 | for ( size_t i = 0; i < count; i++ ) | |
1007 | { | |
1008 | wxString title = wxStripMenuCodes(m_titles[i]); | |
1009 | if ( menuString == title ) | |
1010 | return m_menus[i]->FindItem(itemString); | |
1011 | } | |
1012 | ||
1013 | return wxNOT_FOUND; | |
1014 | } | |
1015 | ||
1016 | wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const | |
1017 | { | |
1018 | if ( itemMenu ) | |
1019 | *itemMenu = NULL; | |
1020 | ||
1021 | wxMenuItem *item = NULL; | |
1022 | size_t count = GetMenuCount(); | |
1023 | for ( size_t i = 0; !item && (i < count); i++ ) | |
1024 | { | |
1025 | item = m_menus[i]->FindItem(id, itemMenu); | |
1026 | } | |
1027 | ||
1028 | return item; | |
1029 | } | |
1030 | ||
1031 |