1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxMenuItem implementation
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "menuitem.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
35 #include "wx/bitmap.h"
36 #include "wx/settings.h"
38 #include "wx/window.h"
41 #include "wx/string.h"
44 #include "wx/menuitem.h"
51 #include "wx/msw/private.h"
54 // Implemented in menu.cpp
55 UINT
GetMenuState(HMENU hMenu
, UINT id
, UINT flags
) ;
58 // ---------------------------------------------------------------------------
60 // ---------------------------------------------------------------------------
63 #define GetHMenuOf(menu) ((HMENU)menu->GetHMenu())
65 // conditional compilation
67 #define OWNER_DRAWN_ONLY( code ) if ( IsOwnerDrawn() ) code
68 #else // !wxUSE_OWNER_DRAWN
69 #define OWNER_DRAWN_ONLY( code )
70 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
72 // ============================================================================
74 // ============================================================================
76 // ----------------------------------------------------------------------------
77 // dynamic classes implementation
78 // ----------------------------------------------------------------------------
80 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
82 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
89 wxMenuItem::wxMenuItem(wxMenu
*pParentMenu
,
92 const wxString
& strHelp
,
95 : wxMenuItemBase(pParentMenu
, id
, text
, strHelp
, kind
, pSubMenu
)
97 , wxOwnerDrawn(text
, kind
== wxITEM_CHECK
)
103 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
105 const wxString
& text
,
106 const wxString
& help
,
109 : wxMenuItemBase(parentMenu
, id
, text
, help
,
110 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
111 #if wxUSE_OWNER_DRAWN
112 , wxOwnerDrawn(text
, isCheckable
, true)
113 #endif // owner drawn
118 void wxMenuItem::Init()
120 m_radioGroup
.start
= -1;
121 m_isRadioGroupStart
= FALSE
;
123 #if wxUSE_OWNER_DRAWN
124 // set default menu colors
125 #define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
127 SetTextColour(SYS_COLOR(MENUTEXT
));
128 SetBackgroundColour(SYS_COLOR(MENU
));
132 // we don't want normal items be owner-drawn
135 // tell the owner drawing code to to show the accel string as well
136 SetAccelString(m_text
.AfterFirst(_T('\t')));
137 #endif // wxUSE_OWNER_DRAWN
140 wxMenuItem::~wxMenuItem()
147 // return the id for calling Win32 API functions
148 int wxMenuItem::GetRealId() const
150 return m_subMenu
? (int)m_subMenu
->GetHMenu() : GetId();
156 bool wxMenuItem::IsChecked() const
158 int flag
= ::GetMenuState(GetHMenuOf(m_parentMenu
), GetId(), MF_BYCOMMAND
);
160 return (flag
& MF_CHECKED
) != 0;
164 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
166 return wxStripMenuCodes(text
);
172 void wxMenuItem::SetAsRadioGroupStart()
174 m_isRadioGroupStart
= TRUE
;
177 void wxMenuItem::SetRadioGroupStart(int start
)
179 wxASSERT_MSG( !m_isRadioGroupStart
,
180 _T("should only be called for the next radio items") );
182 m_radioGroup
.start
= start
;
185 void wxMenuItem::SetRadioGroupEnd(int end
)
187 wxASSERT_MSG( m_isRadioGroupStart
,
188 _T("should only be called for the first radio item") );
190 m_radioGroup
.end
= end
;
196 void wxMenuItem::Enable(bool enable
)
198 if ( m_isEnabled
== enable
)
201 long rc
= EnableMenuItem(GetHMenuOf(m_parentMenu
),
204 (enable
? MF_ENABLED
: MF_GRAYED
));
207 wxLogLastError(wxT("EnableMenuItem"));
210 wxMenuItemBase::Enable(enable
);
213 void wxMenuItem::Check(bool check
)
215 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
217 if ( m_isChecked
== check
)
220 int flags
= check
? MF_CHECKED
: MF_UNCHECKED
;
221 HMENU hmenu
= GetHMenuOf(m_parentMenu
);
223 if ( GetKind() == wxITEM_RADIO
)
225 // it doesn't make sense to uncheck a radio item - what would this do?
229 // get the index of this item in the menu
230 const wxMenuItemList
& items
= m_parentMenu
->GetMenuItems();
231 int pos
= items
.IndexOf(this);
232 wxCHECK_RET( pos
!= wxNOT_FOUND
,
233 _T("menuitem not found in the menu items list?") );
235 // get the radio group range
239 if ( m_isRadioGroupStart
)
241 // we already have all information we need
243 end
= m_radioGroup
.end
;
245 else // next radio group item
247 // get the radio group end from the start item
248 start
= m_radioGroup
.start
;
249 end
= items
.Item(start
)->GetData()->m_radioGroup
.end
;
253 // calling CheckMenuRadioItem() with such parameters hangs my system
254 // (NT4 SP6) and I suspect this could happen to the others as well - so
256 wxCHECK_RET( start
!= -1 && end
!= -1,
257 _T("invalid ::CheckMenuRadioItem() parameter(s)") );
259 if ( !::CheckMenuRadioItem(hmenu
,
260 start
, // the first radio group item
262 pos
, // the one to check
265 wxLogLastError(_T("CheckMenuRadioItem"));
269 // also uncheck all the other items in this radio group
270 wxMenuItemList::compatibility_iterator node
= items
.Item(start
);
271 for ( int n
= start
; n
<= end
&& node
; n
++ )
275 node
->GetData()->m_isChecked
= FALSE
;
278 // we also have to do it in the menu for Win16 (under Win32
279 // CheckMenuRadioItem() does it for us)
281 ::CheckMenuItem(hmenu
, n
, n
== pos
? MF_CHECKED
: MF_UNCHECKED
);
284 node
= node
->GetNext();
289 if ( ::CheckMenuItem(hmenu
,
291 MF_BYCOMMAND
| flags
) == (DWORD
)-1 )
293 wxLogLastError(wxT("CheckMenuItem"));
297 wxMenuItemBase::Check(check
);
300 void wxMenuItem::SetText(const wxString
& text
)
302 // don't do anything if label didn't change
303 if ( m_text
== text
)
306 wxMenuItemBase::SetText(text
);
307 OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(text
) );
308 #if wxUSE_OWNER_DRAWN
309 // tell the owner drawing code to to show the accel string as well
310 SetAccelString(text
.AfterFirst(_T('\t')));
313 HMENU hMenu
= GetHMenuOf(m_parentMenu
);
314 wxCHECK_RET( hMenu
, wxT("menuitem without menu") );
317 m_parentMenu
->UpdateAccel(this);
318 #endif // wxUSE_ACCEL
320 UINT id
= GetRealId();
321 UINT flagsOld
= ::GetMenuState(hMenu
, id
, MF_BYCOMMAND
);
322 if ( flagsOld
== 0xFFFFFFFF )
324 wxLogLastError(wxT("GetMenuState"));
330 // high byte contains the number of items in a submenu for submenus
332 flagsOld
|= MF_POPUP
;
337 #if wxUSE_OWNER_DRAWN
338 if ( IsOwnerDrawn() )
340 flagsOld
|= MF_OWNERDRAW
;
341 data
= (LPCTSTR
)this;
346 flagsOld
|= MF_STRING
;
347 data
= (wxChar
*) text
.c_str();
351 // FIXME: complete this, applying the old
353 // However, the WinCE doc for SetMenuItemInfo
354 // says that you can't use it to set the menu
355 // item state; only data, id and type.
358 info
.cbSize
= sizeof(info
);
359 info
.fMask
= MIIM_TYPE
;
360 info
.fType
= MFT_STRING
;
361 info
.cch
= text
.Length();
362 info
.dwTypeData
= (LPTSTR
) data
;
363 if ( !SetMenuItemInfo(hMenu
, id
, FALSE
, & info
) )
365 wxLogLastError(wxT("SetMenuItemInfo"));
368 if ( ::ModifyMenu(hMenu
, id
,
369 MF_BYCOMMAND
| flagsOld
,
370 id
, data
) == (int)0xFFFFFFFF )
372 wxLogLastError(wxT("ModifyMenu"));
378 void wxMenuItem::SetCheckable(bool checkable
)
380 wxMenuItemBase::SetCheckable(checkable
);
381 OWNER_DRAWN_ONLY( wxOwnerDrawn::SetCheckable(checkable
) );
384 // ----------------------------------------------------------------------------
386 // ----------------------------------------------------------------------------
388 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
390 const wxString
& name
,
391 const wxString
& help
,
395 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
398 #endif // wxUSE_MENUS