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