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