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