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