]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/menuitem.cpp
test wxExecute() in the sample
[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// 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
267
268// change item state
269// -----------------
270
271void wxMenuItem::Enable(
272 bool bEnable
273)
274{
275 bool bOk;
276
277 if (m_isEnabled == bEnable)
278 return;
279 if (bEnable)
280 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
281 ,MM_SETITEMATTR
282 ,MPFROM2SHORT(GetRealId(), TRUE)
283 ,MPFROM2SHORT(MIA_DISABLED, FALSE)
284 );
285 else
286 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
287 ,MM_SETITEMATTR
288 ,MPFROM2SHORT(GetRealId(), TRUE)
289 ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
290 );
291 if (!bOk)
292 {
293 wxLogLastError("EnableMenuItem");
294 }
295 wxMenuItemBase::Enable(bEnable);
296} // end of wxMenuItem::Enable
297
298void wxMenuItem::Check(
299 bool bCheck
300)
301{
302 bool bOk;
303
304 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
305 if (m_isChecked == bCheck)
306 return;
307
308 HMENU hMenu = GetHmenuOf(m_parentMenu);
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)
381 bOk = (bool)::WinSendMsg( hMenu
382 ,MM_SETITEMATTR
383 ,MPFROM2SHORT(GetRealId(), TRUE)
384 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
385 );
386 else
387 bOk = (bool)::WinSendMsg( hMenu
388 ,MM_SETITEMATTR
389 ,MPFROM2SHORT(GetRealId(), TRUE)
390 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
391 );
392 }
393 if (!bOk)
394 {
395 wxLogLastError("CheckMenuItem");
396 }
397 wxMenuItemBase::Check(bCheck);
398} // end of wxMenuItem::Check
399
400void wxMenuItem::SetText(
401 const wxString& rText
402)
403{
404 //
405 // Don't do anything if label didn't change
406 //
407
408 wxString sText = TextToLabel(rText);
409 if (m_text == sText)
410 return;
411
412 wxMenuItemBase::SetText(sText);
413 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(sText));
414
415 HWND hMenu = GetHmenuOf(m_parentMenu);
416
417 wxCHECK_RET(hMenu, wxT("menuitem without menu"));
418
419#if wxUSE_ACCEL
420 m_parentMenu->UpdateAccel(this);
421#endif // wxUSE_ACCEL
422
423 USHORT uId = GetRealId();
424 MENUITEM vItem;
425 USHORT uFlagsOld;
426
427 if (!::WinSendMsg( hMenu
428 ,MM_QUERYITEM
429 ,MPFROM2SHORT(uId, TRUE)
430 ,(MPARAM)&vItem
431 ))
432 {
433 wxLogLastError("GetMenuState");
434 }
435 else
436 {
437 uFlagsOld = vItem.afStyle;
438 if (IsSubMenu())
439 {
440 uFlagsOld |= MIS_SUBMENU;
441 }
442
443 BYTE* pData;
444
445#if wxUSE_OWNER_DRAWN
446 if (IsOwnerDrawn())
447 {
448 uFlagsOld |= MIS_OWNERDRAW;
449 pData = (BYTE*)this;
450 }
451 else
452#endif //owner drawn
453 {
454 uFlagsOld |= MIS_TEXT;
455 pData = (BYTE*)sText.c_str();
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"));
468 }
469
470 //
471 // Set the text
472 //
473 if (::WinSendMsg( hMenu
474 ,MM_SETITEMTEXT
475 ,MPFROMSHORT(uId)
476 ,(MPARAM)pData
477 ))
478 {
479 wxLogLastError(wxT("ModifyMenu"));
480 }
481 }
482} // end of wxMenuItem::SetText
483
484void wxMenuItem::SetCheckable(
485 bool bCheckable
486)
487{
488 wxMenuItemBase::SetCheckable(bCheckable);
489 OWNER_DRAWN_ONLY(wxOwnerDrawn::SetCheckable(bCheckable));
490} // end of wxMenuItem::SetCheckable
491
492// ----------------------------------------------------------------------------
493// wxMenuItemBase
494// ----------------------------------------------------------------------------
495
496wxMenuItem* wxMenuItemBase::New(
497 wxMenu* pParentMenu
498, int nId
499, const wxString& rName
500, const wxString& rHelp
501, wxItemKind kind
502, wxMenu* pSubMenu
503)
504{
505 return new wxMenuItem( pParentMenu
506 ,nId
507 ,rName
508 ,rHelp
509 ,kind
510 ,pSubMenu
511 );
512} // end of wxMenuItemBase::New
513