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