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