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