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