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