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