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