]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menu.cpp
wxExecute() fixes and doc updates: the return value for sync exec case is now
[wxWidgets.git] / src / msw / menu.cpp
CommitLineData
2bda0e17
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
4// Author: Julian Smart
5// Modified by: Vadim Zeitlin
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
2bda0e17 12#ifdef __GNUG__
a3b46648 13#pragma implementation "menu.h"
2bda0e17
KB
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
23#ifndef WX_PRECOMP
24#include "wx/frame.h"
25#include "wx/menu.h"
26#include "wx/utils.h"
27#endif
28
47d67540 29#if wxUSE_OWNER_DRAWN
b8d3a4f1 30 #include "wx/ownerdrw.h"
2bda0e17
KB
31#endif
32
33#include "wx/msw/private.h"
34#include "wx/msw/menu.h"
35#include "wx/menuitem.h"
36#include "wx/log.h"
37
38// other standard headers
39// ----------------------
40#include <string.h>
41
b8d3a4f1
VZ
42// ----------------------------------------------------------------------------
43// constants
44// ----------------------------------------------------------------------------
45
46// the (popup) menu title has this special id
47static const int idMenuTitle = -2;
48
49// ----------------------------------------------------------------------------
50// wxWindows macros
51// ----------------------------------------------------------------------------
2bda0e17 52#if !USE_SHARED_LIBRARY
b8d3a4f1
VZ
53 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
54 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
2bda0e17
KB
55#endif
56
57// ============================================================================
58// implementation
59// ============================================================================
60
61// Menus
62
63// Construct a menu with optional title (then use append)
64wxMenu::wxMenu(const wxString& Title, const wxFunction func)
65{
66 m_title = Title;
67 m_parent = NULL;
68 m_eventHandler = this;
69 m_pInvokingWindow = NULL;
70 m_doBreak = FALSE ;
71 m_noItems = 0;
72 m_menuBar = NULL;
73 m_hMenu = (WXHMENU) CreatePopupMenu();
74 m_savehMenu = 0 ;
75 m_topLevelMenu = this;
3dd4e4e0
JS
76 m_clientData = (void*) NULL;
77
2bda0e17
KB
78 if (m_title != "")
79 {
b8d3a4f1 80 Append(idMenuTitle, m_title) ;
2bda0e17
KB
81 AppendSeparator() ;
82 }
83
84 Callback(func);
85}
86
87// The wxWindow destructor will take care of deleting the submenus.
b8d3a4f1 88wxMenu::~wxMenu()
2bda0e17
KB
89{
90 if (m_hMenu)
91 DestroyMenu((HMENU) m_hMenu);
92 m_hMenu = 0;
93
94 // Windows seems really bad on Menu de-allocation...
95 // After many try, here is what I do: RemoveMenu() will ensure
96 // that popup are "disconnected" from their parent; then call
97 // delete method on each child (which in turn do a recursive job),
98 // and finally, DestroyMenu()
99 //
100 // With that, BoundCheckers is happy, and no complaints...
101/*
102 int N = 0 ;
103 if (m_hMenu)
104 N = GetMenuItemCount(m_hMenu);
105 int i;
106 for (i = N-1; i >= 0; i--)
107 RemoveMenu(m_hMenu, i, MF_BYPOSITION);
108*/
109
110 // How is deleting submenus in this loop any different from deleting
111 // the submenus in the children list, via ~wxWindow ?
112 // I'll reinstate this deletion for now and remove addition
113 // from children list (which doesn't exist now)
114 // Julian 1/3/97
115 wxNode *node = m_menuItems.First();
116 while (node)
117 {
118 wxMenuItem *item = (wxMenuItem *)node->Data();
119
120 // Delete child menus.
121 // Beware: they must not be appended to children list!!!
122 // (because order of delete is significant)
123 if (item->GetSubMenu())
124 item->DeleteSubMenu();
125
126 wxNode *next = node->Next();
127 delete item;
128 delete node;
129 node = next;
130 }
131/*
132 if (m_hMenu)
133 DestroyMenu(m_hMenu);
134 m_hMenu = 0;
135*/
136}
137
b8d3a4f1 138void wxMenu::Break()
2bda0e17
KB
139{
140 m_doBreak = TRUE ;
141}
142
143// function appends a new item or submenu to the menu
144void wxMenu::Append(wxMenuItem *pItem)
145{
1311c7a9 146 wxCHECK_RET( pItem != NULL, "can't append NULL item to the menu" );
2bda0e17
KB
147
148 m_menuItems.Append(pItem);
149
150 UINT flags = 0;
151
152 if ( m_doBreak ) {
153 flags |= MF_MENUBREAK;
154 m_doBreak = FALSE;
155 }
156
157 if ( pItem->IsSeparator() ) {
158 flags |= MF_SEPARATOR;
159 }
160
161 // id is the numeric id for normal menu items and HMENU for submenus
162 UINT id;
163 wxMenu *SubMenu = pItem->GetSubMenu();
164 if ( SubMenu != NULL ) {
cfe780fb 165 wxASSERT( SubMenu->m_hMenu != (WXHMENU) NULL );
2bda0e17
KB
166
167 id = (UINT)SubMenu->m_hMenu;
168
169 SubMenu->m_topLevelMenu = m_topLevelMenu;
170 SubMenu->m_parent = this;
171 SubMenu->m_savehMenu = (WXHMENU)id;
172 SubMenu->m_hMenu = 0;
173
174 flags |= MF_POPUP;
175 }
176 else {
177 id = pItem->GetId();
178 }
179
180 LPCSTR pData;
2bda0e17 181
47d67540 182#if wxUSE_OWNER_DRAWN
2bda0e17
KB
183 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
184 // item draws itself, pass pointer to it in data parameter
185 flags |= MF_OWNERDRAW;
186 pData = (LPCSTR)pItem;
187 }
188 else
189#endif
190 {
191 // menu is just a normal string (passed in data parameter)
192 flags |= MF_STRING;
b8d3a4f1 193 pData = pItem->GetName();
2bda0e17
KB
194 }
195
b8d3a4f1
VZ
196 // visually select the menu title
197 if ( id == idMenuTitle )
198 {
199 // TODO use SetMenuItemInfo(MFS_DEFAULT) to put it in bold face
2bda0e17
KB
200 }
201
202 HMENU hMenu = (HMENU)((m_hMenu == 0) ? m_savehMenu : m_hMenu);
2bda0e17
KB
203 if ( !AppendMenu(hMenu, flags, id, pData) )
204 {
b8d3a4f1 205 wxLogLastError("AppendMenu");
2bda0e17
KB
206 }
207
208 m_noItems++;
209}
210
b8d3a4f1 211void wxMenu::AppendSeparator()
2bda0e17
KB
212{
213 Append(new wxMenuItem(this, ID_SEPARATOR));
214}
215
216// Pullright item
217void wxMenu::Append(int Id, const wxString& label, wxMenu *SubMenu,
218 const wxString& helpString)
219{
220 Append(new wxMenuItem(this, Id, label, helpString, FALSE, SubMenu));
221}
222
223// Ordinary menu item
224void wxMenu::Append(int Id, const wxString& label,
225 const wxString& helpString, bool checkable)
226{
227 // 'checkable' parameter is useless for Windows.
228 Append(new wxMenuItem(this, Id, label, helpString, checkable));
229}
230
231void wxMenu::Delete(int id)
232{
233 wxNode *node;
2bda0e17
KB
234 int pos;
235 HMENU menu;
236
fd3f686c 237 wxMenuItem *item = NULL;
2bda0e17
KB
238 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) {
239 item = (wxMenuItem *)node->Data();
240 if (item->GetId() == id)
241 break;
242 }
243
244 if (!node)
245 return;
246
247 menu = (HMENU)(m_hMenu ? m_hMenu : m_savehMenu);
248
249 wxMenu *pSubMenu = item->GetSubMenu();
250 if ( pSubMenu != NULL ) {
251 RemoveMenu(menu, (UINT)pos, MF_BYPOSITION);
252 pSubMenu->m_hMenu = pSubMenu->m_savehMenu;
253 pSubMenu->m_savehMenu = 0;
254 pSubMenu->m_parent = NULL;
255 // RemoveChild(item->subMenu);
256 pSubMenu->m_topLevelMenu = NULL;
257 // TODO: Why isn't subMenu deleted here???
258 // Will put this in for now. Assuming this is supposed
259 // to delete the menu, not just remove it.
260 item->DeleteSubMenu();
261 }
262 else {
263 DeleteMenu(menu, (UINT)pos, MF_BYPOSITION);
264 }
265
266 m_menuItems.DeleteNode(node);
267 delete item;
268}
269
270void wxMenu::Enable(int Id, bool Flag)
271{
272 wxMenuItem *item = FindItemForId(Id);
1311c7a9 273 wxCHECK_RET( item != NULL, "can't enable non-existing menu item" );
2bda0e17
KB
274
275 item->Enable(Flag);
276}
277
278bool wxMenu::Enabled(int Id) const
279{
280 wxMenuItem *item = FindItemForId(Id);
1311c7a9 281 wxCHECK( item != NULL, FALSE );
2bda0e17
KB
282
283 return item->IsEnabled();
284}
285
286void wxMenu::Check(int Id, bool Flag)
287{
288 wxMenuItem *item = FindItemForId(Id);
1311c7a9 289 wxCHECK_RET( item != NULL, "can't get status of non-existing menu item" );
2bda0e17
KB
290
291 item->Check(Flag);
292}
293
294bool wxMenu::Checked(int Id) const
295{
296 wxMenuItem *item = FindItemForId(Id);
1311c7a9 297 wxCHECK( item != NULL, FALSE );
2bda0e17
KB
298
299 return item->IsChecked();
300}
301
302void wxMenu::SetTitle(const wxString& label)
303{
b8d3a4f1
VZ
304 bool hasNoTitle = m_title.IsEmpty();
305 m_title = label;
306
307 HMENU hMenu = (HMENU)((m_hMenu == 0) ? m_savehMenu : m_hMenu);
308
309 if ( hasNoTitle )
310 {
311 if ( !label.IsEmpty() )
312 {
fd3f686c
VZ
313 if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
314 (unsigned)idMenuTitle, m_title) ||
315 !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
b8d3a4f1
VZ
316 {
317 wxLogLastError("InsertMenu");
318 }
319 }
320 }
321 else
322 {
323 if ( label.IsEmpty() )
324 {
325 // remove the title and the separator after it
326 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
327 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
328 {
329 wxLogLastError("RemoveMenu");
330 }
331 }
332 else
333 {
334 // modify the title
fd3f686c 335 if ( !ModifyMenu(hMenu, 0u,
b8d3a4f1 336 MF_BYPOSITION | MF_STRING,
fd3f686c 337 (unsigned)idMenuTitle, m_title) )
b8d3a4f1
VZ
338 {
339 wxLogLastError("ModifyMenu");
340 }
341 }
342 }
343
750b78ba 344#ifndef __WIN16__
a3f4e9e8
VZ
345 // put the title string in bold face
346 if ( !m_title.IsEmpty() )
347 {
348 MENUITEMINFO mii;
349 mii.cbSize = sizeof(mii);
350 mii.fMask = MIIM_STATE;
351 mii.fState = MFS_DEFAULT;
352
353 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
354 {
355 wxLogLastError("SetMenuItemInfo");
356 }
357 }
750b78ba 358#endif
2bda0e17
KB
359}
360
f7387de5 361const wxString wxMenu::GetTitle() const
2bda0e17
KB
362{
363 return m_title;
364}
365
366void wxMenu::SetLabel(int Id, const wxString& label)
367{
368 wxMenuItem *item = FindItemForId(Id) ;
369 if (item==NULL)
370 return;
371
372 if (item->GetSubMenu()==NULL)
373 {
374 if (m_hMenu)
375 {
376 UINT was_flag = GetMenuState((HMENU)m_hMenu,Id,MF_BYCOMMAND) ;
377 ModifyMenu((HMENU)m_hMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
378 }
379 else if (m_savehMenu)
380 {
381 UINT was_flag = GetMenuState((HMENU)m_savehMenu,Id,MF_BYCOMMAND) ;
382 ModifyMenu((HMENU)m_savehMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
383 }
384 }
385 else
386 {
387 wxMenu *father = item->GetSubMenu()->m_topLevelMenu ;
388 wxNode *node = father->m_menuItems.First() ;
389 int i = 0 ;
390 while (node)
391 {
392 wxMenuItem *matched = (wxMenuItem*)node->Data() ;
393 if (matched==item)
394 break ;
395 i++ ;
396 node = node->Next() ;
397 }
398 // Here, we have the position.
399 ModifyMenu((HMENU)father->m_savehMenu,i,
400 MF_BYPOSITION|MF_STRING|MF_POPUP,
401 (UINT)item->GetSubMenu()->m_savehMenu,(const char *)label) ;
402 }
403 item->SetName(label);
404}
405
47bc1060 406wxString wxMenu::GetLabel(int id) const
2bda0e17 407{
47bc1060 408/*
2bda0e17
KB
409 static char tmp[128] ;
410 int len;
411 if (m_hMenu)
412 len = GetMenuString((HMENU)m_hMenu,Id,tmp,WXSIZEOF(tmp) - 1,MF_BYCOMMAND);
413 else if (m_savehMenu)
414 len = GetMenuString((HMENU)m_savehMenu,Id,tmp,WXSIZEOF(tmp) - 1,MF_BYCOMMAND);
415 else
416 len = 0 ;
417 tmp[len] = '\0' ;
418 return wxString(tmp) ;
47bc1060
JS
419
420*/
421 wxMenuItem *pItem = FindItemForId(id) ;
422 if (pItem)
423 return pItem->GetName() ;
424 else
425 return wxEmptyString;
2bda0e17
KB
426}
427
debe6624 428bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
2bda0e17 429{
a3f4e9e8
VZ
430 // ignore commands from the menu title
431
432 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
433 if ( id != (WXWORD)idMenuTitle )
434 {
435 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
436 event.SetEventObject( this );
437 event.SetId( id );
438 event.SetInt( id );
439 ProcessCommand(event);
440 }
441
442 return TRUE;
2bda0e17
KB
443}
444
445// Finds the item id matching the given string, -1 if not found.
446int wxMenu::FindItem (const wxString& itemString) const
447{
448 char buf1[200];
449 char buf2[200];
450 wxStripMenuCodes ((char *)(const char *)itemString, buf1);
451
452 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
453 {
454 wxMenuItem *item = (wxMenuItem *) node->Data ();
455 if (item->GetSubMenu())
456 {
457 int ans = item->GetSubMenu()->FindItem(itemString);
458 if (ans > -1)
459 return ans;
460 }
461 if ( !item->IsSeparator() )
462 {
463 wxStripMenuCodes((char *)item->GetName().c_str(), buf2);
464 if (strcmp(buf1, buf2) == 0)
465 return item->GetId();
466 }
467 }
468
469 return -1;
470}
471
debe6624 472wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
2bda0e17
KB
473{
474 if (itemMenu)
475 *itemMenu = NULL;
476 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
477 {
478 wxMenuItem *item = (wxMenuItem *) node->Data ();
479
480 if (item->GetId() == itemId)
481 {
482 if (itemMenu)
483 *itemMenu = (wxMenu *) this;
484 return item;
485 }
486
487 if (item->GetSubMenu())
488 {
489 wxMenuItem *ans = item->GetSubMenu()->FindItemForId (itemId, itemMenu);
490 if (ans)
491 return ans;
492 }
493 }
494
495 if (itemMenu)
496 *itemMenu = NULL;
497 return NULL;
498}
499
debe6624 500void wxMenu::SetHelpString(int itemId, const wxString& helpString)
2bda0e17
KB
501{
502 wxMenuItem *item = FindItemForId (itemId);
503 if (item)
504 item->SetHelp(helpString);
505}
506
debe6624 507wxString wxMenu::GetHelpString (int itemId) const
2bda0e17
KB
508{
509 wxMenuItem *item = FindItemForId (itemId);
ce3ed50d
JS
510 if (item)
511 return item->GetHelp();
512 else
513 return wxEmptyString;
2bda0e17
KB
514}
515
516void wxMenu::ProcessCommand(wxCommandEvent & event)
517{
518 bool processed = FALSE;
519
520 // Try a callback
521 if (m_callback)
522 {
b8d3a4f1 523 (void)(*(m_callback))(*this, event);
2bda0e17
KB
524 processed = TRUE;
525 }
526
527 // Try the menu's event handler
528 if ( !processed && GetEventHandler())
529 {
530 processed = GetEventHandler()->ProcessEvent(event);
531 }
532
533 // Try the window the menu was popped up from (and up
534 // through the hierarchy)
535 if ( !processed && GetInvokingWindow())
02800301 536 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
537}
538
539extern wxMenu *wxCurrentPopupMenu;
debe6624 540bool wxWindow::PopupMenu(wxMenu *menu, int x, int y)
2bda0e17
KB
541{
542 menu->SetInvokingWindow(this);
631f1bfe 543 menu->UpdateUI();
2bda0e17
KB
544
545 HWND hWnd = (HWND) GetHWND();
546 HMENU hMenu = (HMENU)menu->m_hMenu;
547 POINT point;
548 point.x = x;
549 point.y = y;
550 ::ClientToScreen(hWnd, &point);
551 wxCurrentPopupMenu = menu;
552 ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
553 wxYield();
554 wxCurrentPopupMenu = NULL;
555
556 menu->SetInvokingWindow(NULL);
557
558 return TRUE;
559}
560
561// Menu Bar
b8d3a4f1 562wxMenuBar::wxMenuBar()
2bda0e17
KB
563{
564 m_eventHandler = this;
cba2db0c
JS
565 m_menuCount = 0;
566 m_menus = NULL;
567 m_titles = NULL;
568 m_menuBarFrame = NULL;
569 m_hMenu = 0;
570}
2bda0e17 571
cba2db0c
JS
572wxMenuBar::wxMenuBar( long WXUNUSED(style) )
573{
574 m_eventHandler = this;
2bda0e17
KB
575 m_menuCount = 0;
576 m_menus = NULL;
577 m_titles = NULL;
578 m_menuBarFrame = NULL;
579 m_hMenu = 0;
580}
581
debe6624 582wxMenuBar::wxMenuBar(int N, wxMenu *Menus[], const wxString Titles[])
2bda0e17
KB
583{
584 m_eventHandler = this;
585 m_menuCount = N;
586 m_menus = Menus;
587 m_titles = new wxString[N];
588 int i;
589 for ( i = 0; i < N; i++ )
590 m_titles[i] = Titles[i];
591 m_menuBarFrame = NULL;
592 for (i = 0; i < N; i++)
593 m_menus[i]->m_menuBar = (wxMenuBar *) this;
594
595 m_hMenu = 0;
596}
597
b8d3a4f1 598wxMenuBar::~wxMenuBar()
2bda0e17
KB
599{
600 // In fact, don't want menu to be destroyed before MDI
601 // shuffling has taken place. Let it be destroyed
602 // automatically when the window is destroyed.
603
604// DestroyMenu(menu);
605// m_hMenu = NULL;
606
607 int i;
608/*
609 // See remarks in ::~wxMenu() method
610 // BEWARE - this may interfere with MDI fixes, so
611 // may need to remove
612 int N = 0 ;
613
614 if (m_menuBarFrame && ((m_menuBarFrame->GetWindowStyleFlag() & wxSDI) == wxSDI))
615 {
616 if (menu)
617 N = GetMenuItemCount(menu) ;
618 for (i = N-1; i >= 0; i--)
619 RemoveMenu(menu, i, MF_BYPOSITION);
620 }
621*/
622 for (i = 0; i < m_menuCount; i++)
623 {
624 delete m_menus[i];
625 }
626 delete[] m_menus;
627 delete[] m_titles;
628
629/* Don't destroy menu here, in case we're MDI and
630 need to do some shuffling with VALID menu handles.
631 if (menu)
632 DestroyMenu(menu);
633 m_hMenu = 0;
634*/
635}
636
637// Must only be used AFTER menu has been attached to frame,
638// otherwise use individual menus to enable/disable items
debe6624 639void wxMenuBar::Enable(int Id, bool Flag)
2bda0e17
KB
640{
641 int ms_flag;
642 if (Flag)
643 ms_flag = MF_ENABLED;
644 else
645 ms_flag = MF_GRAYED;
646
647 wxMenu *itemMenu = NULL;
648 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
649 if (!item)
650 return;
651
652 if (itemMenu->m_hMenu)
653 EnableMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
654 else if (itemMenu->m_savehMenu)
655 EnableMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
656
657}
658
debe6624 659void wxMenuBar::EnableTop(int pos, bool flag)
2bda0e17
KB
660{
661 int ms_flag;
662 if (flag)
663 ms_flag = MF_ENABLED;
664 else
665 ms_flag = MF_GRAYED;
666
667 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | ms_flag);
668 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
669}
670
671// Must only be used AFTER menu has been attached to frame,
672// otherwise use individual menus
debe6624 673void wxMenuBar::Check(int Id, bool Flag)
2bda0e17
KB
674{
675 wxMenu *itemMenu = NULL;
676 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
677 if (!item)
678 return;
679
680 if (!item->IsCheckable())
681 return ;
682 int ms_flag;
683 if (Flag)
684 ms_flag = MF_CHECKED;
685 else
686 ms_flag = MF_UNCHECKED;
687
688 if (itemMenu->m_hMenu)
689 CheckMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
690 else if (itemMenu->m_savehMenu)
691 CheckMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
692
693// CheckMenuItem((HMENU)m_hMenu, Id, MF_BYCOMMAND | ms_flag);
694}
695
debe6624 696bool wxMenuBar::Checked(int Id) const
2bda0e17
KB
697{
698 wxMenu *itemMenu = NULL;
699 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
700 if (!item)
701 return FALSE;
702
fd3f686c 703 int Flag = 0;
2bda0e17
KB
704
705 if (itemMenu->m_hMenu)
706 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
707 else if (itemMenu->m_savehMenu)
708 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
709
710// Flag=GetMenuState((HMENU)m_hMenu, Id, MF_BYCOMMAND) ;
711
712 if (Flag&MF_CHECKED)
713 return TRUE ;
714 else
715 return FALSE ;
716}
717
debe6624 718bool wxMenuBar::Enabled(int Id) const
2bda0e17
KB
719{
720 wxMenu *itemMenu = NULL;
721 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
722 if (!item)
723 return FALSE;
724
725 int Flag ;
726
727 if (itemMenu->m_hMenu)
728 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
729 else if (itemMenu->m_savehMenu)
730 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
731
732 if (Flag&MF_ENABLED)
733 return TRUE ;
734 else
735 return FALSE ;
736}
737
738
debe6624 739void wxMenuBar::SetLabel(int Id, const wxString& label)
2bda0e17
KB
740{
741 wxMenu *itemMenu = NULL;
742 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
743
744 if (!item)
745 return;
746
747 if (itemMenu->m_hMenu)
748 {
749 UINT was_flag = GetMenuState((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND) ;
750 ModifyMenu((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
751 }
752 else if (itemMenu->m_savehMenu)
753 {
754 UINT was_flag = GetMenuState((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND) ;
755 ModifyMenu((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
756 }
757}
758
debe6624 759wxString wxMenuBar::GetLabel(int Id) const
2bda0e17
KB
760{
761 wxMenu *itemMenu = NULL;
762 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
763
764 if (!item)
765 return wxString("");
766
767 static char tmp[128] ;
768 int len = 0;
769 if (itemMenu->m_hMenu)
770 {
771 len = GetMenuString((HMENU)itemMenu->m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
772 }
773 else if (itemMenu->m_savehMenu)
774 {
775 len = GetMenuString((HMENU)itemMenu->m_savehMenu,Id,tmp,127,MF_BYCOMMAND) ;
776 }
777
778// int len = GetMenuString((HMENU)m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
779 tmp[len] = '\0' ;
780 return wxString(tmp) ;
781}
782
debe6624 783void wxMenuBar::SetLabelTop(int pos, const wxString& label)
2bda0e17
KB
784{
785 UINT was_flag = GetMenuState((HMENU)m_hMenu,pos,MF_BYPOSITION) ;
786 if (was_flag&MF_POPUP)
787 {
788 was_flag &= 0xff ;
789 HMENU popup = GetSubMenu((HMENU)m_hMenu,pos) ;
790 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,(UINT)popup,(const char *)label) ;
791 }
792 else
793 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,pos,(const char *)label) ;
794}
795
debe6624 796wxString wxMenuBar::GetLabelTop(int pos) const
2bda0e17
KB
797{
798 static char tmp[128] ;
799 int len = GetMenuString((HMENU)m_hMenu,pos,tmp,127,MF_BYPOSITION) ;
800 tmp[len] = '\0' ;
801 return wxString(tmp);
802}
803
debe6624 804bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
2bda0e17
KB
805{
806 if (!m_menuBarFrame)
807 return TRUE;
808
809 if (RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION)) {
810 m_menus[pos]->m_hMenu = m_menus[pos]->m_savehMenu;
811 m_menus[pos]->m_savehMenu = 0;
812
813 if (m_menuBarFrame) {
814 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
815 }
816
817 return TRUE;
818 }
819
820 return FALSE;
821}
822
823bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title)
824{
825 if (!a_menu->m_hMenu)
826 return FALSE;
827
828 if (!m_menuBarFrame)
829 return TRUE;
830
831 a_menu->m_savehMenu = a_menu->m_hMenu;
832 a_menu->m_hMenu = 0;
833
834 AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, (UINT)a_menu->m_savehMenu, title);
835
836 DrawMenuBar((HWND) m_menuBarFrame->GetHWND());
837
838 return TRUE;
839}
840
841void wxMenuBar::Append (wxMenu * menu, const wxString& title)
842{
843 if (!OnAppend(menu, title))
844 return;
845
846 m_menuCount ++;
847 wxMenu **new_menus = new wxMenu *[m_menuCount];
848 wxString *new_titles = new wxString[m_menuCount];
849 int i;
850
851 for (i = 0; i < m_menuCount - 1; i++)
852 {
853 new_menus[i] = m_menus[i];
854 m_menus[i] = NULL;
855 new_titles[i] = m_titles[i];
856 m_titles[i] = "";
857 }
858 if (m_menus)
859 {
860 delete[]m_menus;
861 delete[]m_titles;
862 }
863 m_menus = new_menus;
864 m_titles = new_titles;
865
866 m_menus[m_menuCount - 1] = (wxMenu *)menu;
867 m_titles[m_menuCount - 1] = title;
868
869 ((wxMenu *)menu)->m_menuBar = (wxMenuBar *) this;
870 ((wxMenu *)menu)->SetParent(this);
871}
872
debe6624 873void wxMenuBar::Delete(wxMenu * menu, int i)
2bda0e17
KB
874{
875 int j;
876 int ii = (int) i;
877
878 if (menu != 0) {
879 for (ii = 0; ii < m_menuCount; ii++) {
880 if (m_menus[ii] == menu)
881 break;
882 }
883 if (ii >= m_menuCount)
884 return;
885 } else {
886 if (ii < 0 || ii >= m_menuCount)
887 return;
888 menu = m_menus[ii];
889 }
890
891 if (!OnDelete(menu, ii))
892 return;
893
894 menu->SetParent(NULL);
895
896 -- m_menuCount;
897 for (j = ii; j < m_menuCount; j++) {
898 m_menus[j] = m_menus[j + 1];
899 m_titles[j] = m_titles[j + 1];
900 }
901}
902
903// Find the menu menuString, item itemString, and return the item id.
904// Returns -1 if none found.
905int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemString) const
906{
907 char buf1[200];
908 char buf2[200];
909 wxStripMenuCodes ((char *)(const char *)menuString, buf1);
910 int i;
911 for (i = 0; i < m_menuCount; i++)
912 {
913 wxStripMenuCodes ((char *)(const char *)m_titles[i], buf2);
914 if (strcmp (buf1, buf2) == 0)
915 return m_menus[i]->FindItem (itemString);
916 }
917 return -1;
918}
919
debe6624 920wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const
2bda0e17
KB
921{
922 if (itemMenu)
923 *itemMenu = NULL;
924
925 wxMenuItem *item = NULL;
926 int i;
927 for (i = 0; i < m_menuCount; i++)
fd3f686c
VZ
928 {
929 item = m_menus[i]->FindItemForId (Id, itemMenu);
930 if (item)
2bda0e17 931 return item;
fd3f686c 932 }
2bda0e17
KB
933 return NULL;
934}
935
debe6624 936void wxMenuBar::SetHelpString (int Id, const wxString& helpString)
2bda0e17
KB
937{
938 int i;
939 for (i = 0; i < m_menuCount; i++)
940 {
941 if (m_menus[i]->FindItemForId (Id))
942 {
943 m_menus[i]->SetHelpString (Id, helpString);
944 return;
945 }
946 }
947}
948
debe6624 949wxString wxMenuBar::GetHelpString (int Id) const
2bda0e17
KB
950{
951 int i;
952 for (i = 0; i < m_menuCount; i++)
953 {
954 if (m_menus[i]->FindItemForId (Id))
955 return wxString(m_menus[i]->GetHelpString (Id));
956 }
957 return wxString("");
958}
959
960wxWindow *wxMenu::GetWindow() const
961{
962 if ( m_pInvokingWindow != NULL )
963 return m_pInvokingWindow;
964 if ( m_menuBar != NULL)
965 return m_menuBar->m_menuBarFrame;
966 return NULL;
967}
968
969WXHMENU wxMenu::GetHMenu() const
970{
971 if ( m_hMenu != 0 )
972 return m_hMenu;
973 else if ( m_savehMenu != 0 )
974 return m_savehMenu;
975
976 return 0;
977}
978
631f1bfe
JS
979// Update a menu and all submenus recursively.
980// source is the object that has the update event handlers
981// defined for it. If NULL, the menu or associated window
982// will be used.
983void wxMenu::UpdateUI(wxEvtHandler* source)
984{
985 if (!source && GetInvokingWindow())
986 source = GetInvokingWindow()->GetEventHandler();
987 if (!source)
988 source = GetEventHandler();
989 if (!source)
990 source = this;
991
992 wxNode* node = GetItems().First();
993 while (node)
994 {
995 wxMenuItem* item = (wxMenuItem*) node->Data();
996 if ( !item->IsSeparator() )
997 {
998 wxWindowID id = item->GetId();
999 wxUpdateUIEvent event(id);
1000 event.SetEventObject( source );
1001
1002 if (source->ProcessEvent(event))
1003 {
1004 if (event.GetSetText())
1005 SetLabel(id, event.GetText());
1006 if (event.GetSetChecked())
1007 Check(id, event.GetChecked());
1008 if (event.GetSetEnabled())
1009 Enable(id, event.GetEnabled());
1010 }
1011
1012 if (item->GetSubMenu())
1013 item->GetSubMenu()->UpdateUI(source);
1014 }
1015 node = node->Next();
1016 }
1017}