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