]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menuitem.cpp
fixed wxFontDialog API: accept const ref instead of (well, in addition to) a possibly...
[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>
9// Licence: wxWindows license
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
c2dcfdef 53// ---------------------------------------------------------------------------
974e8d94 54// macro
c2dcfdef
VZ
55// ---------------------------------------------------------------------------
56
974e8d94 57// hide the ugly cast
c2dcfdef
VZ
58#define GetHMenuOf(menu) ((HMENU)menu->GetHMenu())
59
974e8d94
VZ
60// conditional compilation
61#if wxUSE_OWNER_DRAWN
62 #define OWNER_DRAWN_ONLY( code ) if ( IsOwnerDrawn() ) code
63#else // !wxUSE_OWNER_DRAWN
64 #define OWNER_DRAWN_ONLY( code )
65#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
66
2bda0e17
KB
67// ============================================================================
68// implementation
69// ============================================================================
70
71// ----------------------------------------------------------------------------
72// dynamic classes implementation
73// ----------------------------------------------------------------------------
74
621b3e21 75IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
2bda0e17
KB
76
77// ----------------------------------------------------------------------------
78// wxMenuItem
79// ----------------------------------------------------------------------------
80
81// ctor & dtor
82// -----------
83
974e8d94
VZ
84wxMenuItem::wxMenuItem(wxMenu *pParentMenu,
85 int id,
86 const wxString& text,
87 const wxString& strHelp,
d65c269b 88 wxItemKind kind,
90002c49 89 wxMenu *pSubMenu)
d65c269b 90 : wxMenuItemBase(pParentMenu, id, text, strHelp, kind, pSubMenu)
47d67540 91#if wxUSE_OWNER_DRAWN
546bfbea 92 , wxOwnerDrawn(GetLabelFromText(text), kind == wxITEM_CHECK)
974e8d94 93#endif // owner drawn
2bda0e17 94{
2368dcda
VZ
95 Init();
96}
2bda0e17 97
2368dcda
VZ
98wxMenuItem::wxMenuItem(wxMenu *parentMenu,
99 int id,
100 const wxString& text,
101 const wxString& help,
102 bool isCheckable,
103 wxMenu *subMenu)
104 : wxMenuItemBase(parentMenu, id, text, help,
105 isCheckable ? wxITEM_CHECK : wxITEM_NORMAL, subMenu)
106#if wxUSE_OWNER_DRAWN
107 , wxOwnerDrawn(GetLabelFromText(text), isCheckable)
108#endif // owner drawn
109{
110 Init();
111}
112
113void wxMenuItem::Init()
114{
be15b995
VZ
115 m_radioGroup.start = -1;
116 m_isRadioGroupStart = FALSE;
0472ece7 117
47d67540 118#if wxUSE_OWNER_DRAWN
2bda0e17 119 // set default menu colors
a756f210 120 #define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
c2dcfdef 121
2bda0e17
KB
122 SetTextColour(SYS_COLOR(MENUTEXT));
123 SetBackgroundColour(SYS_COLOR(MENU));
124
6d5b2a57
VZ
125 #undef SYS_COLOR
126
2bda0e17
KB
127 // we don't want normal items be owner-drawn
128 ResetOwnerDrawn();
129
6d5b2a57 130 // tell the owner drawing code to to show the accel string as well
2368dcda 131 SetAccelString(m_text.AfterFirst(_T('\t')));
974e8d94 132#endif // wxUSE_OWNER_DRAWN
2bda0e17
KB
133}
134
c2dcfdef 135wxMenuItem::~wxMenuItem()
2bda0e17
KB
136{
137}
138
139// misc
140// ----
141
c2dcfdef
VZ
142// return the id for calling Win32 API functions
143int wxMenuItem::GetRealId() const
144{
974e8d94 145 return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId();
c2dcfdef
VZ
146}
147
3dfac970
VZ
148// get item state
149// --------------
150
a8cfd0cb 151bool wxMenuItem::IsChecked() const
3dfac970 152{
a8cfd0cb 153 int flag = ::GetMenuState(GetHMenuOf(m_parentMenu), GetId(), MF_BYCOMMAND);
3dfac970 154
4aee367e 155 return (flag & MF_CHECKED) != 0;
3dfac970
VZ
156}
157
3b59cdbf
VZ
158/* static */
159wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
717a57c2 160{
4a3563c5 161 return wxStripMenuCodes(text);
717a57c2
VZ
162}
163
be15b995
VZ
164// radio group stuff
165// -----------------
166
167void wxMenuItem::SetAsRadioGroupStart()
168{
169 m_isRadioGroupStart = TRUE;
170}
171
172void wxMenuItem::SetRadioGroupStart(int start)
173{
174 wxASSERT_MSG( !m_isRadioGroupStart,
175 _T("should only be called for the next radio items") );
176
177 m_radioGroup.start = start;
178}
179
180void wxMenuItem::SetRadioGroupEnd(int end)
181{
182 wxASSERT_MSG( m_isRadioGroupStart,
183 _T("should only be called for the first radio item") );
184
185 m_radioGroup.end = end;
186}
187
2bda0e17
KB
188// change item state
189// -----------------
190
717a57c2 191void wxMenuItem::Enable(bool enable)
2bda0e17 192{
717a57c2
VZ
193 if ( m_isEnabled == enable )
194 return;
195
196 long rc = EnableMenuItem(GetHMenuOf(m_parentMenu),
197 GetRealId(),
198 MF_BYCOMMAND |
199 (enable ? MF_ENABLED : MF_GRAYED));
c2dcfdef 200
717a57c2 201 if ( rc == -1 ) {
f6bcfd97 202 wxLogLastError(wxT("EnableMenuItem"));
c2dcfdef 203 }
717a57c2
VZ
204
205 wxMenuItemBase::Enable(enable);
2bda0e17
KB
206}
207
717a57c2 208void wxMenuItem::Check(bool check)
2bda0e17 209{
d65c269b 210 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
c2dcfdef 211
717a57c2
VZ
212 if ( m_isChecked == check )
213 return;
c2dcfdef 214
0472ece7
VZ
215 int flags = check ? MF_CHECKED : MF_UNCHECKED;
216 HMENU hmenu = GetHMenuOf(m_parentMenu);
217
546bfbea 218 if ( GetKind() == wxITEM_RADIO )
0472ece7
VZ
219 {
220 // it doesn't make sense to uncheck a radio item - what would this do?
221 if ( !check )
222 return;
223
be15b995 224 // get the index of this item in the menu
0472ece7
VZ
225 const wxMenuItemList& items = m_parentMenu->GetMenuItems();
226 int pos = items.IndexOf(this);
227 wxCHECK_RET( pos != wxNOT_FOUND,
228 _T("menuitem not found in the menu items list?") );
229
be15b995
VZ
230 // get the radio group range
231 int start,
232 end;
233
234 if ( m_isRadioGroupStart )
235 {
236 // we already have all information we need
237 start = pos;
238 end = m_radioGroup.end;
239 }
240 else // next radio group item
241 {
242 // get the radio group end from the start item
243 start = m_radioGroup.start;
244 end = items.Item(start)->GetData()->m_radioGroup.end;
245 }
246
0472ece7 247#ifdef __WIN32__
be15b995
VZ
248 // calling CheckMenuRadioItem() with such parameters hangs my system
249 // (NT4 SP6) and I suspect this could happen to the others as well - so
250 // don't do it!
251 wxCHECK_RET( start != -1 && end != -1,
252 _T("invalid ::CheckMenuRadioItem() parameter(s)") );
253
0472ece7 254 if ( !::CheckMenuRadioItem(hmenu,
be15b995
VZ
255 start, // the first radio group item
256 end, // the last one
257 pos, // the one to check
0f243af3 258 MF_BYPOSITION) )
0472ece7
VZ
259 {
260 wxLogLastError(_T("CheckMenuRadioItem"));
261 }
262#endif // __WIN32__
263
264 // also uncheck all the other items in this radio group
be15b995
VZ
265 wxMenuItemList::Node *node = items.Item(start);
266 for ( int n = start; n <= end && node; n++ )
0472ece7
VZ
267 {
268 if ( n != pos )
269 {
270 node->GetData()->m_isChecked = FALSE;
271 }
272
273 // we also have to do it in the menu for Win16 (under Win32
274 // CheckMenuRadioItem() does it for us)
275#ifndef __WIN32__
276 ::CheckMenuItem(hmenu, n, n == pos ? MF_CHECKED : MF_UNCHECKED);
277#endif // Win16
278
279 node = node->GetNext();
280 }
281 }
282 else // check item
283 {
284 if ( ::CheckMenuItem(hmenu,
285 GetRealId(),
9f385aa0 286 MF_BYCOMMAND | flags) == (DWORD)-1 )
0472ece7
VZ
287 {
288 wxLogLastError(wxT("CheckMenuItem"));
289 }
c2dcfdef 290 }
717a57c2
VZ
291
292 wxMenuItemBase::Check(check);
c2dcfdef
VZ
293}
294
974e8d94 295void wxMenuItem::SetText(const wxString& text)
c2dcfdef
VZ
296{
297 // don't do anything if label didn't change
974e8d94 298 if ( m_text == text )
c2dcfdef
VZ
299 return;
300
974e8d94
VZ
301 wxMenuItemBase::SetText(text);
302 OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(text) );
c2dcfdef 303
974e8d94 304 HMENU hMenu = GetHMenuOf(m_parentMenu);
717a57c2
VZ
305 wxCHECK_RET( hMenu, wxT("menuitem without menu") );
306
307#if wxUSE_ACCEL
308 m_parentMenu->UpdateAccel(this);
309#endif // wxUSE_ACCEL
2bda0e17 310
c2dcfdef
VZ
311 UINT id = GetRealId();
312 UINT flagsOld = ::GetMenuState(hMenu, id, MF_BYCOMMAND);
313 if ( flagsOld == 0xFFFFFFFF )
314 {
f6bcfd97 315 wxLogLastError(wxT("GetMenuState"));
c2dcfdef
VZ
316 }
317 else
318 {
319 if ( IsSubMenu() )
320 {
321 // high byte contains the number of items in a submenu for submenus
322 flagsOld &= 0xFF;
323 flagsOld |= MF_POPUP;
324 }
325
837e5743 326 LPCTSTR data;
974e8d94 327
c2dcfdef
VZ
328#if wxUSE_OWNER_DRAWN
329 if ( IsOwnerDrawn() )
330 {
331 flagsOld |= MF_OWNERDRAW;
837e5743 332 data = (LPCTSTR)this;
c2dcfdef
VZ
333 }
334 else
335#endif //owner drawn
336 {
337 flagsOld |= MF_STRING;
f5166ed4 338 data = (wxChar*) text.c_str();
c2dcfdef
VZ
339 }
340
341 if ( ::ModifyMenu(hMenu, id,
342 MF_BYCOMMAND | flagsOld,
a17e237f 343 id, data) == (int)0xFFFFFFFF )
c2dcfdef 344 {
223d09f6 345 wxLogLastError(wxT("ModifyMenu"));
c2dcfdef
VZ
346 }
347 }
348}
2bda0e17 349
974e8d94
VZ
350void wxMenuItem::SetCheckable(bool checkable)
351{
352 wxMenuItemBase::SetCheckable(checkable);
353 OWNER_DRAWN_ONLY( wxOwnerDrawn::SetCheckable(checkable) );
354}
355
356// ----------------------------------------------------------------------------
357// wxMenuItemBase
358// ----------------------------------------------------------------------------
359
360wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
361 int id,
362 const wxString& name,
363 const wxString& help,
d65c269b 364 wxItemKind kind,
974e8d94
VZ
365 wxMenu *subMenu)
366{
d65c269b 367 return new wxMenuItem(parentMenu, id, name, help, kind, subMenu);
974e8d94 368}
1e6feb95
VZ
369
370#endif // wxUSE_MENUS