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