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