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