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