]> git.saurik.com Git - wxWidgets.git/blob - src/msw/menu.cpp
added CreateAccelTable() helper which creates the accel table for just this menu
[wxWidgets.git] / src / msw / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/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
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_MENUS
28
29 #include "wx/menu.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/utils.h"
34 #include "wx/intl.h"
35 #include "wx/log.h"
36 #endif
37
38 #if wxUSE_OWNER_DRAWN
39 #include "wx/ownerdrw.h"
40 #endif
41
42 #include "wx/ptr_scpd.h"
43
44 #include "wx/msw/private.h"
45 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
46
47 #ifdef __WXWINCE__
48 #include <windows.h>
49 #include <windowsx.h>
50 #include <tchar.h>
51 #include <ole2.h>
52 #include <shellapi.h>
53 #if (_WIN32_WCE < 400) && !defined(__HANDHELDPC__)
54 #include <aygshell.h>
55 #endif
56
57 #include "wx/msw/wince/missing.h"
58
59 #endif
60
61 // other standard headers
62 #include <string.h>
63
64 //VC6 needs these defining, though they are in winuser.h
65 #ifndef MIIM_BITMAP
66 #define MIIM_STRING 0x00000040
67 #define MIIM_BITMAP 0x00000080
68 #define MIIM_FTYPE 0x00000100
69 #define HBMMENU_CALLBACK ((HBITMAP) -1)
70 typedef struct tagMENUINFO
71 {
72 DWORD cbSize;
73 DWORD fMask;
74 DWORD dwStyle;
75 UINT cyMax;
76 HBRUSH hbrBack;
77 DWORD dwContextHelpID;
78 DWORD dwMenuData;
79 } MENUINFO, FAR *LPMENUINFO;
80 #endif
81
82 #if wxUSE_OWNER_DRAWN
83 #include "wx/dynlib.h"
84 #endif
85
86 #ifndef MNS_CHECKORBMP
87 #define MNS_CHECKORBMP 0x04000000
88 #endif
89 #ifndef MIM_STYLE
90 #define MIM_STYLE 0x00000010
91 #endif
92
93 // ----------------------------------------------------------------------------
94 // global variables
95 // ----------------------------------------------------------------------------
96
97 // ----------------------------------------------------------------------------
98 // constants
99 // ----------------------------------------------------------------------------
100
101 // the (popup) menu title has this special id
102 static const UINT idMenuTitle = (UINT)-3;
103
104 // ----------------------------------------------------------------------------
105 // private functions
106 // ----------------------------------------------------------------------------
107
108 // make the given menu item default
109 static void SetDefaultMenuItem(HMENU WXUNUSED_IN_WINCE(hmenu),
110 UINT WXUNUSED_IN_WINCE(id))
111 {
112 #ifndef __WXWINCE__
113 MENUITEMINFO mii;
114 wxZeroMemory(mii);
115 mii.cbSize = sizeof(MENUITEMINFO);
116 mii.fMask = MIIM_STATE;
117 mii.fState = MFS_DEFAULT;
118
119 if ( !::SetMenuItemInfo(hmenu, id, FALSE, &mii) )
120 {
121 wxLogLastError(wxT("SetMenuItemInfo"));
122 }
123 #endif
124 }
125
126 #ifdef __WXWINCE__
127 UINT GetMenuState(HMENU hMenu, UINT id, UINT flags)
128 {
129 MENUITEMINFO info;
130 wxZeroMemory(info);
131 info.cbSize = sizeof(info);
132 info.fMask = MIIM_STATE;
133 // MF_BYCOMMAND is zero so test MF_BYPOSITION
134 if ( !::GetMenuItemInfo(hMenu, id, flags & MF_BYPOSITION ? TRUE : FALSE , & info) )
135 wxLogLastError(wxT("GetMenuItemInfo"));
136 return info.fState;
137 }
138 #endif
139
140 // ============================================================================
141 // implementation
142 // ============================================================================
143
144 #include "wx/listimpl.cpp"
145
146 WX_DEFINE_LIST( wxMenuInfoList )
147
148 #if wxUSE_EXTENDED_RTTI
149
150 WX_DEFINE_FLAGS( wxMenuStyle )
151
152 wxBEGIN_FLAGS( wxMenuStyle )
153 wxFLAGS_MEMBER(wxMENU_TEAROFF)
154 wxEND_FLAGS( wxMenuStyle )
155
156 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler,"wx/menu.h")
157
158 wxCOLLECTION_TYPE_INFO( wxMenuItem * , wxMenuItemList ) ;
159
160 template<> void wxCollectionToVariantArray( wxMenuItemList const &theList, wxxVariantArray &value)
161 {
162 wxListCollectionToVariantArray<wxMenuItemList::compatibility_iterator>( theList , value ) ;
163 }
164
165 wxBEGIN_PROPERTIES_TABLE(wxMenu)
166 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_MENU_SELECTED , wxCommandEvent)
167 wxPROPERTY( Title, wxString , SetTitle, GetTitle, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
168 wxREADONLY_PROPERTY_FLAGS( MenuStyle , wxMenuStyle , long , GetStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
169 wxPROPERTY_COLLECTION( MenuItems , wxMenuItemList , wxMenuItem* , Append , GetMenuItems , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
170 wxEND_PROPERTIES_TABLE()
171
172 wxBEGIN_HANDLERS_TABLE(wxMenu)
173 wxEND_HANDLERS_TABLE()
174
175 wxDIRECT_CONSTRUCTOR_2( wxMenu , wxString , Title , long , MenuStyle )
176
177 WX_DEFINE_FLAGS( wxMenuBarStyle )
178
179 wxBEGIN_FLAGS( wxMenuBarStyle )
180 wxFLAGS_MEMBER(wxMB_DOCKABLE)
181 wxEND_FLAGS( wxMenuBarStyle )
182
183 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
184 bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxWriter * , wxPersister * , wxxVariantArray & )
185 {
186 return true ;
187 }
188
189 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow ,"wx/menu.h",wxMenuBarStreamingCallback)
190
191 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo, wxObject , "wx/menu.h" )
192
193 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo)
194 wxREADONLY_PROPERTY( Menu , wxMenu* , GetMenu , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
195 wxREADONLY_PROPERTY( Title , wxString , GetTitle , wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
196 wxEND_PROPERTIES_TABLE()
197
198 wxBEGIN_HANDLERS_TABLE(wxMenuInfo)
199 wxEND_HANDLERS_TABLE()
200
201 wxCONSTRUCTOR_2( wxMenuInfo , wxMenu* , Menu , wxString , Title )
202
203 wxCOLLECTION_TYPE_INFO( wxMenuInfo * , wxMenuInfoList ) ;
204
205 template<> void wxCollectionToVariantArray( wxMenuInfoList const &theList, wxxVariantArray &value)
206 {
207 wxListCollectionToVariantArray<wxMenuInfoList::compatibility_iterator>( theList , value ) ;
208 }
209
210 wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
211 wxPROPERTY_COLLECTION( MenuInfos , wxMenuInfoList , wxMenuInfo* , Append , GetMenuInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
212 wxEND_PROPERTIES_TABLE()
213
214 wxBEGIN_HANDLERS_TABLE(wxMenuBar)
215 wxEND_HANDLERS_TABLE()
216
217 wxCONSTRUCTOR_DUMMY( wxMenuBar )
218
219 #else
220 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
221 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
222 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo, wxObject)
223 #endif
224
225 const wxMenuInfoList& wxMenuBar::GetMenuInfos() const
226 {
227 wxMenuInfoList* list = const_cast< wxMenuInfoList* >( &m_menuInfos ) ;
228 WX_CLEAR_LIST( wxMenuInfoList , *list ) ;
229 for( size_t i = 0 ; i < GetMenuCount() ; ++i )
230 {
231 wxMenuInfo* info = new wxMenuInfo() ;
232 info->Create( const_cast<wxMenuBar*>(this)->GetMenu(i) , GetMenuLabel(i) ) ;
233 list->Append( info ) ;
234 }
235 return m_menuInfos ;
236 }
237
238 // ---------------------------------------------------------------------------
239 // wxMenu construction, adding and removing menu items
240 // ---------------------------------------------------------------------------
241
242 // Construct a menu with optional title (then use append)
243 void wxMenu::Init()
244 {
245 m_doBreak = false;
246 m_startRadioGroup = -1;
247
248 // create the menu
249 m_hMenu = (WXHMENU)CreatePopupMenu();
250 if ( !m_hMenu )
251 {
252 wxLogLastError(wxT("CreatePopupMenu"));
253 }
254
255 // if we have a title, insert it in the beginning of the menu
256 if ( !m_title.empty() )
257 {
258 Append(idMenuTitle, m_title);
259 AppendSeparator();
260 }
261 }
262
263 // The wxWindow destructor will take care of deleting the submenus.
264 wxMenu::~wxMenu()
265 {
266 // we should free Windows resources only if Windows doesn't do it for us
267 // which happens if we're attached to a menubar or a submenu of another
268 // menu
269 if ( !IsAttached() && !GetParent() )
270 {
271 if ( !::DestroyMenu(GetHmenu()) )
272 {
273 wxLogLastError(wxT("DestroyMenu"));
274 }
275 }
276
277 #if wxUSE_ACCEL
278 // delete accels
279 WX_CLEAR_ARRAY(m_accels);
280 #endif // wxUSE_ACCEL
281 }
282
283 void wxMenu::Break()
284 {
285 // this will take effect during the next call to Append()
286 m_doBreak = true;
287 }
288
289 void wxMenu::Attach(wxMenuBarBase *menubar)
290 {
291 wxMenuBase::Attach(menubar);
292
293 EndRadioGroup();
294 }
295
296 #if wxUSE_ACCEL
297
298 int wxMenu::FindAccel(int id) const
299 {
300 size_t n, count = m_accels.GetCount();
301 for ( n = 0; n < count; n++ )
302 {
303 if ( m_accels[n]->m_command == id )
304 return n;
305 }
306
307 return wxNOT_FOUND;
308 }
309
310 void wxMenu::UpdateAccel(wxMenuItem *item)
311 {
312 if ( item->IsSubMenu() )
313 {
314 wxMenu *submenu = item->GetSubMenu();
315 wxMenuItemList::compatibility_iterator node = submenu->GetMenuItems().GetFirst();
316 while ( node )
317 {
318 UpdateAccel(node->GetData());
319
320 node = node->GetNext();
321 }
322 }
323 else if ( !item->IsSeparator() )
324 {
325 // recurse upwards: we should only modify m_accels of the top level
326 // menus, not of the submenus as wxMenuBar doesn't look at them
327 // (alternative and arguable cleaner solution would be to recurse
328 // downwards in GetAccelCount() and CopyAccels())
329 if ( GetParent() )
330 {
331 GetParent()->UpdateAccel(item);
332 return;
333 }
334
335 // find the (new) accel for this item
336 wxAcceleratorEntry *accel = wxAcceleratorEntry::Create(item->GetItemLabel());
337 if ( accel )
338 accel->m_command = item->GetId();
339
340 // find the old one
341 int n = FindAccel(item->GetId());
342 if ( n == wxNOT_FOUND )
343 {
344 // no old, add new if any
345 if ( accel )
346 m_accels.Add(accel);
347 else
348 return; // skipping RebuildAccelTable() below
349 }
350 else
351 {
352 // replace old with new or just remove the old one if no new
353 delete m_accels[n];
354 if ( accel )
355 m_accels[n] = accel;
356 else
357 m_accels.RemoveAt(n);
358 }
359
360 if ( IsAttached() )
361 {
362 GetMenuBar()->RebuildAccelTable();
363 }
364 }
365 //else: it is a separator, they can't have accels, nothing to do
366 }
367
368 #endif // wxUSE_ACCEL
369
370 // append a new item or submenu to the menu
371 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
372 {
373 #if wxUSE_ACCEL
374 UpdateAccel(pItem);
375 #endif // wxUSE_ACCEL
376
377 // we should support disabling the item even prior to adding it to the menu
378 UINT flags = pItem->IsEnabled() ? MF_ENABLED : MF_GRAYED;
379
380 // if "Break" has just been called, insert a menu break before this item
381 // (and don't forget to reset the flag)
382 if ( m_doBreak ) {
383 flags |= MF_MENUBREAK;
384 m_doBreak = false;
385 }
386
387 if ( pItem->IsSeparator() ) {
388 flags |= MF_SEPARATOR;
389 }
390
391 // id is the numeric id for normal menu items and HMENU for submenus as
392 // required by ::AppendMenu() API
393 UINT_PTR id;
394 wxMenu *submenu = pItem->GetSubMenu();
395 if ( submenu != NULL ) {
396 wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") );
397
398 submenu->SetParent(this);
399
400 id = (UINT_PTR)submenu->GetHMenu();
401
402 flags |= MF_POPUP;
403 }
404 else {
405 id = pItem->GetMSWId();
406 }
407
408
409 // prepare to insert the item in the menu
410 wxString itemText = pItem->GetItemLabel();
411 LPCTSTR pData = NULL;
412 if ( pos == (size_t)-1 )
413 {
414 // append at the end (note that the item is already appended to
415 // internal data structures)
416 pos = GetMenuItemCount() - 1;
417 }
418
419 // adjust position to account for the title, if any
420 if ( !m_title.empty() )
421 pos += 2; // for the title itself and its separator
422
423 BOOL ok = false;
424
425 #if wxUSE_OWNER_DRAWN
426 // Currently, mixing owner-drawn and non-owner-drawn items results in
427 // inconsistent margins, so we force this to be owner-drawn if any other
428 // items already are. Later we might want to use a boolean in the wxMenu
429 // to avoid search. Also we might make this fix unnecessary by getting the correct
430 // margin using NONCLIENTMETRICS.
431 if ( !pItem->IsOwnerDrawn() && !pItem->IsSeparator() )
432 {
433 // Check if any other items are ownerdrawn, and make ownerdrawn if so
434 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
435 while (node)
436 {
437 if (node->GetData()->IsOwnerDrawn())
438 {
439 pItem->SetOwnerDrawn(true);
440 break;
441 }
442 node = node->GetNext();
443 }
444 }
445 #endif
446
447 // check if we have something more than a simple text item
448 #if wxUSE_OWNER_DRAWN
449 if ( pItem->IsOwnerDrawn() )
450 {
451 // is the item owner-drawn just because of the [checked] bitmap?
452 if ( (pItem->GetBitmap(false).Ok() || pItem->GetBitmap(true).Ok()) &&
453 !pItem->GetTextColour().Ok() &&
454 !pItem->GetBackgroundColour().Ok() &&
455 !pItem->GetFont().Ok() )
456 {
457 // try to use InsertMenuItem() as it's guaranteed to look correct
458 // while our owner-drawn code is not
459 #ifndef __DMC__
460 // DMC at march 2007 doesn't have HBITMAP hbmpItem tagMENUITEMINFOA /W
461 // MIIM_BITMAP only works under WinME/2000+
462 WinStruct<MENUITEMINFO> mii;
463 if ( wxGetWinVersion() >= wxWinVersion_98 )
464 {
465 mii.fMask = MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
466 if ( pItem->IsCheckable() )
467 {
468 // need to set checked/unchecked bitmaps as otherwise our
469 // MSWOnDrawItem() item is not called
470 mii.fMask |= MIIM_CHECKMARKS;
471 }
472
473 mii.cch = itemText.length();
474 mii.dwTypeData = const_cast<wxChar *>(itemText.wx_str());
475
476 if (flags & MF_POPUP)
477 {
478 mii.fMask |= MIIM_SUBMENU;
479 mii.hSubMenu = (HMENU)pItem->GetSubMenu()->GetHMenu();
480 }
481 else
482 {
483 mii.fMask |= MIIM_ID;
484 mii.wID = id;
485 }
486
487 // we can't pass HBITMAP directly as hbmpItem for 2 reasons:
488 // 1. we can't draw it with transparency then (this is not
489 // very important now but would be with themed menu bg)
490 // 2. worse, Windows inverts the bitmap for the selected
491 // item and this looks downright ugly
492 //
493 // so instead draw it ourselves in MSWOnDrawItem()
494 mii.dwItemData = reinterpret_cast<ULONG_PTR>(pItem);
495 if ( pItem->IsCheckable() )
496 {
497 mii.hbmpChecked =
498 mii.hbmpUnchecked = HBMMENU_CALLBACK;
499 }
500 mii.hbmpItem = HBMMENU_CALLBACK;
501
502 ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii);
503 if ( !ok )
504 {
505 wxLogLastError(wxT("InsertMenuItem()"));
506 }
507 else // InsertMenuItem() ok
508 {
509 // we need to remove the extra indent which is reserved for
510 // the checkboxes by default as it looks ugly unless check
511 // boxes are used together with bitmaps and this is not the
512 // case in wx API
513 WinStruct<MENUINFO> mi;
514
515 // don't call SetMenuInfo() directly, this would prevent
516 // the app from starting up under Windows 95/NT 4
517 typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *);
518
519 wxDynamicLibrary dllUser(_T("user32"));
520 wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser);
521 if ( pfnSetMenuInfo )
522 {
523 mi.fMask = MIM_STYLE;
524 mi.dwStyle = MNS_CHECKORBMP;
525 if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) )
526 wxLogLastError(_T("SetMenuInfo(MNS_NOCHECK)"));
527 }
528
529 // tell the item that it's not really owner-drawn but only
530 // needs to draw its bitmap, the rest is done by Windows
531 pItem->ResetOwnerDrawn();
532 }
533 }
534 #endif // __DMC__
535 }
536
537 if ( !ok )
538 {
539 // item draws itself, pass pointer to it in data parameter
540 flags |= MF_OWNERDRAW;
541 pData = (LPCTSTR)pItem;
542 }
543 }
544 else
545 #endif // wxUSE_OWNER_DRAWN
546 {
547 // item is just a normal string (passed in data parameter)
548 flags |= MF_STRING;
549
550 #ifdef __WXWINCE__
551 itemText = wxMenuItem::GetLabelText(itemText);
552 #endif
553
554 pData = (wxChar*)itemText.wx_str();
555 }
556
557 // item might have already been inserted by InsertMenuItem() above
558 if ( !ok )
559 {
560 if ( !::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData) )
561 {
562 wxLogLastError(wxT("InsertMenu[Item]()"));
563
564 return false;
565 }
566 }
567
568
569 // if we just appended the title, highlight it
570 if ( id == idMenuTitle )
571 {
572 // visually select the menu title
573 SetDefaultMenuItem(GetHmenu(), id);
574 }
575
576 // if we're already attached to the menubar, we must update it
577 if ( IsAttached() && GetMenuBar()->IsAttached() )
578 {
579 GetMenuBar()->Refresh();
580 }
581
582 return true;
583 }
584
585 void wxMenu::EndRadioGroup()
586 {
587 // we're not inside a radio group any longer
588 m_startRadioGroup = -1;
589 }
590
591 wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
592 {
593 wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
594
595 bool check = false;
596
597 if ( item->GetKind() == wxITEM_RADIO )
598 {
599 int count = GetMenuItemCount();
600
601 if ( m_startRadioGroup == -1 )
602 {
603 // start a new radio group
604 m_startRadioGroup = count;
605
606 // for now it has just one element
607 item->SetAsRadioGroupStart();
608 item->SetRadioGroupEnd(m_startRadioGroup);
609
610 // ensure that we have a checked item in the radio group
611 check = true;
612 }
613 else // extend the current radio group
614 {
615 // we need to update its end item
616 item->SetRadioGroupStart(m_startRadioGroup);
617 wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_startRadioGroup);
618
619 if ( node )
620 {
621 node->GetData()->SetRadioGroupEnd(count);
622 }
623 else
624 {
625 wxFAIL_MSG( _T("where is the radio group start item?") );
626 }
627 }
628 }
629 else // not a radio item
630 {
631 EndRadioGroup();
632 }
633
634 if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
635 {
636 return NULL;
637 }
638
639 if ( check )
640 {
641 // check the item initially
642 item->Check(true);
643 }
644
645 return item;
646 }
647
648 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
649 {
650 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
651 return item;
652 else
653 return NULL;
654 }
655
656 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
657 {
658 // we need to find the item's position in the child list
659 size_t pos;
660 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
661 for ( pos = 0; node; pos++ )
662 {
663 if ( node->GetData() == item )
664 break;
665
666 node = node->GetNext();
667 }
668
669 // DoRemove() (unlike Remove) can only be called for an existing item!
670 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
671
672 #if wxUSE_ACCEL
673 // remove the corresponding accel from the accel table
674 int n = FindAccel(item->GetId());
675 if ( n != wxNOT_FOUND )
676 {
677 delete m_accels[n];
678
679 m_accels.RemoveAt(n);
680 }
681 //else: this item doesn't have an accel, nothing to do
682 #endif // wxUSE_ACCEL
683
684 // remove the item from the menu
685 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
686 {
687 wxLogLastError(wxT("RemoveMenu"));
688 }
689
690 if ( IsAttached() && GetMenuBar()->IsAttached() )
691 {
692 // otherwise, the change won't be visible
693 GetMenuBar()->Refresh();
694 }
695
696 // and from internal data structures
697 return wxMenuBase::DoRemove(item);
698 }
699
700 // ---------------------------------------------------------------------------
701 // accelerator helpers
702 // ---------------------------------------------------------------------------
703
704 #if wxUSE_ACCEL
705
706 // create the wxAcceleratorEntries for our accels and put them into the provided
707 // array - return the number of accels we have
708 size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
709 {
710 size_t count = GetAccelCount();
711 for ( size_t n = 0; n < count; n++ )
712 {
713 *accels++ = *m_accels[n];
714 }
715
716 return count;
717 }
718
719 wxAcceleratorTable *wxMenu::CreateAccelTable() const
720 {
721 const size_t count = m_accels.size();
722 wxScopedArray<wxAcceleratorEntry> accels(new wxAcceleratorEntry[count]);
723 CopyAccels(accels.get());
724
725 return new wxAcceleratorTable(count, accels.get());
726 }
727
728 #endif // wxUSE_ACCEL
729
730 // ---------------------------------------------------------------------------
731 // set wxMenu title
732 // ---------------------------------------------------------------------------
733
734 void wxMenu::SetTitle(const wxString& label)
735 {
736 bool hasNoTitle = m_title.empty();
737 m_title = label;
738
739 HMENU hMenu = GetHmenu();
740
741 if ( hasNoTitle )
742 {
743 if ( !label.empty() )
744 {
745 if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
746 idMenuTitle, m_title.wx_str()) ||
747 !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
748 {
749 wxLogLastError(wxT("InsertMenu"));
750 }
751 }
752 }
753 else
754 {
755 if ( label.empty() )
756 {
757 // remove the title and the separator after it
758 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
759 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
760 {
761 wxLogLastError(wxT("RemoveMenu"));
762 }
763 }
764 else
765 {
766 // modify the title
767 #ifdef __WXWINCE__
768 MENUITEMINFO info;
769 wxZeroMemory(info);
770 info.cbSize = sizeof(info);
771 info.fMask = MIIM_TYPE;
772 info.fType = MFT_STRING;
773 info.cch = m_title.length();
774 info.dwTypeData = const_cast<wxChar *>(m_title.wx_str());
775 if ( !SetMenuItemInfo(hMenu, 0, TRUE, & info) )
776 {
777 wxLogLastError(wxT("SetMenuItemInfo"));
778 }
779 #else
780 if ( !ModifyMenu(hMenu, 0u,
781 MF_BYPOSITION | MF_STRING,
782 idMenuTitle, m_title.wx_str()) )
783 {
784 wxLogLastError(wxT("ModifyMenu"));
785 }
786 #endif
787 }
788 }
789
790 #ifdef __WIN32__
791 // put the title string in bold face
792 if ( !m_title.empty() )
793 {
794 SetDefaultMenuItem(GetHmenu(), idMenuTitle);
795 }
796 #endif // Win32
797 }
798
799 // ---------------------------------------------------------------------------
800 // event processing
801 // ---------------------------------------------------------------------------
802
803 bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id_)
804 {
805 const int id = (signed short)id_;
806
807 // ignore commands from the menu title
808 if ( id != (int)idMenuTitle )
809 {
810 // update the check item when it's clicked
811 wxMenuItem * const item = FindItem(id);
812 if ( item && item->IsCheckable() )
813 item->Toggle();
814
815 // get the status of the menu item: note that it has been just changed
816 // by Toggle() above so here we already get the new state of the item
817 UINT menuState = ::GetMenuState(GetHmenu(), id, MF_BYCOMMAND);
818 SendEvent(id, menuState & MF_CHECKED);
819 }
820
821 return true;
822 }
823
824 // ---------------------------------------------------------------------------
825 // other
826 // ---------------------------------------------------------------------------
827
828 wxWindow *wxMenu::GetWindow() const
829 {
830 if ( m_invokingWindow != NULL )
831 return m_invokingWindow;
832 else if ( GetMenuBar() != NULL)
833 return GetMenuBar()->GetFrame();
834
835 return NULL;
836 }
837
838 // ---------------------------------------------------------------------------
839 // Menu Bar
840 // ---------------------------------------------------------------------------
841
842 void wxMenuBar::Init()
843 {
844 m_eventHandler = this;
845 m_hMenu = 0;
846 #if wxUSE_TOOLBAR && defined(__WXWINCE__)
847 m_toolBar = NULL;
848 #endif
849 // Not using a combined wxToolBar/wxMenuBar? then use
850 // a commandbar in WinCE .NET just to implement the
851 // menubar.
852 #if defined(WINCE_WITH_COMMANDBAR)
853 m_commandBar = NULL;
854 m_adornmentsAdded = false;
855 #endif
856 }
857
858 wxMenuBar::wxMenuBar()
859 {
860 Init();
861 }
862
863 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
864 {
865 Init();
866 }
867
868 wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
869 {
870 Init();
871
872 m_titles.Alloc(count);
873
874 for ( size_t i = 0; i < count; i++ )
875 {
876 m_menus.Append(menus[i]);
877 m_titles.Add(titles[i]);
878
879 menus[i]->Attach(this);
880 }
881 }
882
883 wxMenuBar::~wxMenuBar()
884 {
885 // In Windows CE (not .NET), the menubar is always associated
886 // with a toolbar, which destroys the menu implicitly.
887 #if defined(WINCE_WITHOUT_COMMANDBAR) && defined(__POCKETPC__)
888 if (GetToolBar())
889 {
890 wxToolMenuBar* toolMenuBar = wxDynamicCast(GetToolBar(), wxToolMenuBar);
891 if (toolMenuBar)
892 toolMenuBar->SetMenuBar(NULL);
893 }
894 #else
895 // we should free Windows resources only if Windows doesn't do it for us
896 // which happens if we're attached to a frame
897 if (m_hMenu && !IsAttached())
898 {
899 #if defined(WINCE_WITH_COMMANDBAR)
900 ::DestroyWindow((HWND) m_commandBar);
901 m_commandBar = (WXHWND) NULL;
902 #else
903 ::DestroyMenu((HMENU)m_hMenu);
904 #endif
905 m_hMenu = (WXHMENU)NULL;
906 }
907 #endif
908 }
909
910 // ---------------------------------------------------------------------------
911 // wxMenuBar helpers
912 // ---------------------------------------------------------------------------
913
914 void wxMenuBar::Refresh()
915 {
916 if ( IsFrozen() )
917 return;
918
919 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
920
921 #if defined(WINCE_WITHOUT_COMMANDBAR)
922 if (GetToolBar())
923 {
924 CommandBar_DrawMenuBar((HWND) GetToolBar()->GetHWND(), 0);
925 }
926 #elif defined(WINCE_WITH_COMMANDBAR)
927 if (m_commandBar)
928 DrawMenuBar((HWND) m_commandBar);
929 #else
930 DrawMenuBar(GetHwndOf(GetFrame()));
931 #endif
932 }
933
934 WXHMENU wxMenuBar::Create()
935 {
936 // Note: this doesn't work at all on Smartphone,
937 // since you have to use resources.
938 // We'll have to find another way to add a menu
939 // by changing/adding menu items to an existing menu.
940 #if defined(WINCE_WITHOUT_COMMANDBAR)
941 if ( m_hMenu != 0 )
942 return m_hMenu;
943
944 wxToolMenuBar * const bar = static_cast<wxToolMenuBar *>(GetToolBar());
945 if ( !bar )
946 return NULL;
947
948 HWND hCommandBar = GetHwndOf(bar);
949
950 // notify comctl32.dll about the version of the headers we use before using
951 // any other TB_XXX messages
952 SendMessage(hCommandBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
953
954 TBBUTTON tbButton;
955 wxZeroMemory(tbButton);
956 tbButton.iBitmap = I_IMAGENONE;
957 tbButton.fsState = TBSTATE_ENABLED;
958 tbButton.fsStyle = TBSTYLE_DROPDOWN |
959 TBSTYLE_NO_DROPDOWN_ARROW |
960 TBSTYLE_AUTOSIZE;
961
962 for ( unsigned i = 0; i < GetMenuCount(); i++ )
963 {
964 HMENU hPopupMenu = (HMENU) GetMenu(i)->GetHMenu();
965 tbButton.dwData = (DWORD)hPopupMenu;
966 wxString label = wxStripMenuCodes(GetMenuLabel(i));
967 tbButton.iString = (int) label.wx_str();
968
969 tbButton.idCommand = NewControlId();
970 if ( !::SendMessage(hCommandBar, TB_INSERTBUTTON, i, (LPARAM)&tbButton) )
971 {
972 wxLogLastError(wxT("TB_INSERTBUTTON"));
973 }
974 }
975
976 m_hMenu = bar->GetHMenu();
977 return m_hMenu;
978 #else // !__WXWINCE__
979 if ( m_hMenu != 0 )
980 return m_hMenu;
981
982 m_hMenu = (WXHMENU)::CreateMenu();
983
984 if ( !m_hMenu )
985 {
986 wxLogLastError(wxT("CreateMenu"));
987 }
988 else
989 {
990 size_t count = GetMenuCount(), i;
991 wxMenuList::iterator it;
992 for ( i = 0, it = m_menus.begin(); i < count; i++, it++ )
993 {
994 if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
995 (UINT_PTR)(*it)->GetHMenu(),
996 m_titles[i].wx_str()) )
997 {
998 wxLogLastError(wxT("AppendMenu"));
999 }
1000 }
1001 }
1002
1003 return m_hMenu;
1004 #endif // __WXWINCE__/!__WXWINCE__
1005 }
1006
1007 int wxMenuBar::MSWPositionForWxMenu(wxMenu *menu, int wxpos)
1008 {
1009 wxASSERT(menu);
1010 wxASSERT(menu->GetHMenu());
1011 wxASSERT(m_hMenu);
1012
1013 #if defined(__WXWINCE__)
1014 int totalMSWItems = GetMenuCount();
1015 #else
1016 int totalMSWItems = GetMenuItemCount((HMENU)m_hMenu);
1017 #endif
1018
1019 int i; // For old C++ compatibility
1020 for(i=wxpos; i<totalMSWItems; i++)
1021 {
1022 if(GetSubMenu((HMENU)m_hMenu,i)==(HMENU)menu->GetHMenu())
1023 return i;
1024 }
1025 for(i=0; i<wxpos; i++)
1026 {
1027 if(GetSubMenu((HMENU)m_hMenu,i)==(HMENU)menu->GetHMenu())
1028 return i;
1029 }
1030 wxFAIL;
1031 return -1;
1032 }
1033
1034 // ---------------------------------------------------------------------------
1035 // wxMenuBar functions to work with the top level submenus
1036 // ---------------------------------------------------------------------------
1037
1038 // NB: we don't support owner drawn top level items for now, if we do these
1039 // functions would have to be changed to use wxMenuItem as well
1040
1041 void wxMenuBar::EnableTop(size_t pos, bool enable)
1042 {
1043 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
1044 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
1045
1046 int flag = enable ? MF_ENABLED : MF_GRAYED;
1047
1048 EnableMenuItem((HMENU)m_hMenu, MSWPositionForWxMenu(GetMenu(pos),pos), MF_BYPOSITION | flag);
1049
1050 Refresh();
1051 }
1052
1053 void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
1054 {
1055 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
1056
1057 m_titles[pos] = label;
1058
1059 if ( !IsAttached() )
1060 {
1061 return;
1062 }
1063 //else: have to modify the existing menu
1064
1065 int mswpos = MSWPositionForWxMenu(GetMenu(pos),pos);
1066
1067 UINT_PTR id;
1068 UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, mswpos, MF_BYPOSITION);
1069 if ( flagsOld == 0xFFFFFFFF )
1070 {
1071 wxLogLastError(wxT("GetMenuState"));
1072
1073 return;
1074 }
1075
1076 if ( flagsOld & MF_POPUP )
1077 {
1078 // HIBYTE contains the number of items in the submenu in this case
1079 flagsOld &= 0xff;
1080 id = (UINT_PTR)::GetSubMenu((HMENU)m_hMenu, mswpos);
1081 }
1082 else
1083 {
1084 id = pos;
1085 }
1086
1087 #ifdef __WXWINCE__
1088 MENUITEMINFO info;
1089 wxZeroMemory(info);
1090 info.cbSize = sizeof(info);
1091 info.fMask = MIIM_TYPE;
1092 info.fType = MFT_STRING;
1093 info.cch = label.length();
1094 info.dwTypeData = const_cast<wxChar *>(label.wx_str());
1095 if ( !SetMenuItemInfo(GetHmenu(), id, TRUE, &info) )
1096 {
1097 wxLogLastError(wxT("SetMenuItemInfo"));
1098 }
1099
1100 #else
1101 if ( ::ModifyMenu(GetHmenu(), mswpos, MF_BYPOSITION | MF_STRING | flagsOld,
1102 id, label.wx_str()) == (int)0xFFFFFFFF )
1103 {
1104 wxLogLastError(wxT("ModifyMenu"));
1105 }
1106 #endif
1107
1108 Refresh();
1109 }
1110
1111 wxString wxMenuBar::GetMenuLabel(size_t pos) const
1112 {
1113 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
1114 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
1115
1116 return m_titles[pos];
1117 }
1118
1119 // ---------------------------------------------------------------------------
1120 // wxMenuBar construction
1121 // ---------------------------------------------------------------------------
1122
1123 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
1124 {
1125 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
1126 if ( !menuOld )
1127 return NULL;
1128
1129 m_titles[pos] = title;
1130
1131 #if defined(WINCE_WITHOUT_COMMANDBAR)
1132 if (IsAttached())
1133 #else
1134 if (GetHmenu())
1135 #endif
1136 {
1137 int mswpos = MSWPositionForWxMenu(menuOld,pos);
1138
1139 // can't use ModifyMenu() because it deletes the submenu it replaces
1140 if ( !::RemoveMenu(GetHmenu(), (UINT)mswpos, MF_BYPOSITION) )
1141 {
1142 wxLogLastError(wxT("RemoveMenu"));
1143 }
1144
1145 if ( !::InsertMenu(GetHmenu(), (UINT)mswpos,
1146 MF_BYPOSITION | MF_POPUP | MF_STRING,
1147 (UINT_PTR)GetHmenuOf(menu), title.wx_str()) )
1148 {
1149 wxLogLastError(wxT("InsertMenu"));
1150 }
1151
1152 #if wxUSE_ACCEL
1153 if ( menuOld->HasAccels() || menu->HasAccels() )
1154 {
1155 // need to rebuild accell table
1156 RebuildAccelTable();
1157 }
1158 #endif // wxUSE_ACCEL
1159
1160 if (IsAttached())
1161 Refresh();
1162 }
1163
1164 return menuOld;
1165 }
1166
1167 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
1168 {
1169 // Find out which MSW item before which we'll be inserting before
1170 // wxMenuBarBase::Insert is called and GetMenu(pos) is the new menu.
1171 // If IsAttached() is false this won't be used anyway
1172 bool isAttached =
1173 #if defined(WINCE_WITHOUT_COMMANDBAR)
1174 IsAttached();
1175 #else
1176 (GetHmenu() != 0);
1177 #endif
1178
1179 int mswpos = (!isAttached || (pos == m_menus.GetCount()))
1180 ? -1 // append the menu
1181 : MSWPositionForWxMenu(GetMenu(pos),pos);
1182
1183 if ( !wxMenuBarBase::Insert(pos, menu, title) )
1184 return false;
1185
1186 m_titles.Insert(title, pos);
1187
1188 if ( isAttached )
1189 {
1190 #if defined(WINCE_WITHOUT_COMMANDBAR)
1191 if (!GetToolBar())
1192 return false;
1193 TBBUTTON tbButton;
1194 memset(&tbButton, 0, sizeof(TBBUTTON));
1195 tbButton.iBitmap = I_IMAGENONE;
1196 tbButton.fsState = TBSTATE_ENABLED;
1197 tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE;
1198
1199 HMENU hPopupMenu = (HMENU) menu->GetHMenu() ;
1200 tbButton.dwData = (DWORD)hPopupMenu;
1201 wxString label = wxStripMenuCodes(title);
1202 tbButton.iString = (int) label.wx_str();
1203
1204 tbButton.idCommand = NewControlId();
1205 if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_INSERTBUTTON, pos, (LPARAM)&tbButton))
1206 {
1207 wxLogLastError(wxT("TB_INSERTBUTTON"));
1208 return false;
1209 }
1210 wxUnusedVar(mswpos);
1211 #else
1212 if ( !::InsertMenu(GetHmenu(), mswpos,
1213 MF_BYPOSITION | MF_POPUP | MF_STRING,
1214 (UINT_PTR)GetHmenuOf(menu), title.wx_str()) )
1215 {
1216 wxLogLastError(wxT("InsertMenu"));
1217 }
1218 #endif
1219 #if wxUSE_ACCEL
1220 if ( menu->HasAccels() )
1221 {
1222 // need to rebuild accell table
1223 RebuildAccelTable();
1224 }
1225 #endif // wxUSE_ACCEL
1226
1227 if (IsAttached())
1228 Refresh();
1229 }
1230
1231 return true;
1232 }
1233
1234 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
1235 {
1236 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
1237 wxCHECK_MSG( submenu, false, wxT("can't append invalid menu to menubar") );
1238
1239 if ( !wxMenuBarBase::Append(menu, title) )
1240 return false;
1241
1242 m_titles.Add(title);
1243
1244 #if defined(WINCE_WITHOUT_COMMANDBAR)
1245 if (IsAttached())
1246 #else
1247 if (GetHmenu())
1248 #endif
1249 {
1250 #if defined(WINCE_WITHOUT_COMMANDBAR)
1251 if (!GetToolBar())
1252 return false;
1253 TBBUTTON tbButton;
1254 memset(&tbButton, 0, sizeof(TBBUTTON));
1255 tbButton.iBitmap = I_IMAGENONE;
1256 tbButton.fsState = TBSTATE_ENABLED;
1257 tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE;
1258
1259 size_t pos = GetMenuCount();
1260 HMENU hPopupMenu = (HMENU) menu->GetHMenu() ;
1261 tbButton.dwData = (DWORD)hPopupMenu;
1262 wxString label = wxStripMenuCodes(title);
1263 tbButton.iString = (int) label.wx_str();
1264
1265 tbButton.idCommand = NewControlId();
1266 if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_INSERTBUTTON, pos, (LPARAM)&tbButton))
1267 {
1268 wxLogLastError(wxT("TB_INSERTBUTTON"));
1269 return false;
1270 }
1271 #else
1272 if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
1273 (UINT_PTR)submenu, title.wx_str()) )
1274 {
1275 wxLogLastError(wxT("AppendMenu"));
1276 }
1277 #endif
1278
1279 #if wxUSE_ACCEL
1280 if ( menu->HasAccels() )
1281 {
1282 // need to rebuild accelerator table
1283 RebuildAccelTable();
1284 }
1285 #endif // wxUSE_ACCEL
1286
1287 if (IsAttached())
1288 Refresh();
1289 }
1290
1291 return true;
1292 }
1293
1294 wxMenu *wxMenuBar::Remove(size_t pos)
1295 {
1296 wxMenu *menu = wxMenuBarBase::Remove(pos);
1297 if ( !menu )
1298 return NULL;
1299
1300 #if defined(WINCE_WITHOUT_COMMANDBAR)
1301 if (IsAttached())
1302 #else
1303 if (GetHmenu())
1304 #endif
1305 {
1306 #if defined(WINCE_WITHOUT_COMMANDBAR)
1307 if (GetToolBar())
1308 {
1309 if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_DELETEBUTTON, (UINT) pos, (LPARAM) 0))
1310 {
1311 wxLogLastError(wxT("TB_DELETEBUTTON"));
1312 }
1313 }
1314 #else
1315 if ( !::RemoveMenu(GetHmenu(), (UINT)MSWPositionForWxMenu(menu,pos), MF_BYPOSITION) )
1316 {
1317 wxLogLastError(wxT("RemoveMenu"));
1318 }
1319 #endif
1320
1321 #if wxUSE_ACCEL
1322 if ( menu->HasAccels() )
1323 {
1324 // need to rebuild accell table
1325 RebuildAccelTable();
1326 }
1327 #endif // wxUSE_ACCEL
1328
1329 if (IsAttached())
1330 Refresh();
1331 }
1332
1333 m_titles.RemoveAt(pos);
1334
1335 return menu;
1336 }
1337
1338 #if wxUSE_ACCEL
1339
1340 void wxMenuBar::RebuildAccelTable()
1341 {
1342 // merge the accelerators of all menus into one accel table
1343 size_t nAccelCount = 0;
1344 size_t i, count = GetMenuCount();
1345 wxMenuList::iterator it;
1346 for ( i = 0, it = m_menus.begin(); i < count; i++, it++ )
1347 {
1348 nAccelCount += (*it)->GetAccelCount();
1349 }
1350
1351 if ( nAccelCount )
1352 {
1353 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
1354
1355 nAccelCount = 0;
1356 for ( i = 0, it = m_menus.begin(); i < count; i++, it++ )
1357 {
1358 nAccelCount += (*it)->CopyAccels(&accelEntries[nAccelCount]);
1359 }
1360
1361 SetAcceleratorTable(wxAcceleratorTable(nAccelCount, accelEntries));
1362
1363 delete [] accelEntries;
1364 }
1365 }
1366
1367 #endif // wxUSE_ACCEL
1368
1369 void wxMenuBar::Attach(wxFrame *frame)
1370 {
1371 wxMenuBarBase::Attach(frame);
1372
1373 #if defined(WINCE_WITH_COMMANDBAR)
1374 if (!m_hMenu)
1375 this->Create();
1376 if (!m_commandBar)
1377 m_commandBar = (WXHWND) CommandBar_Create(wxGetInstance(), (HWND) frame->GetHWND(), NewControlId());
1378 if (m_commandBar)
1379 {
1380 if (m_hMenu)
1381 {
1382 if (!CommandBar_InsertMenubarEx((HWND) m_commandBar, NULL, (LPTSTR) m_hMenu, 0))
1383 {
1384 wxLogLastError(wxT("CommandBar_InsertMenubarEx"));
1385 }
1386 }
1387 }
1388 #endif
1389
1390 #if wxUSE_ACCEL
1391 RebuildAccelTable();
1392 #endif // wxUSE_ACCEL
1393 }
1394
1395 #if defined(WINCE_WITH_COMMANDBAR)
1396 bool wxMenuBar::AddAdornments(long style)
1397 {
1398 if (m_adornmentsAdded || !m_commandBar)
1399 return false;
1400
1401 if (style & wxCLOSE_BOX)
1402 {
1403 if (!CommandBar_AddAdornments((HWND) m_commandBar, 0, 0))
1404 wxLogLastError(wxT("CommandBar_AddAdornments"));
1405 else
1406 return true;
1407 }
1408 return false;
1409 }
1410 #endif
1411
1412 void wxMenuBar::Detach()
1413 {
1414 wxMenuBarBase::Detach();
1415 }
1416
1417 #endif // wxUSE_MENUS