]> git.saurik.com Git - wxWidgets.git/blame - src/os2/menuitem.cpp
fixed huge memory leak in wxFileDialog (closes patch 544060)
[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
598d8cac
DW
239//
240// Radio group stuff
f95255e2 241// -----------------
598d8cac 242//
f95255e2
DW
243void wxMenuItem::SetAsRadioGroupStart()
244{
245 m_bIsRadioGroupStart = TRUE;
246} // end of wxMenuItem::SetAsRadioGroupStart
247
248void wxMenuItem::SetRadioGroupStart(
249 int nStart
250)
251{
598d8cac
DW
252 wxASSERT_MSG( !m_bIsRadioGroupStart
253 ,_T("should only be called for the next radio items")
254 );
f95255e2
DW
255
256 m_vRadioGroup.m_nStart = nStart;
598d8cac 257} // wxMenuItem::SetRadioGroupStart
f95255e2
DW
258
259void wxMenuItem::SetRadioGroupEnd(
260 int nEnd
261)
262{
598d8cac
DW
263 wxASSERT_MSG( m_bIsRadioGroupStart
264 ,_T("should only be called for the first radio item")
265 );
f95255e2
DW
266 m_vRadioGroup.m_nEnd = nEnd;
267} // end of wxMenuItem::SetRadioGroupEnd
268
0e320a79
DW
269// change item state
270// -----------------
271
22e90769
DW
272void wxMenuItem::Enable(
273 bool bEnable
274)
0e320a79 275{
22e90769 276 bool bOk;
75f11ad7 277
22e90769
DW
278 if (m_isEnabled == bEnable)
279 return;
280 if (bEnable)
914589c2
DW
281 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
282 ,MM_SETITEMATTR
283 ,MPFROM2SHORT(GetRealId(), TRUE)
f6bcfd97 284 ,MPFROM2SHORT(MIA_DISABLED, FALSE)
914589c2 285 );
22e90769 286 else
914589c2
DW
287 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
288 ,MM_SETITEMATTR
289 ,MPFROM2SHORT(GetRealId(), TRUE)
f6bcfd97 290 ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
914589c2 291 );
22e90769
DW
292 if (!bOk)
293 {
c5fb56c0 294 wxLogLastError("EnableMenuItem");
0e320a79 295 }
22e90769
DW
296 wxMenuItemBase::Enable(bEnable);
297} // end of wxMenuItem::Enable
0e320a79 298
22e90769
DW
299void wxMenuItem::Check(
300 bool bCheck
301)
0e320a79 302{
22e90769 303 bool bOk;
75f11ad7 304
d65c269b 305 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
22e90769 306 if (m_isChecked == bCheck)
c5fb56c0 307 return;
f95255e2 308
50b39f8f 309 HMENU hMenu = GetHmenuOf(m_parentMenu);
598d8cac
DW
310
311 if (GetKind() == wxITEM_RADIO)
ab4fece8
DW
312 {
313 //
314 // It doesn't make sense to uncheck a radio item - what would this do?
315 //
316 if (!bCheck)
317 return;
318
319 //
320 // Get the index of this item in the menu
321 //
322 const wxMenuItemList& rItems = m_parentMenu->GetMenuItems();
323 int nPos = rItems.IndexOf(this);
ab4fece8 324
598d8cac
DW
325 wxCHECK_RET( nPos != wxNOT_FOUND
326 ,_T("menuitem not found in the menu items list?")
327 );
ab4fece8
DW
328
329 //
330 // Get the radio group range
331 //
598d8cac
DW
332 int nStart;
333 int nEnd;
ab4fece8
DW
334
335 if (m_bIsRadioGroupStart)
336 {
598d8cac
DW
337 //
338 // We already have all information we need
339 //
ab4fece8 340 nStart = nPos;
598d8cac 341 nEnd = m_vRadioGroup.m_nEnd;
ab4fece8 342 }
598d8cac 343 else // next radio group item
ab4fece8
DW
344 {
345 //
346 // Get the radio group end from the start item
347 //
348 nStart = m_vRadioGroup.m_nStart;
349 nEnd = rItems.Item(nStart)->GetData()->m_vRadioGroup.m_nEnd;
350 }
351
352 //
353 // Also uncheck all the other items in this radio group
354 //
355 wxMenuItemList::Node* pNode = rItems.Item(nStart);
356
357 for (int n = nStart; n <= nEnd && pNode; n++)
358 {
ab4fece8
DW
359 if (n == nPos)
360 {
598d8cac
DW
361 ::WinSendMsg( hMenu
362 ,MM_SETITEMATTR
363 ,MPFROM2SHORT(n, TRUE)
364 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
365 );
ab4fece8 366 }
598d8cac 367 if (n != nPos)
ab4fece8 368 {
598d8cac
DW
369 pNode->GetData()->m_isChecked = FALSE;
370 ::WinSendMsg( hMenu
371 ,MM_SETITEMATTR
372 ,MPFROM2SHORT(n, TRUE)
373 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
374 );
ab4fece8
DW
375 }
376 pNode = pNode->GetNext();
377 }
378 }
379 else // check item
380 {
381 if (bCheck)
50b39f8f 382 bOk = (bool)::WinSendMsg( hMenu
ab4fece8
DW
383 ,MM_SETITEMATTR
384 ,MPFROM2SHORT(GetRealId(), TRUE)
385 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
386 );
387 else
50b39f8f 388 bOk = (bool)::WinSendMsg( hMenu
ab4fece8
DW
389 ,MM_SETITEMATTR
390 ,MPFROM2SHORT(GetRealId(), TRUE)
391 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
392 );
393 }
22e90769
DW
394 if (!bOk)
395 {
f6bcfd97 396 wxLogLastError("CheckMenuItem");
75f11ad7 397 }
22e90769
DW
398 wxMenuItemBase::Check(bCheck);
399} // end of wxMenuItem::Check
75f11ad7 400
22e90769
DW
401void wxMenuItem::SetText(
402 const wxString& rText
403)
75f11ad7 404{
22e90769
DW
405 //
406 // Don't do anything if label didn't change
407 //
2b33b728 408
50b39f8f
DW
409 wxString sText = TextToLabel(rText);
410 if (m_text == sText)
75f11ad7
DW
411 return;
412
50b39f8f
DW
413 wxMenuItemBase::SetText(sText);
414 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(sText));
22e90769 415
50b39f8f 416 HWND hMenu = GetHmenuOf(m_parentMenu);
22e90769
DW
417
418 wxCHECK_RET(hMenu, wxT("menuitem without menu"));
75f11ad7 419
c5fb56c0
DW
420#if wxUSE_ACCEL
421 m_parentMenu->UpdateAccel(this);
422#endif // wxUSE_ACCEL
75f11ad7 423
22e90769
DW
424 USHORT uId = GetRealId();
425 MENUITEM vItem;
426 USHORT uFlagsOld;
914589c2 427
22e90769
DW
428 if (!::WinSendMsg( hMenu
429 ,MM_QUERYITEM
430 ,MPFROM2SHORT(uId, TRUE)
431 ,(MPARAM)&vItem
432 ))
75f11ad7
DW
433 {
434 wxLogLastError("GetMenuState");
435 }
436 else
437 {
22e90769
DW
438 uFlagsOld = vItem.afStyle;
439 if (IsSubMenu())
75f11ad7 440 {
22e90769 441 uFlagsOld |= MIS_SUBMENU;
75f11ad7
DW
442 }
443
22e90769 444 BYTE* pData;
c5fb56c0 445
75f11ad7 446#if wxUSE_OWNER_DRAWN
22e90769 447 if (IsOwnerDrawn())
75f11ad7 448 {
22e90769
DW
449 uFlagsOld |= MIS_OWNERDRAW;
450 pData = (BYTE*)this;
75f11ad7
DW
451 }
452 else
453#endif //owner drawn
454 {
22e90769 455 uFlagsOld |= MIS_TEXT;
50b39f8f 456 pData = (BYTE*)sText.c_str();
22e90769
DW
457 }
458
459 //
460 // Set the style
461 //
462 if (!::WinSendMsg( hMenu
463 ,MM_SETITEM
464 ,MPFROM2SHORT(uId, TRUE)
465 ,(MPARAM)&vItem
466 ))
467 {
468 wxLogLastError(wxT("ModifyMenu"));
75f11ad7
DW
469 }
470
22e90769
DW
471 //
472 // Set the text
473 //
474 if (::WinSendMsg( hMenu
475 ,MM_SETITEMTEXT
476 ,MPFROMSHORT(uId)
477 ,(MPARAM)pData
478 ))
75f11ad7
DW
479 {
480 wxLogLastError(wxT("ModifyMenu"));
481 }
482 }
22e90769 483} // end of wxMenuItem::SetText
0e320a79 484
22e90769
DW
485void wxMenuItem::SetCheckable(
486 bool bCheckable
487)
c5fb56c0 488{
22e90769
DW
489 wxMenuItemBase::SetCheckable(bCheckable);
490 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetCheckable(bCheckable));
491} // end of wxMenuItem::SetCheckable
c5fb56c0
DW
492
493// ----------------------------------------------------------------------------
494// wxMenuItemBase
495// ----------------------------------------------------------------------------
496
22e90769
DW
497wxMenuItem* wxMenuItemBase::New(
498 wxMenu* pParentMenu
499, int nId
500, const wxString& rName
501, const wxString& rHelp
d65c269b 502, wxItemKind kind
22e90769
DW
503, wxMenu* pSubMenu
504)
c5fb56c0 505{
22e90769
DW
506 return new wxMenuItem( pParentMenu
507 ,nId
508 ,rName
509 ,rHelp
d65c269b 510 ,kind
22e90769
DW
511 ,pSubMenu
512 );
513} // end of wxMenuItemBase::New
514