]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menuitem.cpp
Applied patch [ 774886 ] wxnotebook bug
[wxWidgets.git] / src / msw / menuitem.cpp
CommitLineData
2bda0e17
KB
1///////////////////////////////////////////////////////////////////////////////
2// Name: menuitem.cpp
3// Purpose: wxMenuItem implementation
4// Author: Vadim Zeitlin
c2dcfdef 5// Modified by:
2bda0e17
KB
6// Created: 11.11.97
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
6c9a19aa 9// Licence: wxWindows licence
2bda0e17
KB
10///////////////////////////////////////////////////////////////////////////////
11
c2dcfdef
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
a3b46648 20#ifdef __GNUG__
c2dcfdef 21 #pragma implementation "menuitem.h"
a3b46648 22#endif
2bda0e17
KB
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
c2dcfdef 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
1e6feb95
VZ
31#if wxUSE_MENUS
32
2bda0e17 33#ifndef WX_PRECOMP
c2dcfdef
VZ
34 #include "wx/font.h"
35 #include "wx/bitmap.h"
36 #include "wx/settings.h"
37 #include "wx/font.h"
4e938f5b 38 #include "wx/window.h"
0c589ad0
BM
39 #include "wx/accel.h"
40 #include "wx/menu.h"
41 #include "wx/string.h"
2bda0e17
KB
42#endif
43
2bda0e17 44#include "wx/menuitem.h"
6776a0b2 45#include "wx/log.h"
2bda0e17 46
717a57c2
VZ
47#if wxUSE_ACCEL
48 #include "wx/accel.h"
49#endif // wxUSE_ACCEL
50
42e69d6b 51#include "wx/msw/private.h"
ce3ed50d 52
4676948b
JS
53#ifdef __WXWINCE__
54// Implemented in menu.cpp
55UINT GetMenuState(HMENU hMenu, UINT id, UINT flags) ;
56#endif
57
c2dcfdef 58// ---------------------------------------------------------------------------
974e8d94 59// macro
c2dcfdef
VZ
60// ---------------------------------------------------------------------------
61
974e8d94 62// hide the ugly cast
c2dcfdef
VZ
63#define GetHMenuOf(menu) ((HMENU)menu->GetHMenu())
64
974e8d94
VZ
65// conditional compilation
66#if wxUSE_OWNER_DRAWN
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
71
2bda0e17
KB
72// ============================================================================
73// implementation
74// ============================================================================
75
76// ----------------------------------------------------------------------------
77// dynamic classes implementation
78// ----------------------------------------------------------------------------
79
621b3e21 80IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
2bda0e17
KB
81
82// ----------------------------------------------------------------------------
83// wxMenuItem
84// ----------------------------------------------------------------------------
85
86// ctor & dtor
87// -----------
88
974e8d94
VZ
89wxMenuItem::wxMenuItem(wxMenu *pParentMenu,
90 int id,
91 const wxString& text,
92 const wxString& strHelp,
d65c269b 93 wxItemKind kind,
90002c49 94 wxMenu *pSubMenu)
d65c269b 95 : wxMenuItemBase(pParentMenu, id, text, strHelp, kind, pSubMenu)
47d67540 96#if wxUSE_OWNER_DRAWN
f6278a74 97 , wxOwnerDrawn(text, kind == wxITEM_CHECK)
974e8d94 98#endif // owner drawn
2bda0e17 99{
2368dcda
VZ
100 Init();
101}
2bda0e17 102
2368dcda
VZ
103wxMenuItem::wxMenuItem(wxMenu *parentMenu,
104 int id,
105 const wxString& text,
106 const wxString& help,
107 bool isCheckable,
108 wxMenu *subMenu)
109 : wxMenuItemBase(parentMenu, id, text, help,
110 isCheckable ? wxITEM_CHECK : wxITEM_NORMAL, subMenu)
111#if wxUSE_OWNER_DRAWN
19b42379 112 , wxOwnerDrawn(text, isCheckable, true)
2368dcda
VZ
113#endif // owner drawn
114{
115 Init();
116}
117
118void wxMenuItem::Init()
119{
be15b995
VZ
120 m_radioGroup.start = -1;
121 m_isRadioGroupStart = FALSE;
0472ece7 122
47d67540 123#if wxUSE_OWNER_DRAWN
2bda0e17 124 // set default menu colors
a756f210 125 #define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
c2dcfdef 126
2bda0e17
KB
127 SetTextColour(SYS_COLOR(MENUTEXT));
128 SetBackgroundColour(SYS_COLOR(MENU));
129
6d5b2a57
VZ
130 #undef SYS_COLOR
131
2bda0e17
KB
132 // we don't want normal items be owner-drawn
133 ResetOwnerDrawn();
134
6d5b2a57 135 // tell the owner drawing code to to show the accel string as well
2368dcda 136 SetAccelString(m_text.AfterFirst(_T('\t')));
974e8d94 137#endif // wxUSE_OWNER_DRAWN
2bda0e17
KB
138}
139
c2dcfdef 140wxMenuItem::~wxMenuItem()
2bda0e17
KB
141{
142}
143
144// misc
145// ----
146
c2dcfdef
VZ
147// return the id for calling Win32 API functions
148int wxMenuItem::GetRealId() const
149{
974e8d94 150 return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId();
c2dcfdef
VZ
151}
152
3dfac970
VZ
153// get item state
154// --------------
155
a8cfd0cb 156bool wxMenuItem::IsChecked() const
3dfac970 157{
a8cfd0cb 158 int flag = ::GetMenuState(GetHMenuOf(m_parentMenu), GetId(), MF_BYCOMMAND);
3dfac970 159
4aee367e 160 return (flag & MF_CHECKED) != 0;
3dfac970
VZ
161}
162
3b59cdbf
VZ
163/* static */
164wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
717a57c2 165{
4a3563c5 166 return wxStripMenuCodes(text);
717a57c2
VZ
167}
168
be15b995
VZ
169// radio group stuff
170// -----------------
171
172void wxMenuItem::SetAsRadioGroupStart()
173{
174 m_isRadioGroupStart = TRUE;
175}
176
177void wxMenuItem::SetRadioGroupStart(int start)
178{
179 wxASSERT_MSG( !m_isRadioGroupStart,
180 _T("should only be called for the next radio items") );
181
182 m_radioGroup.start = start;
183}
184
185void wxMenuItem::SetRadioGroupEnd(int end)
186{
187 wxASSERT_MSG( m_isRadioGroupStart,
188 _T("should only be called for the first radio item") );
189
190 m_radioGroup.end = end;
191}
192
2bda0e17
KB
193// change item state
194// -----------------
195
717a57c2 196void wxMenuItem::Enable(bool enable)
2bda0e17 197{
717a57c2
VZ
198 if ( m_isEnabled == enable )
199 return;
200
201 long rc = EnableMenuItem(GetHMenuOf(m_parentMenu),
202 GetRealId(),
203 MF_BYCOMMAND |
204 (enable ? MF_ENABLED : MF_GRAYED));
c2dcfdef 205
717a57c2 206 if ( rc == -1 ) {
f6bcfd97 207 wxLogLastError(wxT("EnableMenuItem"));
c2dcfdef 208 }
717a57c2
VZ
209
210 wxMenuItemBase::Enable(enable);
2bda0e17
KB
211}
212
717a57c2 213void wxMenuItem::Check(bool check)
2bda0e17 214{
d65c269b 215 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
c2dcfdef 216
717a57c2
VZ
217 if ( m_isChecked == check )
218 return;
c2dcfdef 219
0472ece7
VZ
220 int flags = check ? MF_CHECKED : MF_UNCHECKED;
221 HMENU hmenu = GetHMenuOf(m_parentMenu);
222
546bfbea 223 if ( GetKind() == wxITEM_RADIO )
0472ece7
VZ
224 {
225 // it doesn't make sense to uncheck a radio item - what would this do?
226 if ( !check )
227 return;
228
be15b995 229 // get the index of this item in the menu
0472ece7
VZ
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?") );
234
be15b995
VZ
235 // get the radio group range
236 int start,
237 end;
238
239 if ( m_isRadioGroupStart )
240 {
241 // we already have all information we need
242 start = pos;
243 end = m_radioGroup.end;
244 }
245 else // next radio group item
246 {
247 // get the radio group end from the start item
248 start = m_radioGroup.start;
249 end = items.Item(start)->GetData()->m_radioGroup.end;
250 }
251
0472ece7 252#ifdef __WIN32__
be15b995
VZ
253 // calling CheckMenuRadioItem() with such parameters hangs my system
254 // (NT4 SP6) and I suspect this could happen to the others as well - so
255 // don't do it!
256 wxCHECK_RET( start != -1 && end != -1,
257 _T("invalid ::CheckMenuRadioItem() parameter(s)") );
258
0472ece7 259 if ( !::CheckMenuRadioItem(hmenu,
be15b995
VZ
260 start, // the first radio group item
261 end, // the last one
262 pos, // the one to check
0f243af3 263 MF_BYPOSITION) )
0472ece7
VZ
264 {
265 wxLogLastError(_T("CheckMenuRadioItem"));
266 }
267#endif // __WIN32__
268
269 // also uncheck all the other items in this radio group
222ed1d6 270 wxMenuItemList::compatibility_iterator node = items.Item(start);
be15b995 271 for ( int n = start; n <= end && node; n++ )
0472ece7
VZ
272 {
273 if ( n != pos )
274 {
275 node->GetData()->m_isChecked = FALSE;
276 }
277
278 // we also have to do it in the menu for Win16 (under Win32
279 // CheckMenuRadioItem() does it for us)
280#ifndef __WIN32__
281 ::CheckMenuItem(hmenu, n, n == pos ? MF_CHECKED : MF_UNCHECKED);
282#endif // Win16
283
284 node = node->GetNext();
285 }
286 }
287 else // check item
288 {
289 if ( ::CheckMenuItem(hmenu,
290 GetRealId(),
9f385aa0 291 MF_BYCOMMAND | flags) == (DWORD)-1 )
0472ece7
VZ
292 {
293 wxLogLastError(wxT("CheckMenuItem"));
294 }
c2dcfdef 295 }
717a57c2
VZ
296
297 wxMenuItemBase::Check(check);
c2dcfdef
VZ
298}
299
974e8d94 300void wxMenuItem::SetText(const wxString& text)
c2dcfdef
VZ
301{
302 // don't do anything if label didn't change
974e8d94 303 if ( m_text == text )
c2dcfdef
VZ
304 return;
305
974e8d94
VZ
306 wxMenuItemBase::SetText(text);
307 OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(text) );
2a2a71e3
JS
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')));
311#endif
c2dcfdef 312
974e8d94 313 HMENU hMenu = GetHMenuOf(m_parentMenu);
717a57c2
VZ
314 wxCHECK_RET( hMenu, wxT("menuitem without menu") );
315
316#if wxUSE_ACCEL
317 m_parentMenu->UpdateAccel(this);
318#endif // wxUSE_ACCEL
2bda0e17 319
c2dcfdef
VZ
320 UINT id = GetRealId();
321 UINT flagsOld = ::GetMenuState(hMenu, id, MF_BYCOMMAND);
322 if ( flagsOld == 0xFFFFFFFF )
323 {
f6bcfd97 324 wxLogLastError(wxT("GetMenuState"));
c2dcfdef
VZ
325 }
326 else
327 {
328 if ( IsSubMenu() )
329 {
330 // high byte contains the number of items in a submenu for submenus
331 flagsOld &= 0xFF;
332 flagsOld |= MF_POPUP;
333 }
334
837e5743 335 LPCTSTR data;
974e8d94 336
c2dcfdef
VZ
337#if wxUSE_OWNER_DRAWN
338 if ( IsOwnerDrawn() )
339 {
340 flagsOld |= MF_OWNERDRAW;
837e5743 341 data = (LPCTSTR)this;
c2dcfdef
VZ
342 }
343 else
344#endif //owner drawn
345 {
346 flagsOld |= MF_STRING;
f5166ed4 347 data = (wxChar*) text.c_str();
c2dcfdef
VZ
348 }
349
4676948b
JS
350#ifdef __WXWINCE__
351 // FIXME: complete this, applying the old
09785dd3
JS
352 // flags.
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.
4676948b
JS
356 MENUITEMINFO info;
357 wxZeroMemory(info);
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) )
364 {
365 wxLogLastError(wxT("SetMenuItemInfo"));
366 }
367#else
c2dcfdef
VZ
368 if ( ::ModifyMenu(hMenu, id,
369 MF_BYCOMMAND | flagsOld,
a17e237f 370 id, data) == (int)0xFFFFFFFF )
c2dcfdef 371 {
223d09f6 372 wxLogLastError(wxT("ModifyMenu"));
c2dcfdef 373 }
4676948b 374#endif
c2dcfdef
VZ
375 }
376}
2bda0e17 377
974e8d94
VZ
378void wxMenuItem::SetCheckable(bool checkable)
379{
380 wxMenuItemBase::SetCheckable(checkable);
381 OWNER_DRAWN_ONLY( wxOwnerDrawn::SetCheckable(checkable) );
382}
383
384// ----------------------------------------------------------------------------
385// wxMenuItemBase
386// ----------------------------------------------------------------------------
387
388wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
389 int id,
390 const wxString& name,
391 const wxString& help,
d65c269b 392 wxItemKind kind,
974e8d94
VZ
393 wxMenu *subMenu)
394{
d65c269b 395 return new wxMenuItem(parentMenu, id, name, help, kind, subMenu);
974e8d94 396}
1e6feb95
VZ
397
398#endif // wxUSE_MENUS