]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/menuitem.cpp
Moved the cleanup code to an EVT_WINDOW_DESTROY handler.
[wxWidgets.git] / src / os2 / menuitem.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: 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#ifdef __GNUG__
17 #pragma implementation "menuitem.h"
18#endif
19
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
34#include "wx/menuitem.h"
35#include "wx/log.h"
36
37#if wxUSE_ACCEL
38 #include "wx/accel.h"
39#endif // wxUSE_ACCEL
40
41#include "wx/os2/private.h"
42
43// ---------------------------------------------------------------------------
44// macro
45// ---------------------------------------------------------------------------
46
47// hide the ugly cast
48#define GetHMenuOf(menu) ((HMENU)menu->GetHMenu())
49
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
57// ----------------------------------------------------------------------------
58// static function for translating menu labels
59// ----------------------------------------------------------------------------
60
61static wxString TextToLabel(const wxString& rTitle)
62{
63 wxString Title;
64 const wxChar *pc;
65 for (pc = rTitle.c_str(); *pc != wxT('\0'); pc++ )
66 {
67 if (*pc == wxT('&') )
68 {
69 if (*(pc+1) == wxT('&'))
70 {
71 pc++;
72 Title << wxT('&');
73 }
74 else
75 Title << wxT('~');
76 }
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
91// ============================================================================
92// implementation
93// ============================================================================
94
95// ----------------------------------------------------------------------------
96// dynamic classes implementation
97// ----------------------------------------------------------------------------
98
99IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
100
101// ----------------------------------------------------------------------------
102// wxMenuItem
103// ----------------------------------------------------------------------------
104
105// ctor & dtor
106// -----------
107
108wxMenuItem::wxMenuItem(
109 wxMenu* pParentMenu
110, int nId
111, const wxString& rsText
112, const wxString& rsHelp
113, wxItemKind eKind
114, wxMenu* pSubMenu
115)
116: wxMenuItemBase( pParentMenu
117 ,nId
118 ,TextToLabel(rsText)
119 ,rsHelp
120 ,eKind
121 ,pSubMenu
122 )
123#if wxUSE_OWNER_DRAWN
124, wxOwnerDrawn( TextToLabel(rsText)
125 ,eKind == wxITEM_CHECK
126 )
127#endif // owner drawn
128{
129 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
130
131 Init();
132} // end of wxMenuItem::wxMenuItem
133
134wxMenuItem::wxMenuItem(
135 wxMenu* pParentMenu
136, int nId
137, const wxString& rsText
138, const wxString& rsHelp
139, bool bIsCheckable
140, wxMenu* pSubMenu
141)
142: wxMenuItemBase( pParentMenu
143 ,nId
144 ,TextToLabel(rsText)
145 ,rsHelp
146 ,bIsCheckable ? wxITEM_CHECK : wxITEM_NORMAL
147 ,pSubMenu
148 )
149#if wxUSE_OWNER_DRAWN
150, wxOwnerDrawn( TextToLabel(rsText)
151 ,bIsCheckable
152 )
153#endif // owner drawn
154{
155 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
156 memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
157 m_vMenuData.id = (USHORT)nId;
158
159 Init();
160} // end of wxMenuItem::wxMenuItem
161
162void wxMenuItem::Init()
163{
164 m_vRadioGroup.m_nStart = -1;
165 m_bIsRadioGroupStart = FALSE;
166
167#if wxUSE_OWNER_DRAWN
168 //
169 // Set default menu colors
170 //
171 #define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
172
173 SetTextColour(SYS_COLOR(MENUTEXT));
174 SetBackgroundColour(SYS_COLOR(MENU));
175
176 #undef SYS_COLOR
177
178 //
179 // We don't want normal items be owner-drawn
180 //
181 ResetOwnerDrawn();
182
183 //
184 // Tell the owner drawing code to to show the accel string as well
185 //
186 SetAccelString(m_text.AfterFirst(_T('\t')));
187#endif // wxUSE_OWNER_DRAWN
188} // end of wxMenuItem::Init
189
190wxMenuItem::~wxMenuItem()
191{
192} // end of wxMenuItem::~wxMenuItem
193
194//
195// Misc
196// ----
197
198//
199// Return the id for calling Win32 API functions
200//
201int wxMenuItem::GetRealId() const
202{
203 return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId();
204} // end of wxMenuItem::GetRealId
205
206//
207// Get item state
208// --------------
209bool wxMenuItem::IsChecked() const
210{
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)
223{
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;
237}
238
239//
240// Radio group stuff
241// -----------------
242//
243void wxMenuItem::SetAsRadioGroupStart()
244{
245 m_bIsRadioGroupStart = TRUE;
246} // end of wxMenuItem::SetAsRadioGroupStart
247
248void wxMenuItem::SetRadioGroupStart(
249 int nStart
250)
251{
252 wxASSERT_MSG( !m_bIsRadioGroupStart
253 ,_T("should only be called for the next radio items")
254 );
255
256 m_vRadioGroup.m_nStart = nStart;
257} // wxMenuItem::SetRadioGroupStart
258
259void wxMenuItem::SetRadioGroupEnd(
260 int nEnd
261)
262{
263 wxASSERT_MSG( m_bIsRadioGroupStart
264 ,_T("should only be called for the first radio item")
265 );
266 m_vRadioGroup.m_nEnd = nEnd;
267} // end of wxMenuItem::SetRadioGroupEnd
268
269// change item state
270// -----------------
271
272void wxMenuItem::Enable(
273 bool bEnable
274)
275{
276 bool bOk;
277
278 if (m_isEnabled == bEnable)
279 return;
280 if (bEnable)
281 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
282 ,MM_SETITEMATTR
283 ,MPFROM2SHORT(GetRealId(), TRUE)
284 ,MPFROM2SHORT(MIA_DISABLED, FALSE)
285 );
286 else
287 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
288 ,MM_SETITEMATTR
289 ,MPFROM2SHORT(GetRealId(), TRUE)
290 ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
291 );
292 if (!bOk)
293 {
294 wxLogLastError("EnableMenuItem");
295 }
296 wxMenuItemBase::Enable(bEnable);
297} // end of wxMenuItem::Enable
298
299void wxMenuItem::Check(
300 bool bCheck
301)
302{
303 bool bOk;
304
305 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
306 if (m_isChecked == bCheck)
307 return;
308
309 HMENU hMenu = GetHmenuOf(m_parentMenu);
310
311 if (GetKind() == wxITEM_RADIO)
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);
324
325 wxCHECK_RET( nPos != wxNOT_FOUND
326 ,_T("menuitem not found in the menu items list?")
327 );
328
329 //
330 // Get the radio group range
331 //
332 int nStart;
333 int nEnd;
334
335 if (m_bIsRadioGroupStart)
336 {
337 //
338 // We already have all information we need
339 //
340 nStart = nPos;
341 nEnd = m_vRadioGroup.m_nEnd;
342 }
343 else // next radio group item
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 {
359 if (n == nPos)
360 {
361 ::WinSendMsg( hMenu
362 ,MM_SETITEMATTR
363 ,MPFROM2SHORT(n, TRUE)
364 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
365 );
366 }
367 if (n != nPos)
368 {
369 pNode->GetData()->m_isChecked = FALSE;
370 ::WinSendMsg( hMenu
371 ,MM_SETITEMATTR
372 ,MPFROM2SHORT(n, TRUE)
373 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
374 );
375 }
376 pNode = pNode->GetNext();
377 }
378 }
379 else // check item
380 {
381 if (bCheck)
382 bOk = (bool)::WinSendMsg( hMenu
383 ,MM_SETITEMATTR
384 ,MPFROM2SHORT(GetRealId(), TRUE)
385 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
386 );
387 else
388 bOk = (bool)::WinSendMsg( hMenu
389 ,MM_SETITEMATTR
390 ,MPFROM2SHORT(GetRealId(), TRUE)
391 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
392 );
393 }
394 if (!bOk)
395 {
396 wxLogLastError("CheckMenuItem");
397 }
398 wxMenuItemBase::Check(bCheck);
399} // end of wxMenuItem::Check
400
401void wxMenuItem::SetText(
402 const wxString& rText
403)
404{
405 //
406 // Don't do anything if label didn't change
407 //
408
409 wxString sText = TextToLabel(rText);
410 if (m_text == sText)
411 return;
412
413 wxMenuItemBase::SetText(sText);
414 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(sText));
415
416 HWND hMenu = GetHmenuOf(m_parentMenu);
417
418 wxCHECK_RET(hMenu, wxT("menuitem without menu"));
419
420#if wxUSE_ACCEL
421 m_parentMenu->UpdateAccel(this);
422#endif // wxUSE_ACCEL
423
424 USHORT uId = GetRealId();
425 MENUITEM vItem;
426 USHORT uFlagsOld;
427
428 if (!::WinSendMsg( hMenu
429 ,MM_QUERYITEM
430 ,MPFROM2SHORT(uId, TRUE)
431 ,(MPARAM)&vItem
432 ))
433 {
434 wxLogLastError("GetMenuState");
435 }
436 else
437 {
438 uFlagsOld = vItem.afStyle;
439 if (IsSubMenu())
440 {
441 uFlagsOld |= MIS_SUBMENU;
442 }
443
444 BYTE* pData;
445
446#if wxUSE_OWNER_DRAWN
447 if (IsOwnerDrawn())
448 {
449 uFlagsOld |= MIS_OWNERDRAW;
450 pData = (BYTE*)this;
451 }
452 else
453#endif //owner drawn
454 {
455 uFlagsOld |= MIS_TEXT;
456 pData = (BYTE*)sText.c_str();
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"));
469 }
470
471 //
472 // Set the text
473 //
474 if (::WinSendMsg( hMenu
475 ,MM_SETITEMTEXT
476 ,MPFROMSHORT(uId)
477 ,(MPARAM)pData
478 ))
479 {
480 wxLogLastError(wxT("ModifyMenu"));
481 }
482 }
483} // end of wxMenuItem::SetText
484
485void wxMenuItem::SetCheckable(
486 bool bCheckable
487)
488{
489 wxMenuItemBase::SetCheckable(bCheckable);
490 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetCheckable(bCheckable));
491} // end of wxMenuItem::SetCheckable
492
493// ----------------------------------------------------------------------------
494// wxMenuItemBase
495// ----------------------------------------------------------------------------
496
497wxMenuItem* wxMenuItemBase::New(
498 wxMenu* pParentMenu
499, int nId
500, const wxString& rName
501, const wxString& rHelp
502, wxItemKind kind
503, wxMenu* pSubMenu
504)
505{
506 return new wxMenuItem( pParentMenu
507 ,nId
508 ,rName
509 ,rHelp
510 ,kind
511 ,pSubMenu
512 );
513} // end of wxMenuItemBase::New
514