]> git.saurik.com Git - wxWidgets.git/blame - src/os2/menu.cpp
compilation fixes
[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
75f11ad7
DW
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
0e320a79 14
75f11ad7
DW
15#ifndef WX_PRECOMP
16 #include "wx/frame.h"
17 #include "wx/menu.h"
18 #include "wx/utils.h"
19 #include "wx/intl.h"
20#endif
0e320a79 21
75f11ad7
DW
22#if wxUSE_OWNER_DRAWN
23 #include "wx/ownerdrw.h"
0e320a79
DW
24#endif
25
75f11ad7 26#include "wx/os2/private.h"
0e320a79
DW
27#include "wx/menu.h"
28#include "wx/menuitem.h"
29#include "wx/log.h"
0e320a79
DW
30
31// other standard headers
0e320a79
DW
32#include <string.h>
33
75f11ad7
DW
34// ----------------------------------------------------------------------------
35// global variables
36// ----------------------------------------------------------------------------
37
38extern wxMenu *wxCurrentPopupMenu;
39
40// ----------------------------------------------------------------------------
41// constants
42// ----------------------------------------------------------------------------
43
44// the (popup) menu title has this special id
45static const int idMenuTitle = -2;
46
47// ----------------------------------------------------------------------------
48// macros
49// ----------------------------------------------------------------------------
50
0e320a79 51#if !USE_SHARED_LIBRARY
75f11ad7
DW
52 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
53 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
0e320a79
DW
54#endif
55
56// ============================================================================
57// implementation
58// ============================================================================
59
75f11ad7
DW
60// ---------------------------------------------------------------------------
61// wxMenu construction, adding and removing menu items
62// ---------------------------------------------------------------------------
0e320a79
DW
63
64// Construct a menu with optional title (then use append)
75f11ad7 65void wxMenu::Init(const wxString& title, const wxFunction func )
0e320a79
DW
66{
67 m_title = title;
68 m_parent = NULL;
69 m_eventHandler = this;
75f11ad7
DW
70 m_pInvokingWindow = NULL;
71 m_doBreak = FALSE ;
0e320a79
DW
72 m_noItems = 0;
73 m_menuBar = NULL;
75f11ad7
DW
74 m_hMenu = 0; //(WXHMENU) CreatePopupMenu();
75 m_savehMenu = 0 ;
76 m_topLevelMenu = this;
0e320a79 77 m_clientData = (void*) NULL;
75f11ad7
DW
78
79 if ( !!m_title )
0e320a79 80 {
75f11ad7 81 Append(idMenuTitle, m_title) ;
0e320a79
DW
82 AppendSeparator() ;
83 }
84
85 Callback(func);
0e320a79
DW
86}
87
88// The wxWindow destructor will take care of deleting the submenus.
89wxMenu::~wxMenu()
90{
75f11ad7
DW
91 // free Windows resources
92 if ( m_hMenu )
93 {
94// ::DestroyMenu((HMENU)m_hMenu);
95 m_hMenu = 0;
96 }
0e320a79 97
75f11ad7 98 // delete submenus
0e320a79 99 wxNode *node = m_menuItems.First();
75f11ad7 100 while ( node )
0e320a79
DW
101 {
102 wxMenuItem *item = (wxMenuItem *)node->Data();
103
104 // Delete child menus.
105 // Beware: they must not be appended to children list!!!
106 // (because order of delete is significant)
75f11ad7 107 if ( item->IsSubMenu() )
0e320a79
DW
108 item->DeleteSubMenu();
109
110 wxNode *next = node->Next();
111 delete item;
112 delete node;
113 node = next;
114 }
115}
116
117void wxMenu::Break()
118{
75f11ad7 119 m_doBreak = TRUE;
0e320a79
DW
120}
121
122// function appends a new item or submenu to the menu
123void wxMenu::Append(wxMenuItem *pItem)
124{
75f11ad7
DW
125 wxCHECK_RET( pItem != NULL, wxT("can't append NULL item to the menu") );
126
127#if wxUSE_ACCEL
128 // check for accelerators: they are given after '\t'
129 wxString label = pItem->GetName();
130 int posTab = label.Find(wxT('\t'));
131 if ( posTab != wxNOT_FOUND ) {
132 // parse the accelerator string
133 int keyCode = 0;
134 int accelFlags = wxACCEL_NORMAL;
135 wxString current;
136 for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) {
137 if ( (label[n] == '+') || (label[n] == '-') ) {
138 if ( current == _("ctrl") )
139 accelFlags |= wxACCEL_CTRL;
140 else if ( current == _("alt") )
141 accelFlags |= wxACCEL_ALT;
142 else if ( current == _("shift") )
143 accelFlags |= wxACCEL_SHIFT;
144 else {
145 wxLogDebug(wxT("Unknown accel modifier: '%s'"),
146 current.c_str());
147 }
148
149 current.Empty();
150 }
151 else {
152 current += wxTolower(label[n]);
153 }
154 }
155
156 if ( current.IsEmpty() ) {
157 wxLogDebug(wxT("No accel key found, accel string ignored."));
158 }
159 else {
160 if ( current.Len() == 1 ) {
161 // it's a letter
162 keyCode = wxToupper(current[0U]);
163 }
164 else {
165 // it should be a function key
166 if ( current[0U] == 'f' && isdigit(current[1U]) &&
167 (current.Len() == 2 ||
168 (current.Len() == 3 && isdigit(current[2U]))) ) {
169 int n;
170 wxSscanf(current.c_str() + 1, wxT("%d"), &n);
171
172 keyCode = VK_F1 + n - 1;
173 }
174 else {
175 wxLogDebug(wxT("Unrecognized accel key '%s', accel "
176 "string ignored."), current.c_str());
177 }
178 }
179 }
180
181 if ( keyCode ) {
182 // do add an entry
183 m_accelKeyCodes.Add(keyCode);
184 m_accelFlags.Add(accelFlags);
185 m_accelIds.Add(pItem->GetId());
186 }
187 }
188#endif // wxUSE_ACCEL
0e320a79 189
75f11ad7 190 UINT flags = 0;
0e320a79 191
75f11ad7
DW
192 // TODO:
193/*
194 // if "Break" has just been called, insert a menu break before this item
195 // (and don't forget to reset the flag)
196 if ( m_doBreak ) {
197 flags |= MF_MENUBREAK;
198 m_doBreak = FALSE;
199 }
0e320a79 200
75f11ad7
DW
201 if ( pItem->IsSeparator() ) {
202 flags |= MF_SEPARATOR;
203 }
204
205 // id is the numeric id for normal menu items and HMENU for submenus as
206 // required by ::AppendMenu() API
207 UINT id;
208 wxMenu *submenu = pItem->GetSubMenu();
209 if ( submenu != NULL ) {
210 wxASSERT( submenu->GetHMenu() != (WXHMENU) NULL );
211
212 id = (UINT)submenu->GetHMenu();
213 submenu->m_topLevelMenu = m_topLevelMenu;
214 submenu->m_parent = this;
215 submenu->m_savehMenu = (WXHMENU)id;
216 submenu->m_hMenu = 0;
217
218 flags |= MF_POPUP;
219 }
220 else {
221 id = pItem->GetId();
222 }
223
224 const char* pData;
225
226#if wxUSE_OWNER_DRAWN
227 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
228 // item draws itself, pass pointer to it in data parameter
229 flags |= MF_OWNERDRAW;
230 pData = (const char*)pItem;
231 }
232 else
233#endif
234 {
235 // menu is just a normal string (passed in data parameter)
236 flags |= MF_STRING;
237 pData = label;
238 }
239 if ( !::AppendMenu(GetHmenu(), flags, id, pData) )
240 {
241 wxLogLastError("AppendMenu");
242 }
243 else
244 {
245 if ( id == idMenuTitle )
246 {
247 // visually select the menu title
248 MENUITEMINFO mii;
249 mii.cbSize = sizeof(mii);
250 mii.fMask = MIIM_STATE;
251 mii.fState = MFS_DEFAULT;
252
253 if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
254 {
255 wxLogLastError(wxT("SetMenuItemInfo"));
256 }
257 }
258 m_menuItems.Append(pItem);
259 m_noItems++;
260 }
261*/
0e320a79
DW
262}
263
264void wxMenu::AppendSeparator()
265{
0e320a79
DW
266 Append(new wxMenuItem(this, ID_SEPARATOR));
267}
268
269// Pullright item
75f11ad7
DW
270void wxMenu::Append(int id,
271 const wxString& label,
272 wxMenu *SubMenu,
0e320a79
DW
273 const wxString& helpString)
274{
75f11ad7 275 Append(new wxMenuItem(this, id, label, helpString, FALSE, SubMenu));
0e320a79
DW
276}
277
278// Ordinary menu item
75f11ad7
DW
279void wxMenu::Append(int id,
280 const wxString& label,
281 const wxString& helpString,
282 bool checkable)
0e320a79 283{
75f11ad7
DW
284 // 'checkable' parameter is useless for Windows.
285 Append(new wxMenuItem(this, id, label, helpString, checkable));
0e320a79
DW
286}
287
75f11ad7 288// delete item by id
0e320a79
DW
289void wxMenu::Delete(int id)
290{
75f11ad7 291 wxMenuItem *item = NULL;
0e320a79 292 int pos;
75f11ad7
DW
293 wxNode *node;
294 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
295 {
296 item = (wxMenuItem *)node->Data();
297 if ( item->GetId() == id )
298 break;
0e320a79
DW
299 }
300
75f11ad7
DW
301 wxCHECK_RET( node, wxT("wxMenu::Delete(): item doesn't exist") );
302
303 HMENU menu = GetHmenu();
304
305 wxMenu *pSubMenu = item->GetSubMenu();
306 if ( pSubMenu != NULL )
307 {
308// RemoveMenu(menu, (UINT)pos, MF_BYPOSITION);
309 pSubMenu->m_hMenu = pSubMenu->m_savehMenu;
310 pSubMenu->m_savehMenu = 0;
311 pSubMenu->m_parent = NULL;
312 // RemoveChild(item->subMenu);
313 pSubMenu->m_topLevelMenu = NULL;
314 // TODO: Why isn't subMenu deleted here???
315 // Will put this in for now. Assuming this is supposed
316 // to delete the menu, not just remove it.
317 item->DeleteSubMenu();
318 }
319// else
320// {
321// DeleteMenu(menu, (UINT)pos, MF_BYPOSITION);
322// }
0e320a79
DW
323
324 m_menuItems.DeleteNode(node);
325 delete item;
75f11ad7 326}
0e320a79 327
75f11ad7
DW
328#if wxUSE_ACCEL
329
330// ---------------------------------------------------------------------------
331// accelerator helpers
332// ---------------------------------------------------------------------------
333
334// create the wxAcceleratorEntries for our accels and put them into provided
335// array - return the number of accels we have
336size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
337{
338 size_t count = GetAccelCount();
339 for ( size_t n = 0; n < count; n++ )
340 {
341 (*accels++).Set(m_accelFlags[n], m_accelKeyCodes[n], m_accelIds[n]);
342 }
343
344 return count;
0e320a79
DW
345}
346
75f11ad7
DW
347#endif // wxUSE_ACCEL
348
349// ---------------------------------------------------------------------------
350// wxMenu functions implemented in wxMenuItem
351// ---------------------------------------------------------------------------
352
353void wxMenu::Enable(int id, bool Flag)
0e320a79 354{
75f11ad7
DW
355 wxMenuItem *item = FindItemForId(id);
356 wxCHECK_RET( item != NULL, wxT("can't enable non-existing menu item") );
0e320a79
DW
357
358 item->Enable(Flag);
359}
360
75f11ad7 361bool wxMenu::IsEnabled(int id) const
0e320a79 362{
75f11ad7
DW
363 wxMenuItem *item = FindItemForId(id);
364 wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") );
0e320a79
DW
365
366 return item->IsEnabled();
367}
368
75f11ad7 369void wxMenu::Check(int id, bool Flag)
0e320a79 370{
75f11ad7
DW
371 wxMenuItem *item = FindItemForId(id);
372 wxCHECK_RET( item != NULL, wxT("can't get status of non-existing menu item") );
0e320a79
DW
373
374 item->Check(Flag);
375}
376
75f11ad7 377bool wxMenu::IsChecked(int id) const
0e320a79 378{
75f11ad7
DW
379 wxMenuItem *item = FindItemForId(id);
380 wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") );
0e320a79
DW
381
382 return item->IsChecked();
383}
384
75f11ad7 385void wxMenu::SetLabel(int id, const wxString& label)
0e320a79 386{
75f11ad7
DW
387 wxMenuItem *item = FindItemForId(id) ;
388 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
389
390 item->SetName(label);
0e320a79
DW
391}
392
75f11ad7 393wxString wxMenu::GetLabel(int id) const
0e320a79 394{
75f11ad7
DW
395 wxString label;
396 wxMenuItem *pItem = FindItemForId(id) ;
397 if (pItem)
398 label = pItem->GetName() ;
399 else
400 wxFAIL_MSG(wxT("wxMenu::GetLabel: item doesn't exist"));
401
402 return label;
0e320a79
DW
403}
404
75f11ad7 405void wxMenu::SetHelpString(int itemId, const wxString& helpString)
0e320a79 406{
75f11ad7
DW
407 wxMenuItem *item = FindItemForId (itemId);
408 if (item)
409 item->SetHelp(helpString);
0e320a79 410 else
75f11ad7 411 wxFAIL_MSG(wxT("wxMenu::SetHelpString: item doesn't exist"));
0e320a79
DW
412}
413
75f11ad7 414wxString wxMenu::GetHelpString (int itemId) const
0e320a79 415{
75f11ad7
DW
416 wxString help;
417 wxMenuItem *item = FindItemForId (itemId);
418 if (item)
419 help = item->GetHelp();
420 else
421 wxFAIL_MSG(wxT("wxMenu::GetHelpString: item doesn't exist"));
422
423 return help;
0e320a79
DW
424}
425
75f11ad7
DW
426// ---------------------------------------------------------------------------
427// wxMenu title
428// ---------------------------------------------------------------------------
429
430void wxMenu::SetTitle(const wxString& label)
0e320a79 431{
75f11ad7
DW
432 bool hasNoTitle = m_title.IsEmpty();
433 m_title = label;
0e320a79 434
75f11ad7
DW
435 HMENU hMenu = GetHmenu();
436// TODO
437/*
438 if ( hasNoTitle )
0e320a79 439 {
75f11ad7
DW
440 if ( !label.IsEmpty() )
441 {
442 if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
443 (unsigned)idMenuTitle, m_title) ||
444 !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
445 {
446 wxLogLastError(wxT("InsertMenu"));
447 }
448 }
0e320a79 449 }
75f11ad7 450 else
0e320a79 451 {
75f11ad7 452 if ( label.IsEmpty() )
0e320a79 453 {
75f11ad7
DW
454 // remove the title and the separator after it
455 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
456 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
457 {
458 wxLogLastError("RemoveMenu");
459 }
0e320a79 460 }
75f11ad7 461 else
0e320a79 462 {
75f11ad7
DW
463 // modify the title
464 if ( !ModifyMenu(hMenu, 0u,
465 MF_BYPOSITION | MF_STRING,
466 (unsigned)idMenuTitle, m_title) )
467 {
468 wxLogLastError("ModifyMenu");
469 }
0e320a79
DW
470 }
471 }
472
75f11ad7
DW
473 // put the title string in bold face
474 if ( !m_title.IsEmpty() )
475 {
476 MENUITEMINFO mii;
477 mii.cbSize = sizeof(mii);
478 mii.fMask = MIIM_STATE;
479 mii.fState = MFS_DEFAULT;
480
481 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
482 {
483 wxLogLastError("SetMenuItemInfo");
484 }
485 }
486*/
0e320a79
DW
487}
488
75f11ad7 489const wxString wxMenu::GetTitle() const
0e320a79 490{
75f11ad7 491 return m_title;
0e320a79
DW
492}
493
75f11ad7
DW
494// ---------------------------------------------------------------------------
495// event processing
496// ---------------------------------------------------------------------------
497
498bool wxMenu::OS2Command(WXUINT WXUNUSED(param), WXWORD id)
0e320a79 499{
75f11ad7
DW
500 // ignore commands from the menu title
501
502 if ( id != (WXWORD)idMenuTitle )
503 {
504 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
505 event.SetEventObject( this );
506 event.SetId( id );
507 event.SetInt( id );
508 ProcessCommand(event);
509 }
510
511 return TRUE;
0e320a79
DW
512}
513
75f11ad7 514bool wxMenu::ProcessCommand(wxCommandEvent & event)
0e320a79
DW
515{
516 bool processed = FALSE;
517
518 // Try a callback
519 if (m_callback)
520 {
75f11ad7
DW
521 (void)(*(m_callback))(*this, event);
522 processed = TRUE;
0e320a79
DW
523 }
524
525 // Try the menu's event handler
526 if ( !processed && GetEventHandler())
527 {
75f11ad7 528 processed = GetEventHandler()->ProcessEvent(event);
0e320a79 529 }
75f11ad7
DW
530
531 // Try the window the menu was popped up from (and up through the
532 // hierarchy)
533 wxWindow *win = GetInvokingWindow();
534 if ( !processed && win )
535 processed = win->GetEventHandler()->ProcessEvent(event);
536
537 return processed;
0e320a79
DW
538}
539
75f11ad7
DW
540// ---------------------------------------------------------------------------
541// Item search
542// ---------------------------------------------------------------------------
0e320a79 543
75f11ad7
DW
544// Finds the item id matching the given string, -1 if not found.
545int wxMenu::FindItem (const wxString& itemString) const
546{
547 wxString itemLabel = wxStripMenuCodes(itemString);
548 for ( wxNode *node = m_menuItems.First(); node; node = node->Next() )
0e320a79 549 {
75f11ad7
DW
550 wxMenuItem *item = (wxMenuItem *)node->Data();
551 if ( item->IsSubMenu() )
552 {
553 int ans = item->GetSubMenu()->FindItem(itemString);
554 if ( ans != wxNOT_FOUND )
555 return ans;
556 }
557 else if ( !item->IsSeparator() )
558 {
559 wxString label = wxStripMenuCodes(item->GetName());
560 if ( itemLabel == label )
561 return item->GetId();
562 }
563 }
0e320a79 564
75f11ad7
DW
565 return wxNOT_FOUND;
566}
0e320a79 567
75f11ad7
DW
568wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
569{
570 if ( itemMenu )
571 *itemMenu = NULL;
572
573 wxMenuItem *item = NULL;
574 for ( wxNode *node = m_menuItems.First(); node && !item; node = node->Next() )
575 {
576 item = (wxMenuItem *)node->Data();
577
578 if ( item->GetId() == itemId )
579 {
580 if (itemMenu)
581 *itemMenu = (wxMenu *)this;
582 }
583 else if ( item->IsSubMenu() )
584 {
585 item = item->GetSubMenu()->FindItemForId(itemId, itemMenu);
586 }
587 else
588 {
589 // don't exit the loop
590 item = NULL;
591 }
0e320a79 592 }
75f11ad7
DW
593
594 return item;
0e320a79
DW
595}
596
75f11ad7
DW
597// ---------------------------------------------------------------------------
598// other
599// ---------------------------------------------------------------------------
600
601void wxMenu::Attach(wxMenuBar *menubar)
0e320a79 602{
75f11ad7
DW
603 // menu can be in at most one menubar because otherwise they would both
604 // delete the menu pointer
605 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
0e320a79 606
75f11ad7
DW
607 m_menuBar = menubar;
608 m_savehMenu = m_hMenu;
609 m_hMenu = 0;
610}
611
612void wxMenu::Detach()
613{
614 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
615
616 m_hMenu = m_savehMenu;
617 m_savehMenu = 0;
0e320a79
DW
618}
619
75f11ad7 620// ---------------------------------------------------------------------------
0e320a79 621// Menu Bar
75f11ad7
DW
622// ---------------------------------------------------------------------------
623
624void wxMenuBar::Init()
0e320a79
DW
625{
626 m_eventHandler = this;
627 m_menuCount = 0;
628 m_menus = NULL;
629 m_titles = NULL;
630 m_menuBarFrame = NULL;
75f11ad7
DW
631 m_hMenu = 0;
632}
0e320a79 633
75f11ad7
DW
634wxMenuBar::wxMenuBar()
635{
636 Init();
0e320a79
DW
637}
638
75f11ad7 639wxMenuBar::wxMenuBar( long WXUNUSED(style) )
0e320a79 640{
75f11ad7
DW
641 Init();
642}
643
644wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
645{
646 Init();
647
648 m_menuCount = count;
0e320a79 649 m_menus = menus;
75f11ad7
DW
650 m_titles = new wxString[count];
651
0e320a79 652 int i;
75f11ad7
DW
653 for ( i = 0; i < count; i++ )
654 m_titles[i] = titles[i];
0e320a79 655
75f11ad7
DW
656 for ( i = 0; i < count; i++ )
657 m_menus[i]->Attach(this);
0e320a79
DW
658}
659
660wxMenuBar::~wxMenuBar()
661{
75f11ad7 662 for ( int i = 0; i < m_menuCount; i++ )
0e320a79
DW
663 {
664 delete m_menus[i];
665 }
75f11ad7 666
0e320a79
DW
667 delete[] m_menus;
668 delete[] m_titles;
75f11ad7 669}
0e320a79 670
75f11ad7
DW
671// ---------------------------------------------------------------------------
672// wxMenuBar helpers
673// ---------------------------------------------------------------------------
674
675void wxMenuBar::Refresh()
676{
677 wxCHECK_RET( m_menuBarFrame, wxT("can't refresh a menubar withotu a frame") );
678
679// TODO DrawMenuBar((HWND)m_menuBarFrame->GetHWND()) ;
680}
681
682WXHMENU wxMenuBar::Create()
683{
684 if (m_hMenu != 0 )
685 return m_hMenu;
686
687 wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") );
688
689 m_hMenu = 0; // TODO: (WXHMENU)::CreateMenu();
690
691 if ( !m_hMenu )
692 {
693 wxLogLastError("CreateMenu");
694 }
695 else
696 {
697 for ( int i = 0; i < m_menuCount; i++ )
698 {
699// if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
700// (UINT)m_menus[i]->GetHMenu(),
701// m_titles[i]) )
702// {
703// wxLogLastError("AppendMenu");
704// }
705 }
706 }
707
708 return m_hMenu;
0e320a79
DW
709}
710
75f11ad7
DW
711// ---------------------------------------------------------------------------
712// wxMenuBar functions forwarded to wxMenuItem
713// ---------------------------------------------------------------------------
714
0e320a79
DW
715// Must only be used AFTER menu has been attached to frame,
716// otherwise use individual menus to enable/disable items
75f11ad7 717void wxMenuBar::Enable(int id, bool enable)
0e320a79
DW
718{
719 wxMenu *itemMenu = NULL;
720 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
0e320a79 721
75f11ad7
DW
722 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
723
724 item->Enable(enable);
0e320a79
DW
725}
726
75f11ad7 727void wxMenuBar::EnableTop(int pos, bool enable)
0e320a79 728{
75f11ad7
DW
729 int flag = 0; // TODO enable ? MF_ENABLED : MF_GRAYED;;
730
731// EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
0e320a79
DW
732}
733
734// Must only be used AFTER menu has been attached to frame,
735// otherwise use individual menus
75f11ad7 736void wxMenuBar::Check(int id, bool check)
0e320a79
DW
737{
738 wxMenu *itemMenu = NULL;
739 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
0e320a79 740
75f11ad7
DW
741 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
742 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
0e320a79 743
75f11ad7 744 item->Check(check);
0e320a79
DW
745}
746
75f11ad7 747bool wxMenuBar::IsChecked(int id) const
0e320a79
DW
748{
749 wxMenu *itemMenu = NULL;
750 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
0e320a79 751
75f11ad7
DW
752 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
753
754// int flag = ::GetMenuState(GetHmenuOf(itemMenu), id, MF_BYCOMMAND);
755
756// return (flag & MF_CHECKED) != 0;
0e320a79
DW
757 return FALSE;
758}
759
75f11ad7 760bool wxMenuBar::IsEnabled(int id) const
0e320a79
DW
761{
762 wxMenu *itemMenu = NULL;
763 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
0e320a79 764
75f11ad7 765 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
0e320a79 766
75f11ad7
DW
767// int flag = ::GetMenuState(GetHmenuOf(itemMenu), id, MF_BYCOMMAND) ;
768
769 // don't "and" with MF_ENABLED because its value is 0
770// return (flag & MF_DISABLED) == 0;
771 return FALSE;
772}
0e320a79
DW
773
774void wxMenuBar::SetLabel(int id, const wxString& label)
775{
776 wxMenu *itemMenu = NULL;
777 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
778
75f11ad7 779 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
0e320a79 780
75f11ad7 781 item->SetName(label);
0e320a79
DW
782}
783
784wxString wxMenuBar::GetLabel(int id) const
785{
786 wxMenu *itemMenu = NULL;
787 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
788
75f11ad7 789 wxCHECK_MSG( item, wxT(""), wxT("wxMenuBar::GetLabel(): no such item") );
0e320a79 790
75f11ad7 791 return item->GetName();
0e320a79
DW
792}
793
75f11ad7
DW
794void wxMenuBar::SetHelpString (int id, const wxString& helpString)
795{
796 wxMenu *itemMenu = NULL;
797 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
798
799 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
800
801 item->SetHelp(helpString);
802}
803
804wxString wxMenuBar::GetHelpString (int id) const
805{
806 wxMenu *itemMenu = NULL;
807 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
808
809 wxCHECK_MSG( item, wxT(""), wxT("wxMenuBar::GetHelpString(): no such item") );
810
811 return item->GetHelp();
812}
813
814// ---------------------------------------------------------------------------
815// wxMenuBar functions to work with the top level submenus
816// ---------------------------------------------------------------------------
817
818// NB: we don't support owner drawn top level items for now, if we do these
819// functions would have to be changed to use wxMenuItem as well
820
0e320a79
DW
821void wxMenuBar::SetLabelTop(int pos, const wxString& label)
822{
75f11ad7
DW
823 UINT id;
824 UINT flagsOld = 0; // TODO: ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
825 if ( flagsOld == 0xFFFFFFFF )
826 {
827 wxLogLastError(wxT("GetMenuState"));
828
829 return;
830 }
831
832// if ( flagsOld & MF_POPUP )
833// {
834// // HIBYTE contains the number of items in the submenu in this case
835// flagsOld &= 0xff ;
836// id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos) ;
837// }
838// else
839// {
840// id = pos;
841// }
842
843// if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
844// id, label) == 0xFFFFFFFF )
845// {
846// wxLogLastError("ModifyMenu");
847// }
0e320a79
DW
848}
849
850wxString wxMenuBar::GetLabelTop(int pos) const
851{
75f11ad7
DW
852 int len = 0; // TODO: ::GetMenuString((HMENU)m_hMenu, pos, NULL, 0, MF_BYCOMMAND);
853
854 len++; // for the NUL character
855 wxString label;
856// ::GetMenuString(GetHmenu(), pos, label.GetWriteBuf(len), len, MF_BYCOMMAND);
857 label.UngetWriteBuf();
858
859 return label;
0e320a79
DW
860}
861
75f11ad7
DW
862// ---------------------------------------------------------------------------
863// wxMenuBar notifications
864// ---------------------------------------------------------------------------
865
0e320a79
DW
866bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
867{
75f11ad7
DW
868 if ( !m_menuBarFrame )
869 return TRUE;
870
0e320a79 871 // TODO
75f11ad7
DW
872/*
873 if ( ::RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION) )
874 {
875 // VZ: I'm not sure about what's going on here, so I leave an assert
876 wxASSERT_MSG( m_menus[pos] == a_menu, wxT("what is this parameter for??") );
877
878 a_menu->Detach();
879
880 if ( m_menuBarFrame )
881 Refresh();
882
883 return TRUE;
884 }
885 else
886 {
887 wxLogLastError("RemoveMenu");
888 }
889*/
0e320a79
DW
890 return FALSE;
891}
892
75f11ad7 893bool wxMenuBar::OnAppend(wxMenu *a_menu, const wxChar *title)
0e320a79 894{
75f11ad7
DW
895 WXHMENU submenu = a_menu->GetHMenu();
896 if ( !submenu )
897 return FALSE;
898
899 if ( !m_menuBarFrame )
900 return TRUE;
901
902 a_menu->Attach(this);
903
904// if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
905// (UINT)submenu, title) )
906// {
907// wxLogLastError(wxT("AppendMenu"));
908// }
909
910 Refresh();
911
912 return TRUE;
0e320a79
DW
913}
914
75f11ad7
DW
915// ---------------------------------------------------------------------------
916// wxMenuBar construction
917// ---------------------------------------------------------------------------
918int wxMenuBar::FindMenu(const wxString& title)
919{
920 wxString menuTitle = wxStripMenuCodes(title);
921 for ( int i = 0; i < m_menuCount; i++ )
922 {
923 wxString title = wxStripMenuCodes(m_titles[i]);
924 if ( menuTitle == title )
925 return i;
926 }
927
928 return wxNOT_FOUND;
929
930}
931
932
933void wxMenuBar::ReplaceMenu(int pos, wxMenu * new_menu, const wxString& title)
934{
935 if (m_menuBarFrame) return;
936
937 if ( pos >= 0 && pos < m_menuCount )
938 {
939 wxMenu *old_menu = m_menus[pos];
940 m_menus[pos] = new_menu;
941 delete old_menu;
942 }
943
944}
945
946
947void wxMenuBar::Insert(int pos, wxMenu * menu, const wxString& title)
948{
949 if (m_menuBarFrame) return;
950 if ( pos < 0 && pos >= m_menuCount ) return;
951
952 m_menuCount ++;
953 wxMenu **new_menus = new wxMenu *[m_menuCount];
954 wxString *new_titles = new wxString[m_menuCount];
955 int i;
956
957 for (i = 0; i < pos; i++)
958 {
959 new_menus[i] = m_menus[i];
960 m_menus[i] = NULL;
961 new_titles[i] = m_titles[i];
962 m_titles[i] = wxT("");
963 }
964
965 new_menus[pos] = (wxMenu *)menu;
966 new_titles[i] = title;
967
968 for (i = pos+1; i < m_menuCount; i++)
969 {
970 new_menus[i] = m_menus[i-1];
971 m_menus[i-1] = NULL;
972 new_titles[i] = m_titles[i-1];
973 m_titles[i-1] = wxT("");
974 }
975 if (m_menus)
976 {
977 delete[]m_menus;
978 delete[]m_titles;
979 }
980 m_menus = new_menus;
981 m_titles = new_titles;
982
983 menu->SetParent(this);
984
985}
986
987
0e320a79
DW
988void wxMenuBar::Append (wxMenu * menu, const wxString& title)
989{
990 if (!OnAppend(menu, title))
991 return;
992
993 m_menuCount ++;
994 wxMenu **new_menus = new wxMenu *[m_menuCount];
995 wxString *new_titles = new wxString[m_menuCount];
996 int i;
997
998 for (i = 0; i < m_menuCount - 1; i++)
75f11ad7 999 {
0e320a79
DW
1000 new_menus[i] = m_menus[i];
1001 m_menus[i] = NULL;
1002 new_titles[i] = m_titles[i];
75f11ad7 1003 m_titles[i] = wxT("");
0e320a79
DW
1004 }
1005 if (m_menus)
1006 {
1007 delete[]m_menus;
1008 delete[]m_titles;
1009 }
1010 m_menus = new_menus;
1011 m_titles = new_titles;
1012
1013 m_menus[m_menuCount - 1] = (wxMenu *)menu;
1014 m_titles[m_menuCount - 1] = title;
1015
75f11ad7 1016 menu->SetParent(this);
0e320a79
DW
1017}
1018
1019void wxMenuBar::Delete(wxMenu * menu, int i)
1020{
1021 int j;
1022 int ii = (int) i;
1023
75f11ad7
DW
1024 if (menu != 0) {
1025 for (ii = 0; ii < m_menuCount; ii++) {
0e320a79 1026 if (m_menus[ii] == menu)
75f11ad7
DW
1027 break;
1028 }
0e320a79
DW
1029 if (ii >= m_menuCount)
1030 return;
75f11ad7 1031 } else {
0e320a79
DW
1032 if (ii < 0 || ii >= m_menuCount)
1033 return;
1034 menu = m_menus[ii];
1035 }
1036
1037 if (!OnDelete(menu, ii))
1038 return;
1039
1040 menu->SetParent(NULL);
1041
1042 -- m_menuCount;
75f11ad7 1043 for (j = ii; j < m_menuCount; j++) {
0e320a79
DW
1044 m_menus[j] = m_menus[j + 1];
1045 m_titles[j] = m_titles[j + 1];
1046 }
1047}
1048
75f11ad7 1049void wxMenuBar::Attach(wxFrame *frame)
0e320a79 1050{
75f11ad7
DW
1051 wxASSERT_MSG( !m_menuBarFrame, wxT("menubar already attached!") );
1052
1053 m_menuBarFrame = frame;
1054
1055#if wxUSE_ACCEL
1056 // create the accel table - we consider that the menubar construction is
1057 // finished
1058 size_t nAccelCount = 0;
0e320a79 1059 int i;
75f11ad7
DW
1060 for ( i = 0; i < m_menuCount; i++ )
1061 {
1062 nAccelCount += m_menus[i]->GetAccelCount();
1063 }
1064
1065 if ( nAccelCount )
0e320a79 1066 {
75f11ad7
DW
1067 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
1068
1069 nAccelCount = 0;
1070 for ( i = 0; i < m_menuCount; i++ )
1071 {
1072 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
1073 }
1074
1075 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
1076
1077 delete [] accelEntries;
0e320a79 1078 }
75f11ad7 1079#endif // wxUSE_ACCEL
0e320a79
DW
1080}
1081
75f11ad7 1082void wxMenuBar::Detach()
0e320a79 1083{
75f11ad7
DW
1084// ::DestroyMenu((HMENU)m_hMenu);
1085 m_hMenu = NULL;
1086 m_menuBarFrame = NULL;
1087}
1088
1089
1090// ---------------------------------------------------------------------------
1091// wxMenuBar searching for menu items
1092// ---------------------------------------------------------------------------
1093
1094// Find the itemString in menuString, and return the item id or wxNOT_FOUND
1095int wxMenuBar::FindMenuItem(const wxString& menuString,
1096 const wxString& itemString) const
1097{
1098 wxString menuLabel = wxStripMenuCodes(menuString);
1099 for ( int i = 0; i < m_menuCount; i++ )
1100 {
1101 wxString title = wxStripMenuCodes(m_titles[i]);
1102 if ( menuString == title )
1103 return m_menus[i]->FindItem(itemString);
1104 }
1105
1106 return wxNOT_FOUND;
1107}
1108
1109wxMenuItem *wxMenuBar::FindItemForId (int id, wxMenu **itemMenu) const
1110{
1111 if ( itemMenu )
0e320a79
DW
1112 *itemMenu = NULL;
1113
1114 wxMenuItem *item = NULL;
75f11ad7
DW
1115 for ( int i = 0; !item && (i < m_menuCount); i++ )
1116 {
1117 item = m_menus[i]->FindItemForId(id, itemMenu);
1118 }
1119
1120 return item;
1121}
1122
1123
1124// ----------------------------------------------------------------------------
1125// helper functions
1126// ----------------------------------------------------------------------------
1127
1128wxWindow *wxMenu::GetWindow() const
1129{
1130 if ( m_pInvokingWindow != NULL )
1131 return m_pInvokingWindow;
1132 else if ( m_menuBar != NULL)
1133 return m_menuBar->GetFrame();
1134
0e320a79
DW
1135 return NULL;
1136}
1137
75f11ad7 1138WXHMENU wxMenu::GetHMenu() const
0e320a79 1139{
75f11ad7
DW
1140 if ( m_hMenu != 0 )
1141 return m_hMenu;
1142 else if ( m_savehMenu != 0 )
1143 return m_savehMenu;
1144
1145 wxFAIL_MSG(wxT("wxMenu without HMENU"));
1146
1147 return 0;
0e320a79
DW
1148}
1149
75f11ad7
DW
1150// Update a menu and all submenus recursively. source is the object that has
1151// the update event handlers defined for it. If NULL, the menu or associated
1152// window will be used.
1153void wxMenu::UpdateUI(wxEvtHandler* source)
0e320a79 1154{
75f11ad7
DW
1155 if (!source && GetInvokingWindow())
1156 source = GetInvokingWindow()->GetEventHandler();
1157 if (!source)
1158 source = GetEventHandler();
1159 if (!source)
1160 source = this;
1161
1162 wxNode* node = GetItems().First();
1163 while (node)
0e320a79 1164 {
75f11ad7
DW
1165 wxMenuItem* item = (wxMenuItem*) node->Data();
1166 if ( !item->IsSeparator() )
1167 {
1168 wxWindowID id = item->GetId();
1169 wxUpdateUIEvent event(id);
1170 event.SetEventObject( source );
1171
1172 if (source->ProcessEvent(event))
1173 {
1174 if (event.GetSetText())
1175 SetLabel(id, event.GetText());
1176 if (event.GetSetChecked())
1177 Check(id, event.GetChecked());
1178 if (event.GetSetEnabled())
1179 Enable(id, event.GetEnabled());
1180 }
1181
1182 if (item->GetSubMenu())
1183 item->GetSubMenu()->UpdateUI(source);
1184 }
1185 node = node->Next();
0e320a79 1186 }
0e320a79
DW
1187}
1188