]> git.saurik.com Git - wxWidgets.git/blame - src/os2/menu.cpp
Found bug that skrewed up display wrt horizontal
[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
DW
251 m_vMenuData.id = (USHORT)pSubmenu->GetHMenu();
252 m_vMenuData.afStyle |= MIS_SUBMENU;
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 {
a0606634 660 ::WinSendMsg(hMenuBar, MM_INSERTITEM, (MPARAM)&m_menus[i]->m_vMenuData, (MPARAM)m_titles[i].c_str());
75f11ad7
DW
661 }
662 }
a0606634 663 return hMenuBar;
61243a51 664} // end of wxMenuBar::Create
0e320a79 665
75f11ad7 666// ---------------------------------------------------------------------------
c5fb56c0 667// wxMenuBar functions to work with the top level submenus
75f11ad7
DW
668// ---------------------------------------------------------------------------
669
61243a51 670//
c5fb56c0
DW
671// NB: we don't support owner drawn top level items for now, if we do these
672// functions would have to be changed to use wxMenuItem as well
61243a51
DW
673//
674void wxMenuBar::EnableTop(
675 size_t nPos
676, bool bEnable
677)
0e320a79 678{
61243a51
DW
679 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
680 USHORT uFlag = 0;
681 SHORT nId;
0e320a79 682
61243a51
DW
683 if(!bEnable)
684 uFlag = MIA_DISABLED;
75f11ad7 685
61243a51
DW
686 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
687 if (nId == MIT_ERROR)
688 {
689 wxLogLastError("LogLastError");
690 return;
691 }
692 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(uFlag, uFlag));
c5fb56c0 693 Refresh();
61243a51 694} // end of wxMenuBar::EnableTop
75f11ad7 695
61243a51
DW
696void wxMenuBar::SetLabelTop(
697 size_t nPos
698, const wxString& rLabel
699)
75f11ad7 700{
61243a51
DW
701 SHORT nId;
702 MENUITEM vItem;
75f11ad7 703
61243a51
DW
704 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
705 m_titles[nPos] = rLabel;
75f11ad7 706
61243a51 707 if (!IsAttached())
c5fb56c0
DW
708 {
709 return;
710 }
75f11ad7 711
61243a51
DW
712 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
713 if (nId == MIT_ERROR)
75f11ad7 714 {
61243a51 715 wxLogLastError("LogLastError");
75f11ad7
DW
716 return;
717 }
61243a51
DW
718 if(!::WinSendMsg( (HWND)m_hMenu
719 ,MM_QUERYITEM
720 ,MPFROM2SHORT(nId, TRUE)
721 ,MPARAM(&vItem)
722 ))
75f11ad7 723 {
61243a51 724 wxLogLastError("QueryItem");
c5fb56c0 725 }
61243a51 726 nId = vItem.id;
c5fb56c0 727
61243a51 728 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
c5fb56c0
DW
729 {
730 wxLogLastError("ModifyMenu");
75f11ad7 731 }
c5fb56c0 732 Refresh();
61243a51 733} // end of wxMenuBar::SetLabelTop
0e320a79 734
61243a51
DW
735wxString wxMenuBar::GetLabelTop(
736 size_t nPos
737) const
0e320a79 738{
61243a51 739 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
c5fb56c0 740 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
61243a51
DW
741 return m_titles[nPos];
742} // end of wxMenuBar::GetLabelTop
75f11ad7 743
c5fb56c0
DW
744// ---------------------------------------------------------------------------
745// wxMenuBar construction
746// ---------------------------------------------------------------------------
75f11ad7 747
61243a51
DW
748wxMenu* wxMenuBar::Replace(
749 size_t nPos
750, wxMenu* pMenu
751, const wxString& rTitle
752)
75f11ad7 753{
61243a51
DW
754 SHORT nId;
755 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
756 ,pMenu
757 ,rTitle
758 );
759
760
761 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
762 if (nId == MIT_ERROR)
763 {
764 wxLogLastError("LogLastError");
765 return NULL;
766 }
767 if (!pMenuOld)
c5fb56c0 768 return FALSE;
61243a51
DW
769 m_titles[nPos] = rTitle;
770 if (IsAttached())
75f11ad7 771 {
61243a51
DW
772 ::WinSendMsg((HWND)m_hMenu, MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
773 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
c5fb56c0
DW
774
775#if wxUSE_ACCEL
61243a51 776 if (pMenuOld->HasAccels() || pMenu->HasAccels())
c5fb56c0 777 {
61243a51
DW
778 //
779 // Need to rebuild accell table
780 //
c5fb56c0
DW
781 RebuildAccelTable();
782 }
783#endif // wxUSE_ACCEL
c5fb56c0
DW
784 Refresh();
785 }
61243a51
DW
786 return pMenuOld;
787} // end of wxMenuBar::Replace
75f11ad7 788
61243a51
DW
789bool wxMenuBar::Insert(
790 size_t nPos
791, wxMenu* pMenu
792, const wxString& rTitle
793)
75f11ad7 794{
61243a51
DW
795 if (!wxMenuBarBase::Insert( nPos
796 ,pMenu
797 ,rTitle
798 ))
c5fb56c0 799 return FALSE;
75f11ad7 800
61243a51
DW
801 m_titles.Insert( rTitle
802 ,nPos
803 );
75f11ad7 804
61243a51 805 pMenu->Attach(this);
75f11ad7 806
61243a51
DW
807 if (IsAttached())
808 {
809 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
c5fb56c0 810#if wxUSE_ACCEL
61243a51 811 if (pMenu->HasAccels())
c5fb56c0
DW
812 {
813 // need to rebuild accell table
814 RebuildAccelTable();
815 }
816#endif // wxUSE_ACCEL
c5fb56c0 817 Refresh();
75f11ad7 818 }
c5fb56c0 819 return TRUE;
61243a51 820} // end of wxMenuBar::Insert
75f11ad7 821
61243a51
DW
822bool wxMenuBar::Append(
823 wxMenu* pMenu
824, const wxString& rTitle
825)
0e320a79 826{
61243a51
DW
827 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
828
829 wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
0e320a79 830
61243a51 831 if (!wxMenuBarBase::Append(pMenu, rTitle))
c5fb56c0 832 return FALSE;
0e320a79 833
61243a51
DW
834 pMenu->Attach(this);
835 m_titles.Add(rTitle);
c5fb56c0 836
c5fb56c0 837 if ( IsAttached() )
0e320a79 838 {
61243a51
DW
839 pMenu->m_vMenuData.iPosition = MIT_END;
840 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
c5fb56c0 841#if wxUSE_ACCEL
61243a51 842 if (pMenu->HasAccels())
c5fb56c0 843 {
61243a51
DW
844 //
845 // Need to rebuild accell table
846 //
c5fb56c0
DW
847 RebuildAccelTable();
848 }
849#endif // wxUSE_ACCEL
c5fb56c0
DW
850 Refresh();
851 }
c5fb56c0 852 return TRUE;
61243a51 853} // end of wxMenuBar::Append
0e320a79 854
61243a51
DW
855wxMenu* wxMenuBar::Remove(
856 size_t nPos
857)
0e320a79 858{
61243a51
DW
859 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
860 SHORT nId;
861
862 if (!pMenu)
c5fb56c0 863 return NULL;
0e320a79 864
61243a51
DW
865 nId = SHORT1FROMMR(::WinSendMsg((HWND)GetHmenu(), MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
866 if (nId == MIT_ERROR)
867 {
868 wxLogLastError("LogLastError");
869 return NULL;
870 }
871 if (IsAttached())
872 {
873 ::WinSendMsg((HWND)GetHmenu(), MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
874 pMenu->Detach();
0e320a79 875
c5fb56c0 876#if wxUSE_ACCEL
61243a51 877 if (pMenu->HasAccels())
c5fb56c0 878 {
61243a51
DW
879 //
880 // Need to rebuild accell table
881 //
c5fb56c0
DW
882 RebuildAccelTable();
883 }
884#endif // wxUSE_ACCEL
c5fb56c0 885 Refresh();
0e320a79 886 }
61243a51
DW
887 m_titles.Remove(nPos);
888 return pMenu;
889} // end of wxMenuBar::Remove
75f11ad7
DW
890
891#if wxUSE_ACCEL
c5fb56c0
DW
892
893void wxMenuBar::RebuildAccelTable()
894{
61243a51
DW
895 //
896 // Merge the accelerators of all menus into one accel table
897 //
898 size_t nAccelCount = 0;
899 size_t i;
900 size_t nCount = GetMenuCount();
901
902 for (i = 0; i < nCount; i++)
75f11ad7
DW
903 {
904 nAccelCount += m_menus[i]->GetAccelCount();
905 }
906
61243a51 907 if (nAccelCount)
0e320a79 908 {
61243a51 909 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
75f11ad7
DW
910
911 nAccelCount = 0;
61243a51 912 for (i = 0; i < nCount; i++)
75f11ad7 913 {
61243a51 914 nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
75f11ad7 915 }
61243a51
DW
916 m_vAccelTable = wxAcceleratorTable( nAccelCount
917 ,pAccelEntries
918 );
919 delete [] pAccelEntries;
0e320a79 920 }
61243a51 921} // end of wxMenuBar::RebuildAccelTable
c5fb56c0
DW
922
923#endif // wxUSE_ACCEL
924
61243a51
DW
925void wxMenuBar::Attach(
926 wxFrame* pFrame
927)
c5fb56c0
DW
928{
929 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
61243a51 930 m_pMenuBarFrame = pFrame;
c5fb56c0
DW
931
932#if wxUSE_ACCEL
933 RebuildAccelTable();
75f11ad7 934#endif // wxUSE_ACCEL
61243a51 935} // end of wxMenuBar::Attach
0e320a79 936
75f11ad7 937void wxMenuBar::Detach()
0e320a79 938{
61243a51 939 ::WinDestroyWindow((HWND)m_hMenu);
c5fb56c0 940 m_hMenu = (WXHMENU)NULL;
61243a51
DW
941 m_pMenuBarFrame = NULL;
942} // end of wxMenuBar::Detach
75f11ad7
DW
943
944// ---------------------------------------------------------------------------
945// wxMenuBar searching for menu items
946// ---------------------------------------------------------------------------
947
61243a51 948//
75f11ad7 949// Find the itemString in menuString, and return the item id or wxNOT_FOUND
61243a51
DW
950//
951int wxMenuBar::FindMenuItem(
952 const wxString& rMenuString
953, const wxString& rItemString
954) const
75f11ad7 955{
61243a51
DW
956 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
957 size_t nCount = GetMenuCount();
958
959 for (size_t i = 0; i < nCount; i++)
75f11ad7 960 {
61243a51 961 wxString sTitle = wxStripMenuCodes(m_titles[i]);
75f11ad7 962
61243a51
DW
963 if (rMenuString == sTitle)
964 return m_menus[i]->FindItem(rItemString);
965 }
75f11ad7 966 return wxNOT_FOUND;
61243a51 967} // end of wxMenuBar::FindMenuItem
75f11ad7 968
61243a51
DW
969wxMenuItem* wxMenuBar::FindItem(
970 int nId
971, wxMenu** ppItemMenu
972) const
75f11ad7 973{
61243a51
DW
974 if (ppItemMenu)
975 *ppItemMenu = NULL;
976
977 wxMenuItem* pItem = NULL;
978 size_t nCount = GetMenuCount();
0e320a79 979
61243a51 980 for (size_t i = 0; !pItem && (i < nCount); i++)
75f11ad7 981 {
61243a51
DW
982 pItem = m_menus[i]->FindItem( nId
983 ,ppItemMenu
984 );
75f11ad7 985 }
61243a51
DW
986 return pItem;
987} // end of wxMenuBar::FindItem
75f11ad7 988