]> git.saurik.com Git - wxWidgets.git/blob - src/os2/menuitem.cpp
Fix nonsensical checked menu item label and behaviour
[wxWidgets.git] / src / os2 / menuitem.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: menuitem.cpp
3 // Purpose: wxMenuItem implementation
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/10/98
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // headers & declarations
14 // ============================================================================
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/font.h"
21 #include "wx/bitmap.h"
22 #include "wx/settings.h"
23 #include "wx/font.h"
24 #include "wx/window.h"
25 #include "wx/accel.h"
26 #include "wx/menu.h"
27 #include "wx/string.h"
28 #endif
29
30 #include "wx/menuitem.h"
31 #include "wx/log.h"
32
33 #if wxUSE_ACCEL
34 #include "wx/accel.h"
35 #endif // wxUSE_ACCEL
36
37 #include "wx/os2/private.h"
38
39 // ---------------------------------------------------------------------------
40 // macro
41 // ---------------------------------------------------------------------------
42
43 // hide the ugly cast
44 #define GetHMenuOf(menu) ((HMENU)menu->GetHMenu())
45
46 // conditional compilation
47 #if wxUSE_OWNER_DRAWN
48 #define OWNER_DRAWN_ONLY( code ) if ( IsOwnerDrawn() ) code
49 #else // !wxUSE_OWNER_DRAWN
50 #define OWNER_DRAWN_ONLY( code )
51 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
52
53 // ============================================================================
54 // implementation
55 // ============================================================================
56
57 // ----------------------------------------------------------------------------
58 // dynamic classes implementation
59 // ----------------------------------------------------------------------------
60
61 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
62
63 // ----------------------------------------------------------------------------
64 // wxMenuItem
65 // ----------------------------------------------------------------------------
66
67 // ctor & dtor
68 // -----------
69
70 wxMenuItem::wxMenuItem(
71 wxMenu* pParentMenu
72 , int nId
73 , const wxString& rsText
74 , const wxString& rsHelp
75 , wxItemKind eKind
76 , wxMenu* pSubMenu
77 )
78 : wxMenuItemBase( pParentMenu
79 ,nId
80 ,wxPMTextToLabel(rsText)
81 ,rsHelp
82 ,eKind
83 ,pSubMenu
84 )
85 #if wxUSE_OWNER_DRAWN
86 , wxOwnerDrawn( wxPMTextToLabel(rsText)
87 ,eKind == wxITEM_CHECK
88 )
89 #endif // owner drawn
90 {
91 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
92 memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
93 m_vMenuData.id = (USHORT)nId;
94
95 Init();
96 } // end of wxMenuItem::wxMenuItem
97
98 wxMenuItem::wxMenuItem(
99 wxMenu* pParentMenu
100 , int nId
101 , const wxString& rsText
102 , const wxString& rsHelp
103 , bool bIsCheckable
104 , wxMenu* pSubMenu
105 )
106 : wxMenuItemBase( pParentMenu
107 ,nId
108 ,wxPMTextToLabel(rsText)
109 ,rsHelp
110 ,bIsCheckable ? wxITEM_CHECK : wxITEM_NORMAL
111 ,pSubMenu
112 )
113 #if wxUSE_OWNER_DRAWN
114 , wxOwnerDrawn( wxPMTextToLabel(rsText)
115 ,bIsCheckable
116 )
117 #endif // owner drawn
118 {
119 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
120 memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
121 m_vMenuData.id = (USHORT)nId;
122
123 Init();
124 } // end of wxMenuItem::wxMenuItem
125
126 void wxMenuItem::Init()
127 {
128 m_vRadioGroup.m_nStart = -1;
129 m_bIsRadioGroupStart = FALSE;
130
131 #if wxUSE_OWNER_DRAWN
132 //
133 // Set default menu colors
134 //
135 #define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
136
137 SetTextColour(SYS_COLOR(MENUTEXT));
138 SetBackgroundColour(SYS_COLOR(MENU));
139
140 //
141 // We don't want normal items be owner-drawn
142 //
143 ResetOwnerDrawn();
144 #undef SYS_COLOR
145
146 //
147 // Tell the owner drawing code to to show the accel string as well
148 //
149 SetAccelString(m_text.AfterFirst(_T('\t')));
150 #endif // wxUSE_OWNER_DRAWN
151 } // end of wxMenuItem::Init
152
153 wxMenuItem::~wxMenuItem()
154 {
155 } // end of wxMenuItem::~wxMenuItem
156
157 //
158 // Misc
159 // ----
160
161 //
162 // Return the id for calling Win32 API functions
163 //
164 int wxMenuItem::GetRealId() const
165 {
166 return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId();
167 } // end of wxMenuItem::GetRealId
168
169 //
170 // Get item state
171 // --------------
172 bool wxMenuItem::IsChecked() const
173 {
174 USHORT uFlag = SHORT1FROMMR(::WinSendMsg( GetHMenuOf(m_parentMenu)
175 ,MM_QUERYITEMATTR
176 ,MPFROM2SHORT(GetId(), TRUE)
177 ,MPFROMSHORT(MIA_CHECKED)
178 ));
179
180 return (uFlag & MIA_CHECKED) == MIA_CHECKED ;
181 } // end of wxMenuItem::IsChecked
182
183 wxString wxMenuItemBase::GetLabelFromText(
184 const wxString& rsText
185 )
186 {
187 wxString sLabel;
188
189 for (const wxChar* zPc = rsText.c_str(); *zPc; zPc++)
190 {
191 if (*zPc == wxT('~') || *zPc == wxT('&'))
192 {
193 //
194 // '~' is the escape character for OS/2PM and '&' is the one for
195 // wxWidgets - skip both of them
196 //
197 continue;
198 }
199 sLabel += *zPc;
200 }
201 return sLabel;
202 } // end of wxMenuItemBase::GetLabelFromText
203
204 //
205 // Radio group stuff
206 // -----------------
207 //
208 void wxMenuItem::SetAsRadioGroupStart()
209 {
210 m_bIsRadioGroupStart = true;
211 } // end of wxMenuItem::SetAsRadioGroupStart
212
213 void wxMenuItem::SetRadioGroupStart(
214 int nStart
215 )
216 {
217 wxASSERT_MSG( !m_bIsRadioGroupStart
218 ,_T("should only be called for the next radio items")
219 );
220
221 m_vRadioGroup.m_nStart = nStart;
222 } // wxMenuItem::SetRadioGroupStart
223
224 void wxMenuItem::SetRadioGroupEnd(
225 int nEnd
226 )
227 {
228 wxASSERT_MSG( m_bIsRadioGroupStart
229 ,_T("should only be called for the first radio item")
230 );
231 m_vRadioGroup.m_nEnd = nEnd;
232 } // end of wxMenuItem::SetRadioGroupEnd
233
234 // change item state
235 // -----------------
236
237 void wxMenuItem::Enable(
238 bool bEnable
239 )
240 {
241 bool bOk;
242
243 if (m_isEnabled == bEnable)
244 return;
245 if (bEnable)
246 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
247 ,MM_SETITEMATTR
248 ,MPFROM2SHORT(GetRealId(), TRUE)
249 ,MPFROM2SHORT(MIA_DISABLED, FALSE)
250 );
251 else
252 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
253 ,MM_SETITEMATTR
254 ,MPFROM2SHORT(GetRealId(), TRUE)
255 ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
256 );
257 if (!bOk)
258 {
259 wxLogLastError(wxT("EnableMenuItem"));
260 }
261 wxMenuItemBase::Enable(bEnable);
262 } // end of wxMenuItem::Enable
263
264 void wxMenuItem::Check(
265 bool bCheck
266 )
267 {
268 bool bOk;
269
270 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
271 if (m_isChecked == bCheck)
272 return;
273
274 HMENU hMenu = GetHmenuOf(m_parentMenu);
275
276 if (GetKind() == wxITEM_RADIO)
277 {
278 //
279 // It doesn't make sense to uncheck a radio item - what would this do?
280 //
281 if (!bCheck)
282 return;
283
284 //
285 // Get the index of this item in the menu
286 //
287 const wxMenuItemList& rItems = m_parentMenu->GetMenuItems();
288 int nPos = rItems.IndexOf(this);
289
290 wxCHECK_RET( nPos != wxNOT_FOUND
291 ,_T("menuitem not found in the menu items list?")
292 );
293
294 //
295 // Get the radio group range
296 //
297 int nStart;
298 int nEnd;
299
300 if (m_bIsRadioGroupStart)
301 {
302 //
303 // We already have all information we need
304 //
305 nStart = nPos;
306 nEnd = m_vRadioGroup.m_nEnd;
307 }
308 else // next radio group item
309 {
310 //
311 // Get the radio group end from the start item
312 //
313 nStart = m_vRadioGroup.m_nStart;
314 nEnd = rItems.Item(nStart)->GetData()->m_vRadioGroup.m_nEnd;
315 }
316
317 //
318 // Also uncheck all the other items in this radio group
319 //
320 wxMenuItemList::compatibility_iterator node = rItems.Item(nStart);
321
322 for (int n = nStart; n <= nEnd && node; n++)
323 {
324 if (n == nPos)
325 {
326 ::WinSendMsg( hMenu
327 ,MM_SETITEMATTR
328 ,MPFROM2SHORT(n, TRUE)
329 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
330 );
331 }
332 if (n != nPos)
333 {
334 node->GetData()->m_isChecked = FALSE;
335 ::WinSendMsg( hMenu
336 ,MM_SETITEMATTR
337 ,MPFROM2SHORT(n, TRUE)
338 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
339 );
340 }
341 node = node->GetNext();
342 }
343 }
344 else // check item
345 {
346 if (bCheck)
347 bOk = (bool)::WinSendMsg( hMenu
348 ,MM_SETITEMATTR
349 ,MPFROM2SHORT(GetRealId(), TRUE)
350 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
351 );
352 else
353 bOk = (bool)::WinSendMsg( hMenu
354 ,MM_SETITEMATTR
355 ,MPFROM2SHORT(GetRealId(), TRUE)
356 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
357 );
358 }
359 if (!bOk)
360 {
361 wxLogLastError(wxT("CheckMenuItem"));
362 }
363 wxMenuItemBase::Check(bCheck);
364 } // end of wxMenuItem::Check
365
366 void wxMenuItem::SetText( const wxString& rText )
367 {
368 //
369 // Don't do anything if label didn't change
370 //
371
372 wxString sText = wxPMTextToLabel(rText);
373 if (m_text == sText)
374 return;
375
376 wxMenuItemBase::SetText(sText);
377 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(sText));
378 #if wxUSE_OWNER_DRAWN
379 SetAccelString(rText.AfterFirst(_T('\t')));
380 #endif // wxUSE_OWNER_DRAWN
381
382 HWND hMenu = GetHmenuOf(m_parentMenu);
383
384 wxCHECK_RET(hMenu, wxT("menuitem without menu"));
385
386 #if wxUSE_ACCEL
387 m_parentMenu->UpdateAccel(this);
388 #endif // wxUSE_ACCEL
389
390 USHORT uId = (USHORT)GetRealId();
391 MENUITEM vItem;
392 USHORT uFlagsOld;
393
394 if (!::WinSendMsg( hMenu
395 ,MM_QUERYITEM
396 ,MPFROM2SHORT(uId, TRUE)
397 ,(MPARAM)&vItem
398 ))
399 {
400 wxLogLastError(wxT("GetMenuState"));
401 }
402 else
403 {
404 uFlagsOld = vItem.afStyle;
405 if (IsSubMenu())
406 {
407 uFlagsOld |= MIS_SUBMENU;
408 }
409
410 BYTE* pData;
411
412 #if wxUSE_OWNER_DRAWN
413 if (IsOwnerDrawn())
414 {
415 uFlagsOld |= MIS_OWNERDRAW;
416 pData = (BYTE*)this;
417 }
418 else
419 #endif //owner drawn
420 {
421 uFlagsOld |= MIS_TEXT;
422 pData = (BYTE*)sText.c_str();
423 }
424
425 //
426 // Set the style
427 //
428 if (!::WinSendMsg( hMenu
429 ,MM_SETITEM
430 ,MPFROM2SHORT(uId, TRUE)
431 ,(MPARAM)&vItem
432 ))
433 {
434 wxLogLastError(wxT("ModifyMenu"));
435 }
436
437 //
438 // Set the text
439 //
440 if (::WinSendMsg( hMenu
441 ,MM_SETITEMTEXT
442 ,MPFROMSHORT(uId)
443 ,(MPARAM)pData
444 ))
445 {
446 wxLogLastError(wxT("ModifyMenu"));
447 }
448 }
449 } // end of wxMenuItem::SetText
450
451 void wxMenuItem::SetCheckable(
452 bool bCheckable
453 )
454 {
455 wxMenuItemBase::SetCheckable(bCheckable);
456 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetCheckable(bCheckable));
457 } // end of wxMenuItem::SetCheckable
458
459 // ----------------------------------------------------------------------------
460 // wxMenuItemBase
461 // ----------------------------------------------------------------------------
462
463 wxMenuItem* wxMenuItemBase::New(
464 wxMenu* pParentMenu
465 , int nId
466 , const wxString& rName
467 , const wxString& rHelp
468 , wxItemKind kind
469 , wxMenu* pSubMenu
470 )
471 {
472 return new wxMenuItem( pParentMenu
473 ,nId
474 ,rName
475 ,rHelp
476 ,kind
477 ,pSubMenu
478 );
479 } // end of wxMenuItemBase::New