]> git.saurik.com Git - wxWidgets.git/blame - src/os2/menu.cpp
Checked for stream validity in wxImage::GetImageCount.
[wxWidgets.git] / src / os2 / menu.cpp
CommitLineData
0e320a79
DW
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
75f11ad7 4// Author: David Webster
0e320a79 5// Modified by:
75f11ad7 6// Created: 10/10/99
0e320a79 7// RCS-ID: $Id$
75f11ad7
DW
8// Copyright: (c) David Webster
9// Licence: wxWindows licence
0e320a79
DW
10/////////////////////////////////////////////////////////////////////////////
11
a4372af6
SN
12#ifdef __GNUG__
13 #pragma implementation "menu.h"
14#endif
15
75f11ad7
DW
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
0e320a79 18
75f11ad7 19#ifndef WX_PRECOMP
b59c98dd 20 #include "wx/app.h"
75f11ad7
DW
21 #include "wx/frame.h"
22 #include "wx/menu.h"
23 #include "wx/utils.h"
24 #include "wx/intl.h"
c5fb56c0 25 #include "wx/log.h"
75f11ad7 26#endif
0e320a79 27
75f11ad7
DW
28#if wxUSE_OWNER_DRAWN
29 #include "wx/ownerdrw.h"
0e320a79
DW
30#endif
31
75f11ad7 32#include "wx/os2/private.h"
0e320a79
DW
33
34// other standard headers
0e320a79
DW
35#include <string.h>
36
75f11ad7
DW
37// ----------------------------------------------------------------------------
38// global variables
39// ----------------------------------------------------------------------------
40
61243a51 41extern wxMenu* wxCurrentPopupMenu;
75f11ad7
DW
42
43// ----------------------------------------------------------------------------
44// constants
45// ----------------------------------------------------------------------------
46
61243a51
DW
47//
48// The (popup) menu title has this special id
49//
50static const int idMenuTitle = -2;
75f11ad7 51
f6bcfd97
BP
52//
53// The unique ID for Menus
54//
55#ifdef __VISAGECPP__
56USHORT wxMenu::m_nextMenuId = 0;
57#else
58static USHORT wxMenu::m_nextMenuId = 0;
59#endif
60
75f11ad7
DW
61// ----------------------------------------------------------------------------
62// macros
63// ----------------------------------------------------------------------------
64
75f11ad7
DW
65 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
66 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
0e320a79 67
2b33b728
SN
68// ----------------------------------------------------------------------------
69// static function for translating menu labels
70// ----------------------------------------------------------------------------
71
c9667cda
DW
72static wxString TextToLabel(
73 const wxString& rsTitle
74)
2b33b728 75{
8635b0db 76 wxString sTitle = "";
c9667cda
DW
77 const wxChar* zPc;
78
8635b0db
DW
79 if (rsTitle.IsEmpty())
80 return sTitle;
c9667cda 81 for (zPc = rsTitle.c_str(); *zPc != wxT('\0'); zPc++ )
2b33b728 82 {
c9667cda 83 if (*zPc == wxT('&') )
2b33b728 84 {
c9667cda 85 if (*(zPc + 1) == wxT('&'))
2b33b728 86 {
c9667cda
DW
87 zPc++;
88 sTitle << wxT('&');
2b33b728 89 }
f6bcfd97 90 else
c9667cda 91 sTitle << wxT('~');
2b33b728 92 }
2b33b728
SN
93 else
94 {
c9667cda 95 if ( *zPc == wxT('~') )
2b33b728 96 {
c9667cda
DW
97 //
98 // Tildes must be doubled to prevent them from being
2b33b728 99 // interpreted as accelerator character prefix by PM ???
c9667cda
DW
100 //
101 sTitle << *zPc;
2b33b728 102 }
c9667cda 103 sTitle << *zPc;
2b33b728
SN
104 }
105 }
c9667cda
DW
106 return sTitle;
107} // end of TextToLabel
2b33b728 108
0e320a79
DW
109// ============================================================================
110// implementation
111// ============================================================================
112
75f11ad7
DW
113// ---------------------------------------------------------------------------
114// wxMenu construction, adding and removing menu items
115// ---------------------------------------------------------------------------
0e320a79 116
61243a51 117//
0e320a79 118// Construct a menu with optional title (then use append)
61243a51 119//
c5fb56c0 120void wxMenu::Init()
0e320a79 121{
61243a51 122 m_bDoBreak = FALSE;
598d8cac 123 m_nStartRadioGroup = -1;
61243a51
DW
124
125 //
f23208ca
DW
126 // Create the menu (to be used as a submenu or a popup)
127 //
128 if ((m_hMenu = ::WinCreateWindow( HWND_DESKTOP
f6bcfd97 129 ,WC_MENU
f23208ca
DW
130 ,"Menu"
131 ,0L
132 ,0L
133 ,0L
134 ,0L
135 ,0L
136 ,NULLHANDLE
137 ,HWND_TOP
138 ,0L
139 ,NULL
140 ,NULL
a0606634 141 )) == 0)
61243a51
DW
142 {
143 wxLogLastError("WinLoadMenu");
144 }
a0606634
DW
145 m_vMenuData.iPosition = 0;
146 m_vMenuData.afStyle = MIS_SUBMENU | MIS_TEXT;
147 m_vMenuData.afAttribute = (USHORT)0;
f6bcfd97 148 m_vMenuData.id = m_nextMenuId++;
a0606634
DW
149 m_vMenuData.hwndSubMenu = m_hMenu;
150 m_vMenuData.hItem = NULLHANDLE;
61243a51
DW
151
152 //
153 // If we have a title, insert it in the beginning of the menu
154 //
f23208ca 155 if (!m_title.IsEmpty())
61243a51
DW
156 {
157 Append( idMenuTitle
158 ,m_title
c9667cda
DW
159 ,wxEmptyString
160 ,wxITEM_NORMAL
61243a51 161 );
c5fb56c0
DW
162 AppendSeparator();
163 }
61243a51 164} // end of wxMenu::Init
0e320a79 165
61243a51 166//
0e320a79 167// The wxWindow destructor will take care of deleting the submenus.
61243a51 168//
0e320a79
DW
169wxMenu::~wxMenu()
170{
61243a51
DW
171 //
172 // We should free PM resources only if PM doesn't do it for us
c5fb56c0
DW
173 // which happens if we're attached to a menubar or a submenu of another
174 // menu
61243a51 175 if (!IsAttached() && !GetParent())
75f11ad7 176 {
61243a51 177 if (!::WinDestroyWindow((HWND)GetHmenu()) )
c5fb56c0 178 {
61243a51 179 wxLogLastError("WinDestroyWindow");
c5fb56c0 180 }
75f11ad7 181 }
0e320a79 182
c5fb56c0 183#if wxUSE_ACCEL
61243a51
DW
184 //
185 // Delete accels
186 //
598d8cac 187 WX_CLEAR_ARRAY(m_vAccels);
c5fb56c0 188#endif // wxUSE_ACCEL
61243a51 189} // end of wxMenu::~wxMenu
0e320a79
DW
190
191void wxMenu::Break()
192{
c5fb56c0 193 // this will take effect during the next call to Append()
61243a51
DW
194 m_bDoBreak = TRUE;
195} // end of wxMenu::Break
0e320a79 196
598d8cac
DW
197void wxMenu::Attach(
198 wxMenuBarBase* pMenubar
199)
ab4fece8 200{
598d8cac
DW
201 wxMenuBase::Attach(pMenubar);
202 EndRadioGroup();
203} // end of wxMenu::Break;
204
205#if wxUSE_ACCEL
ab4fece8 206
61243a51
DW
207int wxMenu::FindAccel(
208 int nId
209) const
0e320a79 210{
61243a51 211 size_t n;
598d8cac 212 size_t nCount = m_vAccels.GetCount();
61243a51 213
598d8cac
DW
214 for (n = 0; n < nCount; n++)
215 if (m_vAccels[n]->m_command == nId)
216 return n;
c5fb56c0 217 return wxNOT_FOUND;
61243a51 218} // end of wxMenu::FindAccel
75f11ad7 219
61243a51
DW
220void wxMenu::UpdateAccel(
221 wxMenuItem* pItem
222)
c5fb56c0 223{
a086de98
DW
224 if (pItem->IsSubMenu())
225 {
226 wxMenu* pSubmenu = pItem->GetSubMenu();
227 wxMenuItemList::Node* pNode = pSubmenu->GetMenuItems().GetFirst();
61243a51 228
a086de98
DW
229 while (pNode)
230 {
231 UpdateAccel(pNode->GetData());
232 pNode = pNode->GetNext();
233 }
234 }
235 else if (!pItem->IsSeparator())
c5fb56c0 236 {
61243a51 237 //
a086de98 238 // Find the (new) accel for this item
61243a51 239 //
a086de98 240 wxAcceleratorEntry* pAccel = wxGetAccelFromString(pItem->GetText());
598d8cac 241
61243a51 242 if (pAccel)
a086de98
DW
243 pAccel->m_command = pItem->GetId();
244
61243a51 245 //
a086de98 246 // Find the old one
61243a51 247 //
938aa9c4 248 size_t n = FindAccel(pItem->GetId());
61243a51 249
a086de98
DW
250 if (n == wxNOT_FOUND)
251 {
252 //
253 // No old, add new if any
254 //
255 if (pAccel)
598d8cac 256 m_vAccels.Add(pAccel);
a086de98 257 else
598d8cac 258 return;
a086de98 259 }
c5fb56c0 260 else
a086de98
DW
261 {
262 //
263 // Replace old with new or just remove the old one if no new
264 //
938aa9c4 265 delete m_vAccels[n];
a086de98
DW
266 if (pAccel)
267 m_vAccels[n] = pAccel;
598d8cac
DW
268 else
269 m_vAccels.RemoveAt(n);
a086de98
DW
270 }
271
272 if (IsAttached())
273 {
274 m_menuBar->RebuildAccelTable();
275 }
c5fb56c0 276 }
61243a51 277} // wxMenu::UpdateAccel
c5fb56c0 278
75f11ad7 279#endif // wxUSE_ACCEL
0e320a79 280
61243a51
DW
281//
282// Append a new item or submenu to the menu
283//
284bool wxMenu::DoInsertOrAppend(
285 wxMenuItem* pItem
286, size_t nPos
287)
c5fb56c0 288{
938aa9c4
DW
289 wxMenu* pSubmenu = pItem->GetSubMenu();
290 MENUITEM& rItem = (pSubmenu != NULL)?pSubmenu->m_vMenuData:
291 pItem->m_vMenuData;
292
a0606634
DW
293 ERRORID vError;
294 wxString sError;
45bedfdd 295 char zMsg[128];
8635b0db 296
c5fb56c0
DW
297#if wxUSE_ACCEL
298 UpdateAccel(pItem);
299#endif // wxUSE_ACCEL
0e320a79 300
61243a51
DW
301 //
302 // If "Break" has just been called, insert a menu break before this item
75f11ad7 303 // (and don't forget to reset the flag)
61243a51
DW
304 //
305 if (m_bDoBreak)
306 {
f6bcfd97 307 rItem.afStyle |= MIS_BREAK;
61243a51 308 m_bDoBreak = FALSE;
75f11ad7 309 }
0e320a79 310
61243a51
DW
311 if (pItem->IsSeparator())
312 {
760ac9ab 313 rItem.afStyle |= MIS_SEPARATOR;
75f11ad7
DW
314 }
315
61243a51
DW
316 //
317 // Id is the numeric id for normal menu items and HMENU for submenus as
c3cea748 318 // required by ::MM_INSERTITEM message API
61243a51 319 //
c5fb56c0 320
f23208ca 321 if (pSubmenu != NULL)
61243a51
DW
322 {
323 wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
324 pSubmenu->SetParent(this);
75f11ad7 325
760ac9ab 326 rItem.iPosition = 0; // submenus have a 0 position
c9667cda
DW
327 rItem.id = (USHORT)pSubmenu->GetHMenu();
328 rItem.afStyle |= MIS_SUBMENU | MIS_TEXT;
75f11ad7 329 }
61243a51
DW
330 else
331 {
760ac9ab 332 rItem.id = pItem->GetId();
75f11ad7
DW
333 }
334
61243a51 335 BYTE* pData;
75f11ad7
DW
336
337#if wxUSE_OWNER_DRAWN
61243a51
DW
338 if (pItem->IsOwnerDrawn())
339 {
340 //
341 // Want to get {Measure|Draw}Item messages?
45bedfdd 342 // item draws itself, passing pointer to data doesn't work in OS/2
c3cea748 343 // Will eventually need to set the image handle somewhere into vItem.hItem
61243a51 344 //
c9667cda
DW
345 rItem.afStyle |= MIS_OWNERDRAW;
346 pData = (BYTE*)NULL;
347 rItem.hItem = (HBITMAP)pItem->GetBitmap().GetHBITMAP();
45bedfdd 348 pItem->m_vMenuData.afStyle = rItem.afStyle;
c9667cda 349 pItem->m_vMenuData.hItem = rItem.hItem;
75f11ad7
DW
350 }
351 else
352#endif
353 {
61243a51
DW
354 //
355 // Menu is just a normal string (passed in data parameter)
356 //
760ac9ab 357 rItem.afStyle |= MIS_TEXT;
c5fb56c0 358 pData = (char*)pItem->GetText().c_str();
75f11ad7 359 }
c5fb56c0 360
f6bcfd97 361 if (nPos == (size_t)-1)
75f11ad7 362 {
f6bcfd97
BP
363 rItem.iPosition = MIT_END;
364 }
365 else
366 {
367 rItem.iPosition = nPos;
c5fb56c0
DW
368 }
369
f6bcfd97
BP
370 APIRET rc;
371
372 rc = (APIRET)::WinSendMsg( GetHmenu()
373 ,MM_INSERTITEM
374 ,(MPARAM)&rItem
375 ,(MPARAM)pData
376 );
45bedfdd
DW
377#if wxUSE_OWNER_DRAWN
378 if (pItem->IsOwnerDrawn())
379 {
380 BOOL rc;
381 MENUITEM vMenuItem;
382
383 ::WinSendMsg( GetHmenu()
384 ,MM_QUERYITEM
385 ,MPFROM2SHORT( (USHORT)pItem->GetId()
386 ,(USHORT)(FALSE)
387 )
388 ,&vMenuItem
389 );
390 }
391#endif
a0606634 392 if (rc == MIT_MEMERROR || rc == MIT_ERROR)
c5fb56c0 393 {
a0606634
DW
394 vError = ::WinGetLastError(vHabmain);
395 sError = wxPMErrorToStr(vError);
396 wxLogError("Error inserting or appending a menuitem. Error: %s\n", sError);
c5fb56c0 397 wxLogLastError("Insert or AppendMenu");
c5fb56c0
DW
398 return FALSE;
399 }
400 else
401 {
61243a51
DW
402 //
403 // If we're already attached to the menubar, we must update it
404 //
1ec46a5b 405 if (IsAttached() && m_menuBar->IsAttached())
c5fb56c0
DW
406 {
407 m_menuBar->Refresh();
408 }
c5fb56c0 409 return TRUE;
75f11ad7 410 }
c5fb56c0 411 return FALSE;
61243a51 412} // end of wxMenu::DoInsertOrAppend
0e320a79 413
598d8cac
DW
414void wxMenu::EndRadioGroup()
415{
416 //
417 // We're not inside a radio group any longer
418 //
419 m_nStartRadioGroup = -1;
420} // end of wxMenu::EndRadioGroup
421
61243a51
DW
422bool wxMenu::DoAppend(
423 wxMenuItem* pItem
424)
0e320a79 425{
f95255e2
DW
426 wxCHECK_MSG( pItem, FALSE, _T("NULL item in wxMenu::DoAppend") );
427
428 bool bCheck = FALSE;
429
430 if (pItem->GetKind() == wxITEM_RADIO)
431 {
432 int nCount = GetMenuItemCount();
433
ab4fece8 434 if (m_nStartRadioGroup == -1)
f95255e2
DW
435 {
436 //
437 // Start a new radio group
438 //
ab4fece8 439 m_nStartRadioGroup = nCount;
f95255e2
DW
440
441 //
442 // For now it has just one element
443 //
444 pItem->SetAsRadioGroupStart();
ab4fece8 445 pItem->SetRadioGroupEnd(m_nStartRadioGroup);
f95255e2
DW
446
447 //
448 // Ensure that we have a checked item in the radio group
449 //
450 bCheck = TRUE;
451 }
452 else // extend the current radio group
453 {
454 //
455 // We need to update its end item
456 //
ab4fece8 457 pItem->SetRadioGroupStart(m_nStartRadioGroup);
598d8cac 458
ab4fece8 459 wxMenuItemList::Node* pNode = GetMenuItems().Item(m_nStartRadioGroup);
f95255e2 460
ab4fece8 461 if (pNode)
f95255e2 462 {
ab4fece8 463 pNode->GetData()->SetRadioGroupEnd(nCount);
f95255e2
DW
464 }
465 else
466 {
467 wxFAIL_MSG( _T("where is the radio group start item?") );
468 }
469 }
470 }
471 else // not a radio item
472 {
473 EndRadioGroup();
474 }
598d8cac 475
f95255e2
DW
476 if (!wxMenuBase::DoAppend(pItem) || !DoInsertOrAppend(pItem))
477 {
478 return FALSE;
479 }
480 if (bCheck)
481 {
598d8cac
DW
482 //
483 // Check the item initially
484 //
f95255e2
DW
485 pItem->Check(TRUE);
486 }
487 return TRUE;
598d8cac 488} // end of wxMenu::DoAppend
0e320a79 489
61243a51
DW
490bool wxMenu::DoInsert(
491 size_t nPos
492, wxMenuItem* pItem
493)
0e320a79 494{
61243a51
DW
495 return ( wxMenuBase::DoInsert( nPos
496 ,pItem) &&
497 DoInsertOrAppend( pItem
498 ,nPos
598d8cac
DW
499 )
500 );
61243a51 501} // end of wxMenu::DoInsert
0e320a79 502
61243a51
DW
503wxMenuItem* wxMenu::DoRemove(
504 wxMenuItem* pItem
505)
0e320a79 506{
61243a51
DW
507 //
508 // We need to find the items position in the child list
509 //
510 size_t nPos;
511 wxMenuItemList::Node* pNode = GetMenuItems().GetFirst();
512
513 for (nPos = 0; pNode; nPos++)
75f11ad7 514 {
61243a51 515 if (pNode->GetData() == pItem)
75f11ad7 516 break;
61243a51 517 pNode = pNode->GetNext();
0e320a79
DW
518 }
519
61243a51 520 //
c5fb56c0 521 // DoRemove() (unlike Remove) can only be called for existing item!
61243a51
DW
522 //
523 wxCHECK_MSG(pNode, NULL, wxT("bug in wxMenu::Remove logic"));
75f11ad7 524
c5fb56c0 525#if wxUSE_ACCEL
61243a51
DW
526 //
527 // Remove the corresponding accel from the accel table
528 //
529 int n = FindAccel(pItem->GetId());
75f11ad7 530
61243a51 531 if (n != wxNOT_FOUND)
75f11ad7 532 {
61243a51 533 delete m_vAccels[n];
598d8cac 534 m_vAccels.RemoveAt(n);
c5fb56c0 535 }
61243a51
DW
536
537#endif // wxUSE_ACCEL
538 //
539 // Remove the item from the menu
540 //
541 ::WinSendMsg( GetHmenu()
542 ,MM_REMOVEITEM
543 ,MPFROM2SHORT(pItem->GetId(), TRUE)
544 ,(MPARAM)0
545 );
1ec46a5b 546 if (IsAttached() && m_menuBar->IsAttached())
61243a51
DW
547 {
548 //
549 // Otherwise, the chane won't be visible
550 //
c5fb56c0 551 m_menuBar->Refresh();
75f11ad7 552 }
0e320a79 553
61243a51
DW
554 //
555 // And from internal data structures
556 //
557 return wxMenuBase::DoRemove(pItem);
558} // end of wxMenu::DoRemove
0e320a79 559
75f11ad7
DW
560// ---------------------------------------------------------------------------
561// accelerator helpers
562// ---------------------------------------------------------------------------
563
c5fb56c0
DW
564#if wxUSE_ACCEL
565
61243a51
DW
566//
567// Create the wxAcceleratorEntries for our accels and put them into provided
75f11ad7 568// array - return the number of accels we have
61243a51
DW
569//
570size_t wxMenu::CopyAccels(
571 wxAcceleratorEntry* pAccels
572) const
75f11ad7 573{
61243a51
DW
574 size_t nCount = GetAccelCount();
575
576 for (size_t n = 0; n < nCount; n++)
75f11ad7 577 {
61243a51 578 *pAccels++ = *m_vAccels[n];
75f11ad7 579 }
61243a51
DW
580 return nCount;
581} // end of wxMenu::CopyAccels
0e320a79 582
75f11ad7
DW
583#endif // wxUSE_ACCEL
584
585// ---------------------------------------------------------------------------
c5fb56c0 586// set wxMenu title
75f11ad7
DW
587// ---------------------------------------------------------------------------
588
61243a51
DW
589void wxMenu::SetTitle(
590 const wxString& rLabel
591)
0e320a79 592{
61243a51
DW
593 bool bHasNoTitle = m_title.IsEmpty();
594 HWND hMenu = GetHmenu();
0e320a79 595
61243a51
DW
596 m_title = rLabel;
597 if (bHasNoTitle)
0e320a79 598 {
61243a51 599 if (!rLabel.IsEmpty())
75f11ad7 600 {
61243a51 601 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
75f11ad7 602 {
61243a51 603 wxLogLastError("SetMenuTitle");
75f11ad7
DW
604 }
605 }
0e320a79 606 }
75f11ad7 607 else
0e320a79 608 {
61243a51 609 if (rLabel.IsEmpty() )
0e320a79 610 {
61243a51
DW
611 ::WinSendMsg( GetHmenu()
612 ,MM_REMOVEITEM
613 ,MPFROM2SHORT(hMenu, TRUE)
614 ,(MPARAM)0
615 );
0e320a79 616 }
75f11ad7 617 else
0e320a79 618 {
61243a51
DW
619 //
620 // Modify the title
621 //
622 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
75f11ad7 623 {
61243a51 624 wxLogLastError("SetMenuTitle");
75f11ad7 625 }
0e320a79
DW
626 }
627 }
61243a51 628} // end of wxMenu::SetTitle
0e320a79 629
75f11ad7
DW
630// ---------------------------------------------------------------------------
631// event processing
632// ---------------------------------------------------------------------------
633
61243a51
DW
634bool wxMenu::OS2Command(
635 WXUINT WXUNUSED(uParam)
636, WXWORD vId
637)
0e320a79 638{
61243a51
DW
639 //
640 // Ignore commands from the menu title
641 //
75f11ad7 642
61243a51 643 if (vId != (WXWORD)idMenuTitle)
75f11ad7 644 {
0367c1c0
DW
645 SendEvent( vId
646 ,(int)::WinSendMsg( GetHmenu()
647 ,MM_QUERYITEMATTR
648 ,(MPARAM)vId
649 ,(MPARAM)MIA_CHECKED
650 )
651 );
61243a51 652 }
75f11ad7 653 return TRUE;
61243a51 654} // end of wxMenu::OS2Command
0e320a79 655
75f11ad7
DW
656// ---------------------------------------------------------------------------
657// other
658// ---------------------------------------------------------------------------
659
61243a51 660wxWindow* wxMenu::GetWindow() const
c5fb56c0 661{
61243a51 662 if (m_invokingWindow != NULL)
c5fb56c0
DW
663 return m_invokingWindow;
664 else if ( m_menuBar != NULL)
665 return m_menuBar->GetFrame();
666
667 return NULL;
61243a51 668} // end of wxMenu::GetWindow
0e320a79 669
45bedfdd
DW
670// recursive search for item by id
671wxMenuItem* wxMenu::FindItem(
672 int nItemId
673, ULONG hItem
674, wxMenu** ppItemMenu
675) const
676{
677 if ( ppItemMenu )
678 *ppItemMenu = NULL;
679
680 wxMenuItem* pItem = NULL;
681
682 for ( wxMenuItemList::Node *node = m_items.GetFirst();
683 node && !pItem;
684 node = node->GetNext() )
685 {
686 pItem = node->GetData();
687
688 if ( pItem->GetId() == nItemId && pItem->m_vMenuData.hItem == hItem)
689 {
690 if ( ppItemMenu )
691 *ppItemMenu = (wxMenu *)this;
692 }
693 else if ( pItem->IsSubMenu() )
694 {
72594e90
DW
695 pItem = pItem->GetSubMenu()->FindItem( nItemId
696 ,hItem
697 ,ppItemMenu
698 );
699 if (pItem)
700 break;
45bedfdd
DW
701 }
702 else
703 {
704 // don't exit the loop
705 pItem = NULL;
706 }
707 }
708 return pItem;
709} // end of wxMenu::FindItem
710
75f11ad7 711// ---------------------------------------------------------------------------
0e320a79 712// Menu Bar
75f11ad7
DW
713// ---------------------------------------------------------------------------
714
715void wxMenuBar::Init()
0e320a79
DW
716{
717 m_eventHandler = this;
e58dab20 718 m_menuBarFrame = NULL;
75f11ad7 719 m_hMenu = 0;
61243a51 720} // end of wxMenuBar::Init
0e320a79 721
75f11ad7
DW
722wxMenuBar::wxMenuBar()
723{
724 Init();
61243a51 725} // end of wxMenuBar::wxMenuBar
0e320a79 726
61243a51
DW
727wxMenuBar::wxMenuBar(
728 long WXUNUSED(lStyle)
729)
0e320a79 730{
75f11ad7 731 Init();
61243a51 732} // end of wxMenuBar::wxMenuBar
75f11ad7 733
61243a51
DW
734wxMenuBar::wxMenuBar(
735 int nCount
736, wxMenu* vMenus[]
737, const wxString sTitles[]
738)
75f11ad7
DW
739{
740 Init();
741
61243a51
DW
742 m_titles.Alloc(nCount);
743 for ( int i = 0; i < nCount; i++ )
c5fb56c0 744 {
61243a51
DW
745 m_menus.Append(vMenus[i]);
746 m_titles.Add(sTitles[i]);
747 vMenus[i]->Attach(this);
c5fb56c0 748 }
61243a51 749} // end of wxMenuBar::wxMenuBar
0e320a79
DW
750
751wxMenuBar::~wxMenuBar()
752{
61243a51 753} // end of wxMenuBar::~wxMenuBar
0e320a79 754
75f11ad7
DW
755// ---------------------------------------------------------------------------
756// wxMenuBar helpers
757// ---------------------------------------------------------------------------
758
61243a51 759void wxMenuBar::Refresh()
75f11ad7 760{
c5fb56c0 761 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
75f11ad7 762
e58dab20 763 WinSendMsg(GetWinHwnd(m_menuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
f23208ca 764} // end of wxMenuBar::Refresh
75f11ad7
DW
765
766WXHMENU wxMenuBar::Create()
767{
61243a51 768 MENUITEM vItem;
f23208ca 769 HWND hFrame;
61243a51 770
75f11ad7 771 if (m_hMenu != 0 )
c5fb56c0 772 return m_hMenu;
75f11ad7 773
61243a51
DW
774 wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
775
f23208ca
DW
776 //
777 // Menubars should be associated with a frame otherwise they are popups
778 //
e58dab20
DW
779 if (m_menuBarFrame != NULL)
780 hFrame = GetWinHwnd(m_menuBarFrame);
f23208ca
DW
781 else
782 hFrame = HWND_DESKTOP;
61243a51
DW
783 //
784 // Create an empty menu and then fill it with insertions
785 //
f6bcfd97
BP
786 if ((m_hMenu = ::WinCreateWindow( hFrame
787 ,WC_MENU
788 ,(PSZ)NULL
789 ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
790 ,0L
791 ,0L
792 ,0L
793 ,0L
794 ,hFrame
795 ,HWND_TOP
796 ,FID_MENU
797 ,NULL
798 ,NULL
799 )) == 0)
75f11ad7 800 {
f6bcfd97 801 wxLogLastError("WinLoadMenu");
75f11ad7
DW
802 }
803 else
804 {
61243a51
DW
805 size_t nCount = GetMenuCount();
806
807 for (size_t i = 0; i < nCount; i++)
75f11ad7 808 {
c0dbf1fb
DW
809 APIRET rc;
810 ERRORID vError;
811 wxString sError;
f6bcfd97 812 HWND hSubMenu;
c3cea748
DW
813
814 //
815 // Set the parent and owner of the submenues to be the menubar, not the desktop
816 //
f6bcfd97
BP
817 hSubMenu = m_menus[i]->m_vMenuData.hwndSubMenu;
818 if (!::WinSetParent(m_menus[i]->m_vMenuData.hwndSubMenu, m_hMenu, FALSE))
c3cea748
DW
819 {
820 vError = ::WinGetLastError(vHabmain);
821 sError = wxPMErrorToStr(vError);
822 wxLogError("Error setting parent for submenu. Error: %s\n", sError);
823 return NULLHANDLE;
824 }
825
f6bcfd97 826 if (!::WinSetOwner(m_menus[i]->m_vMenuData.hwndSubMenu, m_hMenu))
c3cea748
DW
827 {
828 vError = ::WinGetLastError(vHabmain);
829 sError = wxPMErrorToStr(vError);
830 wxLogError("Error setting parent for submenu. Error: %s\n", sError);
831 return NULLHANDLE;
832 }
c0dbf1fb 833
dae16775
DW
834 m_menus[i]->m_vMenuData.iPosition = i;
835
f6bcfd97 836 rc = (APIRET)::WinSendMsg(m_hMenu, MM_INSERTITEM, (MPARAM)&m_menus[i]->m_vMenuData, (MPARAM)m_titles[i].c_str());
c0dbf1fb
DW
837 if (rc == MIT_MEMERROR || rc == MIT_ERROR)
838 {
839 vError = ::WinGetLastError(vHabmain);
840 sError = wxPMErrorToStr(vError);
841 wxLogError("Error inserting or appending a menuitem. Error: %s\n", sError);
842 return NULLHANDLE;
843 }
75f11ad7
DW
844 }
845 }
f6bcfd97 846 return m_hMenu;
61243a51 847} // end of wxMenuBar::Create
0e320a79 848
75f11ad7 849// ---------------------------------------------------------------------------
c5fb56c0 850// wxMenuBar functions to work with the top level submenus
75f11ad7
DW
851// ---------------------------------------------------------------------------
852
61243a51 853//
c5fb56c0
DW
854// NB: we don't support owner drawn top level items for now, if we do these
855// functions would have to be changed to use wxMenuItem as well
61243a51
DW
856//
857void wxMenuBar::EnableTop(
858 size_t nPos
859, bool bEnable
860)
0e320a79 861{
61243a51
DW
862 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
863 USHORT uFlag = 0;
864 SHORT nId;
0e320a79 865
61243a51
DW
866 if(!bEnable)
867 uFlag = MIA_DISABLED;
75f11ad7 868
61243a51
DW
869 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
870 if (nId == MIT_ERROR)
871 {
872 wxLogLastError("LogLastError");
873 return;
874 }
f6bcfd97 875 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(MIA_DISABLED, uFlag));
c5fb56c0 876 Refresh();
61243a51 877} // end of wxMenuBar::EnableTop
75f11ad7 878
61243a51
DW
879void wxMenuBar::SetLabelTop(
880 size_t nPos
881, const wxString& rLabel
882)
75f11ad7 883{
61243a51
DW
884 SHORT nId;
885 MENUITEM vItem;
75f11ad7 886
61243a51
DW
887 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
888 m_titles[nPos] = rLabel;
75f11ad7 889
61243a51 890 if (!IsAttached())
c5fb56c0
DW
891 {
892 return;
893 }
75f11ad7 894
61243a51
DW
895 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
896 if (nId == MIT_ERROR)
75f11ad7 897 {
61243a51 898 wxLogLastError("LogLastError");
75f11ad7
DW
899 return;
900 }
61243a51
DW
901 if(!::WinSendMsg( (HWND)m_hMenu
902 ,MM_QUERYITEM
903 ,MPFROM2SHORT(nId, TRUE)
904 ,MPARAM(&vItem)
905 ))
75f11ad7 906 {
61243a51 907 wxLogLastError("QueryItem");
c5fb56c0 908 }
61243a51 909 nId = vItem.id;
c5fb56c0 910
61243a51 911 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
c5fb56c0
DW
912 {
913 wxLogLastError("ModifyMenu");
75f11ad7 914 }
c5fb56c0 915 Refresh();
61243a51 916} // end of wxMenuBar::SetLabelTop
0e320a79 917
61243a51
DW
918wxString wxMenuBar::GetLabelTop(
919 size_t nPos
920) const
0e320a79 921{
61243a51 922 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
c5fb56c0 923 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
61243a51
DW
924 return m_titles[nPos];
925} // end of wxMenuBar::GetLabelTop
75f11ad7 926
c5fb56c0
DW
927// ---------------------------------------------------------------------------
928// wxMenuBar construction
929// ---------------------------------------------------------------------------
75f11ad7 930
61243a51
DW
931wxMenu* wxMenuBar::Replace(
932 size_t nPos
933, wxMenu* pMenu
934, const wxString& rTitle
935)
75f11ad7 936{
61243a51 937 SHORT nId;
c9667cda 938 wxString sTitle = TextToLabel(rTitle);
61243a51
DW
939 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
940 ,pMenu
c9667cda 941 ,sTitle
61243a51
DW
942 );
943
944
945 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
946 if (nId == MIT_ERROR)
947 {
948 wxLogLastError("LogLastError");
949 return NULL;
950 }
951 if (!pMenuOld)
c9667cda
DW
952 return NULL;
953 m_titles[nPos] = sTitle;
61243a51 954 if (IsAttached())
75f11ad7 955 {
f6bcfd97 956 ::WinSendMsg((HWND)m_hMenu, MM_REMOVEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
c9667cda 957 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
c5fb56c0
DW
958
959#if wxUSE_ACCEL
61243a51 960 if (pMenuOld->HasAccels() || pMenu->HasAccels())
c5fb56c0 961 {
61243a51
DW
962 //
963 // Need to rebuild accell table
964 //
c5fb56c0
DW
965 RebuildAccelTable();
966 }
967#endif // wxUSE_ACCEL
c5fb56c0
DW
968 Refresh();
969 }
61243a51
DW
970 return pMenuOld;
971} // end of wxMenuBar::Replace
75f11ad7 972
61243a51
DW
973bool wxMenuBar::Insert(
974 size_t nPos
975, wxMenu* pMenu
976, const wxString& rTitle
977)
75f11ad7 978{
c9667cda
DW
979 wxString sTitle = TextToLabel(rTitle);
980
61243a51
DW
981 if (!wxMenuBarBase::Insert( nPos
982 ,pMenu
c9667cda 983 ,sTitle
61243a51 984 ))
c5fb56c0 985 return FALSE;
75f11ad7 986
c9667cda 987 m_titles.Insert( sTitle
61243a51
DW
988 ,nPos
989 );
75f11ad7 990
61243a51
DW
991 if (IsAttached())
992 {
c9667cda
DW
993 pMenu->m_vMenuData.iPosition = nPos;
994 ::WinSendMsg( (HWND)m_hMenu
995 ,MM_INSERTITEM
996 ,(MPARAM)&pMenu->m_vMenuData
997 ,(MPARAM)sTitle.c_str()
998 );
c5fb56c0 999#if wxUSE_ACCEL
61243a51 1000 if (pMenu->HasAccels())
c5fb56c0
DW
1001 {
1002 // need to rebuild accell table
1003 RebuildAccelTable();
1004 }
1005#endif // wxUSE_ACCEL
c5fb56c0 1006 Refresh();
75f11ad7 1007 }
c5fb56c0 1008 return TRUE;
61243a51 1009} // end of wxMenuBar::Insert
75f11ad7 1010
61243a51
DW
1011bool wxMenuBar::Append(
1012 wxMenu* pMenu
c9667cda 1013, const wxString& rsTitle
61243a51 1014)
0e320a79 1015{
61243a51
DW
1016 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
1017
1018 wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
0e320a79 1019
c9667cda
DW
1020 wxString sTitle = TextToLabel(rsTitle);
1021
1022 if (!wxMenuBarBase::Append(pMenu, sTitle))
c5fb56c0 1023 return FALSE;
0e320a79 1024
c9667cda 1025 m_titles.Add(sTitle);
c5fb56c0 1026
c5fb56c0 1027 if ( IsAttached() )
0e320a79 1028 {
61243a51 1029 pMenu->m_vMenuData.iPosition = MIT_END;
c9667cda 1030 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
c5fb56c0 1031#if wxUSE_ACCEL
61243a51 1032 if (pMenu->HasAccels())
c5fb56c0 1033 {
61243a51
DW
1034 //
1035 // Need to rebuild accell table
1036 //
c5fb56c0
DW
1037 RebuildAccelTable();
1038 }
1039#endif // wxUSE_ACCEL
c5fb56c0
DW
1040 Refresh();
1041 }
c5fb56c0 1042 return TRUE;
61243a51 1043} // end of wxMenuBar::Append
0e320a79 1044
61243a51
DW
1045wxMenu* wxMenuBar::Remove(
1046 size_t nPos
1047)
0e320a79 1048{
61243a51
DW
1049 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
1050 SHORT nId;
1051
1052 if (!pMenu)
c5fb56c0 1053 return NULL;
0e320a79 1054
c9667cda
DW
1055 nId = SHORT1FROMMR(::WinSendMsg( (HWND)GetHmenu()
1056 ,MM_ITEMIDFROMPOSITION
1057 ,MPFROMSHORT(nPos)
1058 ,(MPARAM)0)
1059 );
61243a51
DW
1060 if (nId == MIT_ERROR)
1061 {
1062 wxLogLastError("LogLastError");
1063 return NULL;
1064 }
1065 if (IsAttached())
1066 {
c9667cda
DW
1067 ::WinSendMsg( (HWND)GetHmenu()
1068 ,MM_REMOVEITEM
1069 ,MPFROM2SHORT(nId, TRUE)
1070 ,(MPARAM)0
1071 );
0e320a79 1072
c5fb56c0 1073#if wxUSE_ACCEL
61243a51 1074 if (pMenu->HasAccels())
c5fb56c0 1075 {
61243a51
DW
1076 //
1077 // Need to rebuild accell table
1078 //
c5fb56c0
DW
1079 RebuildAccelTable();
1080 }
1081#endif // wxUSE_ACCEL
c5fb56c0 1082 Refresh();
0e320a79 1083 }
61243a51
DW
1084 m_titles.Remove(nPos);
1085 return pMenu;
1086} // end of wxMenuBar::Remove
75f11ad7
DW
1087
1088#if wxUSE_ACCEL
c5fb56c0
DW
1089
1090void wxMenuBar::RebuildAccelTable()
1091{
61243a51
DW
1092 //
1093 // Merge the accelerators of all menus into one accel table
1094 //
1095 size_t nAccelCount = 0;
1096 size_t i;
1097 size_t nCount = GetMenuCount();
1098
1099 for (i = 0; i < nCount; i++)
75f11ad7
DW
1100 {
1101 nAccelCount += m_menus[i]->GetAccelCount();
1102 }
1103
61243a51 1104 if (nAccelCount)
0e320a79 1105 {
61243a51 1106 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
75f11ad7
DW
1107
1108 nAccelCount = 0;
61243a51 1109 for (i = 0; i < nCount; i++)
75f11ad7 1110 {
61243a51 1111 nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
75f11ad7 1112 }
61243a51
DW
1113 m_vAccelTable = wxAcceleratorTable( nAccelCount
1114 ,pAccelEntries
1115 );
1116 delete [] pAccelEntries;
0e320a79 1117 }
61243a51 1118} // end of wxMenuBar::RebuildAccelTable
c5fb56c0
DW
1119
1120#endif // wxUSE_ACCEL
1121
61243a51
DW
1122void wxMenuBar::Attach(
1123 wxFrame* pFrame
1124)
c5fb56c0 1125{
598d8cac 1126 wxMenuBarBase::Attach(pFrame);
c5fb56c0
DW
1127
1128#if wxUSE_ACCEL
1129 RebuildAccelTable();
f6bcfd97
BP
1130 //
1131 // Ensure the accelerator table is set to the frame (not the client!)
1132 //
1133 if (!::WinSetAccelTable( vHabmain
f6bcfd97 1134 ,m_vAccelTable.GetHACCEL()
598d8cac 1135 ,(HWND)pFrame->GetFrame()
f6bcfd97
BP
1136 ))
1137 wxLogLastError("WinSetAccelTable");
75f11ad7 1138#endif // wxUSE_ACCEL
61243a51 1139} // end of wxMenuBar::Attach
0e320a79 1140
75f11ad7 1141void wxMenuBar::Detach()
0e320a79 1142{
61243a51 1143 ::WinDestroyWindow((HWND)m_hMenu);
c5fb56c0 1144 m_hMenu = (WXHMENU)NULL;
e58dab20 1145 m_menuBarFrame = NULL;
61243a51 1146} // end of wxMenuBar::Detach
75f11ad7
DW
1147
1148// ---------------------------------------------------------------------------
1149// wxMenuBar searching for menu items
1150// ---------------------------------------------------------------------------
1151
61243a51 1152//
75f11ad7 1153// Find the itemString in menuString, and return the item id or wxNOT_FOUND
61243a51
DW
1154//
1155int wxMenuBar::FindMenuItem(
1156 const wxString& rMenuString
1157, const wxString& rItemString
1158) const
75f11ad7 1159{
61243a51
DW
1160 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
1161 size_t nCount = GetMenuCount();
1162
1163 for (size_t i = 0; i < nCount; i++)
75f11ad7 1164 {
61243a51 1165 wxString sTitle = wxStripMenuCodes(m_titles[i]);
75f11ad7 1166
61243a51
DW
1167 if (rMenuString == sTitle)
1168 return m_menus[i]->FindItem(rItemString);
1169 }
75f11ad7 1170 return wxNOT_FOUND;
61243a51 1171} // end of wxMenuBar::FindMenuItem
75f11ad7 1172
61243a51
DW
1173wxMenuItem* wxMenuBar::FindItem(
1174 int nId
1175, wxMenu** ppItemMenu
1176) const
75f11ad7 1177{
61243a51
DW
1178 if (ppItemMenu)
1179 *ppItemMenu = NULL;
1180
1181 wxMenuItem* pItem = NULL;
1182 size_t nCount = GetMenuCount();
0e320a79 1183
61243a51 1184 for (size_t i = 0; !pItem && (i < nCount); i++)
75f11ad7 1185 {
61243a51
DW
1186 pItem = m_menus[i]->FindItem( nId
1187 ,ppItemMenu
1188 );
75f11ad7 1189 }
61243a51
DW
1190 return pItem;
1191} // end of wxMenuBar::FindItem
75f11ad7 1192
45bedfdd
DW
1193wxMenuItem* wxMenuBar::FindItem(
1194 int nId
1195, ULONG hItem
1196, wxMenu** ppItemMenu
1197) const
1198{
1199 if (ppItemMenu)
1200 *ppItemMenu = NULL;
1201
1202 wxMenuItem* pItem = NULL;
1203 size_t nCount = GetMenuCount();
1204
1205 for (size_t i = 0; !pItem && (i < nCount); i++)
1206 {
1207 pItem = m_menus[i]->FindItem( nId
1208 ,hItem
1209 ,ppItemMenu
1210 );
1211 }
1212 return pItem;
1213} // end of wxMenuBar::FindItem
dae16775 1214