]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menu.cpp
wxProcess-related code now works
[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
a3f4e9e8
VZ
344 // put the title string in bold face
345 if ( !m_title.IsEmpty() )
346 {
347 MENUITEMINFO mii;
348 mii.cbSize = sizeof(mii);
349 mii.fMask = MIIM_STATE;
350 mii.fState = MFS_DEFAULT;
351
352 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
353 {
354 wxLogLastError("SetMenuItemInfo");
355 }
356 }
2bda0e17
KB
357}
358
f7387de5 359const wxString wxMenu::GetTitle() const
2bda0e17
KB
360{
361 return m_title;
362}
363
364void wxMenu::SetLabel(int Id, const wxString& label)
365{
366 wxMenuItem *item = FindItemForId(Id) ;
367 if (item==NULL)
368 return;
369
370 if (item->GetSubMenu()==NULL)
371 {
372 if (m_hMenu)
373 {
374 UINT was_flag = GetMenuState((HMENU)m_hMenu,Id,MF_BYCOMMAND) ;
375 ModifyMenu((HMENU)m_hMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
376 }
377 else if (m_savehMenu)
378 {
379 UINT was_flag = GetMenuState((HMENU)m_savehMenu,Id,MF_BYCOMMAND) ;
380 ModifyMenu((HMENU)m_savehMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
381 }
382 }
383 else
384 {
385 wxMenu *father = item->GetSubMenu()->m_topLevelMenu ;
386 wxNode *node = father->m_menuItems.First() ;
387 int i = 0 ;
388 while (node)
389 {
390 wxMenuItem *matched = (wxMenuItem*)node->Data() ;
391 if (matched==item)
392 break ;
393 i++ ;
394 node = node->Next() ;
395 }
396 // Here, we have the position.
397 ModifyMenu((HMENU)father->m_savehMenu,i,
398 MF_BYPOSITION|MF_STRING|MF_POPUP,
399 (UINT)item->GetSubMenu()->m_savehMenu,(const char *)label) ;
400 }
401 item->SetName(label);
402}
403
47bc1060 404wxString wxMenu::GetLabel(int id) const
2bda0e17 405{
47bc1060 406/*
2bda0e17
KB
407 static char tmp[128] ;
408 int len;
409 if (m_hMenu)
410 len = GetMenuString((HMENU)m_hMenu,Id,tmp,WXSIZEOF(tmp) - 1,MF_BYCOMMAND);
411 else if (m_savehMenu)
412 len = GetMenuString((HMENU)m_savehMenu,Id,tmp,WXSIZEOF(tmp) - 1,MF_BYCOMMAND);
413 else
414 len = 0 ;
415 tmp[len] = '\0' ;
416 return wxString(tmp) ;
47bc1060
JS
417
418*/
419 wxMenuItem *pItem = FindItemForId(id) ;
420 if (pItem)
421 return pItem->GetName() ;
422 else
423 return wxEmptyString;
2bda0e17
KB
424}
425
debe6624 426bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
2bda0e17 427{
a3f4e9e8
VZ
428 // ignore commands from the menu title
429
430 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
431 if ( id != (WXWORD)idMenuTitle )
432 {
433 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
434 event.SetEventObject( this );
435 event.SetId( id );
436 event.SetInt( id );
437 ProcessCommand(event);
438 }
439
440 return TRUE;
2bda0e17
KB
441}
442
443// Finds the item id matching the given string, -1 if not found.
444int wxMenu::FindItem (const wxString& itemString) const
445{
446 char buf1[200];
447 char buf2[200];
448 wxStripMenuCodes ((char *)(const char *)itemString, buf1);
449
450 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
451 {
452 wxMenuItem *item = (wxMenuItem *) node->Data ();
453 if (item->GetSubMenu())
454 {
455 int ans = item->GetSubMenu()->FindItem(itemString);
456 if (ans > -1)
457 return ans;
458 }
459 if ( !item->IsSeparator() )
460 {
461 wxStripMenuCodes((char *)item->GetName().c_str(), buf2);
462 if (strcmp(buf1, buf2) == 0)
463 return item->GetId();
464 }
465 }
466
467 return -1;
468}
469
debe6624 470wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
2bda0e17
KB
471{
472 if (itemMenu)
473 *itemMenu = NULL;
474 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
475 {
476 wxMenuItem *item = (wxMenuItem *) node->Data ();
477
478 if (item->GetId() == itemId)
479 {
480 if (itemMenu)
481 *itemMenu = (wxMenu *) this;
482 return item;
483 }
484
485 if (item->GetSubMenu())
486 {
487 wxMenuItem *ans = item->GetSubMenu()->FindItemForId (itemId, itemMenu);
488 if (ans)
489 return ans;
490 }
491 }
492
493 if (itemMenu)
494 *itemMenu = NULL;
495 return NULL;
496}
497
debe6624 498void wxMenu::SetHelpString(int itemId, const wxString& helpString)
2bda0e17
KB
499{
500 wxMenuItem *item = FindItemForId (itemId);
501 if (item)
502 item->SetHelp(helpString);
503}
504
debe6624 505wxString wxMenu::GetHelpString (int itemId) const
2bda0e17
KB
506{
507 wxMenuItem *item = FindItemForId (itemId);
ce3ed50d
JS
508 if (item)
509 return item->GetHelp();
510 else
511 return wxEmptyString;
2bda0e17
KB
512}
513
514void wxMenu::ProcessCommand(wxCommandEvent & event)
515{
516 bool processed = FALSE;
517
518 // Try a callback
519 if (m_callback)
520 {
b8d3a4f1 521 (void)(*(m_callback))(*this, event);
2bda0e17
KB
522 processed = TRUE;
523 }
524
525 // Try the menu's event handler
526 if ( !processed && GetEventHandler())
527 {
528 processed = GetEventHandler()->ProcessEvent(event);
529 }
530
531 // Try the window the menu was popped up from (and up
532 // through the hierarchy)
533 if ( !processed && GetInvokingWindow())
02800301 534 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
535}
536
537extern wxMenu *wxCurrentPopupMenu;
debe6624 538bool wxWindow::PopupMenu(wxMenu *menu, int x, int y)
2bda0e17
KB
539{
540 menu->SetInvokingWindow(this);
631f1bfe 541 menu->UpdateUI();
2bda0e17
KB
542
543 HWND hWnd = (HWND) GetHWND();
544 HMENU hMenu = (HMENU)menu->m_hMenu;
545 POINT point;
546 point.x = x;
547 point.y = y;
548 ::ClientToScreen(hWnd, &point);
549 wxCurrentPopupMenu = menu;
550 ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
551 wxYield();
552 wxCurrentPopupMenu = NULL;
553
554 menu->SetInvokingWindow(NULL);
555
556 return TRUE;
557}
558
559// Menu Bar
b8d3a4f1 560wxMenuBar::wxMenuBar()
2bda0e17
KB
561{
562 m_eventHandler = this;
563
564 m_menuCount = 0;
565 m_menus = NULL;
566 m_titles = NULL;
567 m_menuBarFrame = NULL;
568 m_hMenu = 0;
569}
570
debe6624 571wxMenuBar::wxMenuBar(int N, wxMenu *Menus[], const wxString Titles[])
2bda0e17
KB
572{
573 m_eventHandler = this;
574 m_menuCount = N;
575 m_menus = Menus;
576 m_titles = new wxString[N];
577 int i;
578 for ( i = 0; i < N; i++ )
579 m_titles[i] = Titles[i];
580 m_menuBarFrame = NULL;
581 for (i = 0; i < N; i++)
582 m_menus[i]->m_menuBar = (wxMenuBar *) this;
583
584 m_hMenu = 0;
585}
586
b8d3a4f1 587wxMenuBar::~wxMenuBar()
2bda0e17
KB
588{
589 // In fact, don't want menu to be destroyed before MDI
590 // shuffling has taken place. Let it be destroyed
591 // automatically when the window is destroyed.
592
593// DestroyMenu(menu);
594// m_hMenu = NULL;
595
596 int i;
597/*
598 // See remarks in ::~wxMenu() method
599 // BEWARE - this may interfere with MDI fixes, so
600 // may need to remove
601 int N = 0 ;
602
603 if (m_menuBarFrame && ((m_menuBarFrame->GetWindowStyleFlag() & wxSDI) == wxSDI))
604 {
605 if (menu)
606 N = GetMenuItemCount(menu) ;
607 for (i = N-1; i >= 0; i--)
608 RemoveMenu(menu, i, MF_BYPOSITION);
609 }
610*/
611 for (i = 0; i < m_menuCount; i++)
612 {
613 delete m_menus[i];
614 }
615 delete[] m_menus;
616 delete[] m_titles;
617
618/* Don't destroy menu here, in case we're MDI and
619 need to do some shuffling with VALID menu handles.
620 if (menu)
621 DestroyMenu(menu);
622 m_hMenu = 0;
623*/
624}
625
626// Must only be used AFTER menu has been attached to frame,
627// otherwise use individual menus to enable/disable items
debe6624 628void wxMenuBar::Enable(int Id, bool Flag)
2bda0e17
KB
629{
630 int ms_flag;
631 if (Flag)
632 ms_flag = MF_ENABLED;
633 else
634 ms_flag = MF_GRAYED;
635
636 wxMenu *itemMenu = NULL;
637 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
638 if (!item)
639 return;
640
641 if (itemMenu->m_hMenu)
642 EnableMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
643 else if (itemMenu->m_savehMenu)
644 EnableMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
645
646}
647
debe6624 648void wxMenuBar::EnableTop(int pos, bool flag)
2bda0e17
KB
649{
650 int ms_flag;
651 if (flag)
652 ms_flag = MF_ENABLED;
653 else
654 ms_flag = MF_GRAYED;
655
656 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | ms_flag);
657 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
658}
659
660// Must only be used AFTER menu has been attached to frame,
661// otherwise use individual menus
debe6624 662void wxMenuBar::Check(int Id, bool Flag)
2bda0e17
KB
663{
664 wxMenu *itemMenu = NULL;
665 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
666 if (!item)
667 return;
668
669 if (!item->IsCheckable())
670 return ;
671 int ms_flag;
672 if (Flag)
673 ms_flag = MF_CHECKED;
674 else
675 ms_flag = MF_UNCHECKED;
676
677 if (itemMenu->m_hMenu)
678 CheckMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
679 else if (itemMenu->m_savehMenu)
680 CheckMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
681
682// CheckMenuItem((HMENU)m_hMenu, Id, MF_BYCOMMAND | ms_flag);
683}
684
debe6624 685bool wxMenuBar::Checked(int Id) const
2bda0e17
KB
686{
687 wxMenu *itemMenu = NULL;
688 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
689 if (!item)
690 return FALSE;
691
fd3f686c 692 int Flag = 0;
2bda0e17
KB
693
694 if (itemMenu->m_hMenu)
695 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
696 else if (itemMenu->m_savehMenu)
697 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
698
699// Flag=GetMenuState((HMENU)m_hMenu, Id, MF_BYCOMMAND) ;
700
701 if (Flag&MF_CHECKED)
702 return TRUE ;
703 else
704 return FALSE ;
705}
706
debe6624 707bool wxMenuBar::Enabled(int Id) const
2bda0e17
KB
708{
709 wxMenu *itemMenu = NULL;
710 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
711 if (!item)
712 return FALSE;
713
714 int Flag ;
715
716 if (itemMenu->m_hMenu)
717 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
718 else if (itemMenu->m_savehMenu)
719 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
720
721 if (Flag&MF_ENABLED)
722 return TRUE ;
723 else
724 return FALSE ;
725}
726
727
debe6624 728void wxMenuBar::SetLabel(int Id, const wxString& label)
2bda0e17
KB
729{
730 wxMenu *itemMenu = NULL;
731 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
732
733 if (!item)
734 return;
735
736 if (itemMenu->m_hMenu)
737 {
738 UINT was_flag = GetMenuState((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND) ;
739 ModifyMenu((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
740 }
741 else if (itemMenu->m_savehMenu)
742 {
743 UINT was_flag = GetMenuState((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND) ;
744 ModifyMenu((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
745 }
746}
747
debe6624 748wxString wxMenuBar::GetLabel(int Id) const
2bda0e17
KB
749{
750 wxMenu *itemMenu = NULL;
751 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
752
753 if (!item)
754 return wxString("");
755
756 static char tmp[128] ;
757 int len = 0;
758 if (itemMenu->m_hMenu)
759 {
760 len = GetMenuString((HMENU)itemMenu->m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
761 }
762 else if (itemMenu->m_savehMenu)
763 {
764 len = GetMenuString((HMENU)itemMenu->m_savehMenu,Id,tmp,127,MF_BYCOMMAND) ;
765 }
766
767// int len = GetMenuString((HMENU)m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
768 tmp[len] = '\0' ;
769 return wxString(tmp) ;
770}
771
debe6624 772void wxMenuBar::SetLabelTop(int pos, const wxString& label)
2bda0e17
KB
773{
774 UINT was_flag = GetMenuState((HMENU)m_hMenu,pos,MF_BYPOSITION) ;
775 if (was_flag&MF_POPUP)
776 {
777 was_flag &= 0xff ;
778 HMENU popup = GetSubMenu((HMENU)m_hMenu,pos) ;
779 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,(UINT)popup,(const char *)label) ;
780 }
781 else
782 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,pos,(const char *)label) ;
783}
784
debe6624 785wxString wxMenuBar::GetLabelTop(int pos) const
2bda0e17
KB
786{
787 static char tmp[128] ;
788 int len = GetMenuString((HMENU)m_hMenu,pos,tmp,127,MF_BYPOSITION) ;
789 tmp[len] = '\0' ;
790 return wxString(tmp);
791}
792
debe6624 793bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
2bda0e17
KB
794{
795 if (!m_menuBarFrame)
796 return TRUE;
797
798 if (RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION)) {
799 m_menus[pos]->m_hMenu = m_menus[pos]->m_savehMenu;
800 m_menus[pos]->m_savehMenu = 0;
801
802 if (m_menuBarFrame) {
803 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
804 }
805
806 return TRUE;
807 }
808
809 return FALSE;
810}
811
812bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title)
813{
814 if (!a_menu->m_hMenu)
815 return FALSE;
816
817 if (!m_menuBarFrame)
818 return TRUE;
819
820 a_menu->m_savehMenu = a_menu->m_hMenu;
821 a_menu->m_hMenu = 0;
822
823 AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, (UINT)a_menu->m_savehMenu, title);
824
825 DrawMenuBar((HWND) m_menuBarFrame->GetHWND());
826
827 return TRUE;
828}
829
830void wxMenuBar::Append (wxMenu * menu, const wxString& title)
831{
832 if (!OnAppend(menu, title))
833 return;
834
835 m_menuCount ++;
836 wxMenu **new_menus = new wxMenu *[m_menuCount];
837 wxString *new_titles = new wxString[m_menuCount];
838 int i;
839
840 for (i = 0; i < m_menuCount - 1; i++)
841 {
842 new_menus[i] = m_menus[i];
843 m_menus[i] = NULL;
844 new_titles[i] = m_titles[i];
845 m_titles[i] = "";
846 }
847 if (m_menus)
848 {
849 delete[]m_menus;
850 delete[]m_titles;
851 }
852 m_menus = new_menus;
853 m_titles = new_titles;
854
855 m_menus[m_menuCount - 1] = (wxMenu *)menu;
856 m_titles[m_menuCount - 1] = title;
857
858 ((wxMenu *)menu)->m_menuBar = (wxMenuBar *) this;
859 ((wxMenu *)menu)->SetParent(this);
860}
861
debe6624 862void wxMenuBar::Delete(wxMenu * menu, int i)
2bda0e17
KB
863{
864 int j;
865 int ii = (int) i;
866
867 if (menu != 0) {
868 for (ii = 0; ii < m_menuCount; ii++) {
869 if (m_menus[ii] == menu)
870 break;
871 }
872 if (ii >= m_menuCount)
873 return;
874 } else {
875 if (ii < 0 || ii >= m_menuCount)
876 return;
877 menu = m_menus[ii];
878 }
879
880 if (!OnDelete(menu, ii))
881 return;
882
883 menu->SetParent(NULL);
884
885 -- m_menuCount;
886 for (j = ii; j < m_menuCount; j++) {
887 m_menus[j] = m_menus[j + 1];
888 m_titles[j] = m_titles[j + 1];
889 }
890}
891
892// Find the menu menuString, item itemString, and return the item id.
893// Returns -1 if none found.
894int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemString) const
895{
896 char buf1[200];
897 char buf2[200];
898 wxStripMenuCodes ((char *)(const char *)menuString, buf1);
899 int i;
900 for (i = 0; i < m_menuCount; i++)
901 {
902 wxStripMenuCodes ((char *)(const char *)m_titles[i], buf2);
903 if (strcmp (buf1, buf2) == 0)
904 return m_menus[i]->FindItem (itemString);
905 }
906 return -1;
907}
908
debe6624 909wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const
2bda0e17
KB
910{
911 if (itemMenu)
912 *itemMenu = NULL;
913
914 wxMenuItem *item = NULL;
915 int i;
916 for (i = 0; i < m_menuCount; i++)
fd3f686c
VZ
917 {
918 item = m_menus[i]->FindItemForId (Id, itemMenu);
919 if (item)
2bda0e17 920 return item;
fd3f686c 921 }
2bda0e17
KB
922 return NULL;
923}
924
debe6624 925void wxMenuBar::SetHelpString (int Id, const wxString& helpString)
2bda0e17
KB
926{
927 int i;
928 for (i = 0; i < m_menuCount; i++)
929 {
930 if (m_menus[i]->FindItemForId (Id))
931 {
932 m_menus[i]->SetHelpString (Id, helpString);
933 return;
934 }
935 }
936}
937
debe6624 938wxString wxMenuBar::GetHelpString (int Id) const
2bda0e17
KB
939{
940 int i;
941 for (i = 0; i < m_menuCount; i++)
942 {
943 if (m_menus[i]->FindItemForId (Id))
944 return wxString(m_menus[i]->GetHelpString (Id));
945 }
946 return wxString("");
947}
948
949wxWindow *wxMenu::GetWindow() const
950{
951 if ( m_pInvokingWindow != NULL )
952 return m_pInvokingWindow;
953 if ( m_menuBar != NULL)
954 return m_menuBar->m_menuBarFrame;
955 return NULL;
956}
957
958WXHMENU wxMenu::GetHMenu() const
959{
960 if ( m_hMenu != 0 )
961 return m_hMenu;
962 else if ( m_savehMenu != 0 )
963 return m_savehMenu;
964
965 return 0;
966}
967
631f1bfe
JS
968// Update a menu and all submenus recursively.
969// source is the object that has the update event handlers
970// defined for it. If NULL, the menu or associated window
971// will be used.
972void wxMenu::UpdateUI(wxEvtHandler* source)
973{
974 if (!source && GetInvokingWindow())
975 source = GetInvokingWindow()->GetEventHandler();
976 if (!source)
977 source = GetEventHandler();
978 if (!source)
979 source = this;
980
981 wxNode* node = GetItems().First();
982 while (node)
983 {
984 wxMenuItem* item = (wxMenuItem*) node->Data();
985 if ( !item->IsSeparator() )
986 {
987 wxWindowID id = item->GetId();
988 wxUpdateUIEvent event(id);
989 event.SetEventObject( source );
990
991 if (source->ProcessEvent(event))
992 {
993 if (event.GetSetText())
994 SetLabel(id, event.GetText());
995 if (event.GetSetChecked())
996 Check(id, event.GetChecked());
997 if (event.GetSetEnabled())
998 Enable(id, event.GetEnabled());
999 }
1000
1001 if (item->GetSubMenu())
1002 item->GetSubMenu()->UpdateUI(source);
1003 }
1004 node = node->Next();
1005 }
1006}