]> git.saurik.com Git - wxWidgets.git/blame - src/os2/menuitem.cpp
make sure wxNativeFontInfo is defined
[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
0e320a79
DW
61// ----------------------------------------------------------------------------
62// wxMenuItem
63// ----------------------------------------------------------------------------
64
65// ctor & dtor
66// -----------
67
22e90769
DW
68wxMenuItem::wxMenuItem(
69 wxMenu* pParentMenu
70, int nId
ab4fece8
DW
71, const wxString& rsText
72, const wxString& rsHelp
73, wxItemKind eKind
22e90769
DW
74, wxMenu* pSubMenu
75)
ab4fece8
DW
76: wxMenuItemBase( pParentMenu
77 ,nId
3a7c1253 78 ,wxPMTextToLabel(rsText)
ab4fece8
DW
79 ,rsHelp
80 ,eKind
81 ,pSubMenu
82 )
0e320a79 83{
22e90769 84 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
8635b0db
DW
85 memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
86 m_vMenuData.id = (USHORT)nId;
75f11ad7 87
f95255e2
DW
88 Init();
89} // end of wxMenuItem::wxMenuItem
90
91wxMenuItem::wxMenuItem(
92 wxMenu* pParentMenu
93, int nId
ab4fece8
DW
94, const wxString& rsText
95, const wxString& rsHelp
f95255e2
DW
96, bool bIsCheckable
97, wxMenu* pSubMenu
98)
ab4fece8
DW
99: wxMenuItemBase( pParentMenu
100 ,nId
3a7c1253 101 ,wxPMTextToLabel(rsText)
ab4fece8
DW
102 ,rsHelp
103 ,bIsCheckable ? wxITEM_CHECK : wxITEM_NORMAL
104 ,pSubMenu
105 )
f95255e2
DW
106{
107 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
938aa9c4
DW
108 memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
109 m_vMenuData.id = (USHORT)nId;
f95255e2
DW
110
111 Init();
112} // end of wxMenuItem::wxMenuItem
113
114void wxMenuItem::Init()
115{
ab4fece8
DW
116 m_vRadioGroup.m_nStart = -1;
117 m_bIsRadioGroupStart = FALSE;
22e90769 118
f95255e2 119#if wxUSE_OWNER_DRAWN
ab4fece8
DW
120 //
121 // Set default menu colors
122 //
98fbab9e
VZ
123 SetTextColour(wxNullColour);
124 SetBackgroundColour(wxNullColour);
75f11ad7 125
ab4fece8
DW
126 //
127 // We don't want normal items be owner-drawn
128 //
98fbab9e 129 SetOwnerDrawn(false);
f95255e2 130#endif // wxUSE_OWNER_DRAWN
ab4fece8 131} // end of wxMenuItem::Init
0e320a79 132
75f11ad7 133wxMenuItem::~wxMenuItem()
0e320a79 134{
22e90769 135} // end of wxMenuItem::~wxMenuItem
0e320a79 136
22e90769
DW
137//
138// Misc
0e320a79
DW
139// ----
140
22e90769
DW
141//
142// Return the id for calling Win32 API functions
143//
75f11ad7
DW
144int wxMenuItem::GetRealId() const
145{
c5fb56c0 146 return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId();
22e90769 147} // end of wxMenuItem::GetRealId
c5fb56c0 148
22e90769
DW
149//
150// Get item state
c5fb56c0 151// --------------
c5fb56c0
DW
152bool wxMenuItem::IsChecked() const
153{
6670f564
WS
154 USHORT uFlag = SHORT1FROMMR(::WinSendMsg( GetHMenuOf(m_parentMenu)
155 ,MM_QUERYITEMATTR
156 ,MPFROM2SHORT(GetId(), TRUE)
157 ,MPFROMSHORT(MIA_CHECKED)
158 ));
22e90769 159
6670f564 160 return (uFlag & MIA_CHECKED) == MIA_CHECKED ;
22e90769
DW
161} // end of wxMenuItem::IsChecked
162
52af3158 163wxString wxMenuItemBase::GetLabelText(
c9667cda 164 const wxString& rsText
22e90769 165)
c5fb56c0 166{
c9667cda
DW
167 wxString sLabel;
168
0fba44b4 169 for (const wxChar* zPc = rsText.c_str(); *zPc; zPc++)
2b33b728 170 {
c9667cda 171 if (*zPc == wxT('~') || *zPc == wxT('&'))
2b33b728 172 {
c9667cda
DW
173 //
174 // '~' is the escape character for OS/2PM and '&' is the one for
77ffb593 175 // wxWidgets - skip both of them
c9667cda 176 //
2b33b728
SN
177 continue;
178 }
c9667cda 179 sLabel += *zPc;
2b33b728 180 }
c9667cda 181 return sLabel;
52af3158 182} // end of wxMenuItemBase::GetLabelText
75f11ad7 183
598d8cac
DW
184//
185// Radio group stuff
f95255e2 186// -----------------
598d8cac 187//
f95255e2
DW
188void wxMenuItem::SetAsRadioGroupStart()
189{
6670f564 190 m_bIsRadioGroupStart = true;
f95255e2
DW
191} // end of wxMenuItem::SetAsRadioGroupStart
192
193void wxMenuItem::SetRadioGroupStart(
194 int nStart
195)
196{
598d8cac 197 wxASSERT_MSG( !m_bIsRadioGroupStart
9a83f860 198 ,wxT("should only be called for the next radio items")
598d8cac 199 );
f95255e2
DW
200
201 m_vRadioGroup.m_nStart = nStart;
598d8cac 202} // wxMenuItem::SetRadioGroupStart
f95255e2
DW
203
204void wxMenuItem::SetRadioGroupEnd(
205 int nEnd
206)
207{
598d8cac 208 wxASSERT_MSG( m_bIsRadioGroupStart
9a83f860 209 ,wxT("should only be called for the first radio item")
598d8cac 210 );
f95255e2
DW
211 m_vRadioGroup.m_nEnd = nEnd;
212} // end of wxMenuItem::SetRadioGroupEnd
213
0e320a79
DW
214// change item state
215// -----------------
216
22e90769
DW
217void wxMenuItem::Enable(
218 bool bEnable
219)
0e320a79 220{
22e90769 221 bool bOk;
75f11ad7 222
22e90769
DW
223 if (m_isEnabled == bEnable)
224 return;
225 if (bEnable)
914589c2
DW
226 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
227 ,MM_SETITEMATTR
228 ,MPFROM2SHORT(GetRealId(), TRUE)
f6bcfd97 229 ,MPFROM2SHORT(MIA_DISABLED, FALSE)
914589c2 230 );
22e90769 231 else
914589c2
DW
232 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
233 ,MM_SETITEMATTR
234 ,MPFROM2SHORT(GetRealId(), TRUE)
f6bcfd97 235 ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
914589c2 236 );
22e90769
DW
237 if (!bOk)
238 {
2173b18f 239 wxLogLastError(wxT("EnableMenuItem"));
0e320a79 240 }
22e90769
DW
241 wxMenuItemBase::Enable(bEnable);
242} // end of wxMenuItem::Enable
0e320a79 243
22e90769
DW
244void wxMenuItem::Check(
245 bool bCheck
246)
0e320a79 247{
22e90769 248 bool bOk;
75f11ad7 249
d65c269b 250 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
22e90769 251 if (m_isChecked == bCheck)
c5fb56c0 252 return;
f95255e2 253
50b39f8f 254 HMENU hMenu = GetHmenuOf(m_parentMenu);
598d8cac
DW
255
256 if (GetKind() == wxITEM_RADIO)
ab4fece8
DW
257 {
258 //
259 // It doesn't make sense to uncheck a radio item - what would this do?
260 //
261 if (!bCheck)
262 return;
263
264 //
265 // Get the index of this item in the menu
266 //
267 const wxMenuItemList& rItems = m_parentMenu->GetMenuItems();
268 int nPos = rItems.IndexOf(this);
ab4fece8 269
598d8cac 270 wxCHECK_RET( nPos != wxNOT_FOUND
9a83f860 271 ,wxT("menuitem not found in the menu items list?")
598d8cac 272 );
ab4fece8
DW
273
274 //
275 // Get the radio group range
276 //
598d8cac
DW
277 int nStart;
278 int nEnd;
ab4fece8
DW
279
280 if (m_bIsRadioGroupStart)
281 {
598d8cac
DW
282 //
283 // We already have all information we need
284 //
ab4fece8 285 nStart = nPos;
598d8cac 286 nEnd = m_vRadioGroup.m_nEnd;
ab4fece8 287 }
598d8cac 288 else // next radio group item
ab4fece8
DW
289 {
290 //
291 // Get the radio group end from the start item
292 //
293 nStart = m_vRadioGroup.m_nStart;
294 nEnd = rItems.Item(nStart)->GetData()->m_vRadioGroup.m_nEnd;
295 }
296
297 //
298 // Also uncheck all the other items in this radio group
299 //
2461cfa0 300 wxMenuItemList::compatibility_iterator node = rItems.Item(nStart);
ab4fece8 301
2461cfa0 302 for (int n = nStart; n <= nEnd && node; n++)
ab4fece8 303 {
ab4fece8
DW
304 if (n == nPos)
305 {
598d8cac
DW
306 ::WinSendMsg( hMenu
307 ,MM_SETITEMATTR
308 ,MPFROM2SHORT(n, TRUE)
309 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
310 );
ab4fece8 311 }
598d8cac 312 if (n != nPos)
ab4fece8 313 {
2461cfa0 314 node->GetData()->m_isChecked = FALSE;
598d8cac
DW
315 ::WinSendMsg( hMenu
316 ,MM_SETITEMATTR
317 ,MPFROM2SHORT(n, TRUE)
318 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
319 );
ab4fece8 320 }
2461cfa0 321 node = node->GetNext();
ab4fece8
DW
322 }
323 }
324 else // check item
325 {
326 if (bCheck)
50b39f8f 327 bOk = (bool)::WinSendMsg( hMenu
ab4fece8
DW
328 ,MM_SETITEMATTR
329 ,MPFROM2SHORT(GetRealId(), TRUE)
330 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
331 );
332 else
50b39f8f 333 bOk = (bool)::WinSendMsg( hMenu
ab4fece8
DW
334 ,MM_SETITEMATTR
335 ,MPFROM2SHORT(GetRealId(), TRUE)
336 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
337 );
338 }
22e90769
DW
339 if (!bOk)
340 {
2173b18f 341 wxLogLastError(wxT("CheckMenuItem"));
75f11ad7 342 }
22e90769
DW
343 wxMenuItemBase::Check(bCheck);
344} // end of wxMenuItem::Check
75f11ad7 345
52af3158 346void wxMenuItem::SetItemLabel( const wxString& rText )
75f11ad7 347{
22e90769
DW
348 //
349 // Don't do anything if label didn't change
350 //
2b33b728 351
3a7c1253 352 wxString sText = wxPMTextToLabel(rText);
50b39f8f 353 if (m_text == sText)
75f11ad7
DW
354 return;
355
345319d6 356 // wxMenuItemBase will do stock ID checks
52af3158 357 wxMenuItemBase::SetItemLabel(sText);
345319d6 358
98fbab9e 359 HWND hMenu = GetHmenuOf(m_parentMenu);
22e90769
DW
360
361 wxCHECK_RET(hMenu, wxT("menuitem without menu"));
75f11ad7 362
c5fb56c0
DW
363#if wxUSE_ACCEL
364 m_parentMenu->UpdateAccel(this);
365#endif // wxUSE_ACCEL
75f11ad7 366
6670f564
WS
367 USHORT uId = (USHORT)GetRealId();
368 MENUITEM vItem;
369 USHORT uFlagsOld;
914589c2 370
22e90769
DW
371 if (!::WinSendMsg( hMenu
372 ,MM_QUERYITEM
373 ,MPFROM2SHORT(uId, TRUE)
374 ,(MPARAM)&vItem
375 ))
75f11ad7 376 {
2173b18f 377 wxLogLastError(wxT("GetMenuState"));
75f11ad7
DW
378 }
379 else
380 {
22e90769
DW
381 uFlagsOld = vItem.afStyle;
382 if (IsSubMenu())
75f11ad7 383 {
22e90769 384 uFlagsOld |= MIS_SUBMENU;
75f11ad7
DW
385 }
386
f450b5cf 387 char* pData;
c5fb56c0 388
75f11ad7 389#if wxUSE_OWNER_DRAWN
22e90769 390 if (IsOwnerDrawn())
75f11ad7 391 {
22e90769 392 uFlagsOld |= MIS_OWNERDRAW;
f450b5cf 393 pData = (char*)this;
75f11ad7
DW
394 }
395 else
396#endif //owner drawn
397 {
22e90769 398 uFlagsOld |= MIS_TEXT;
404aba09 399 pData = (char*) m_text.wx_str();
22e90769
DW
400 }
401
402 //
403 // Set the style
404 //
405 if (!::WinSendMsg( hMenu
406 ,MM_SETITEM
407 ,MPFROM2SHORT(uId, TRUE)
408 ,(MPARAM)&vItem
409 ))
410 {
411 wxLogLastError(wxT("ModifyMenu"));
75f11ad7
DW
412 }
413
22e90769
DW
414 //
415 // Set the text
416 //
417 if (::WinSendMsg( hMenu
418 ,MM_SETITEMTEXT
419 ,MPFROMSHORT(uId)
420 ,(MPARAM)pData
421 ))
75f11ad7
DW
422 {
423 wxLogLastError(wxT("ModifyMenu"));
424 }
425 }
22e90769 426} // end of wxMenuItem::SetText
0e320a79 427
98fbab9e
VZ
428#if wxUSE_OWNER_DRAWN
429
430wxString wxMenuItem::GetName() const
431{
432 return GetItemLabelText();
433}
434
435bool wxMenuItem::OnMeasureItem( size_t* pWidth, size_t* pHeight )
436{
437 wxMemoryDC vDC;
438
439 wxString sStr = GetName();
440
441 //
442 // If we have a valid accel string, then pad out
443 // the menu string so that the menu and accel string are not
444 // placed on top of each other.
445 wxString accel = GetItemLabel().AfterFirst(wxT('\t'));
446 if (!accel.empty() )
447 {
448 sStr.Pad(sStr.length()%8);
449 sStr += accel;
450 }
451 vDC.SetFont(GetFont());
452 vDC.GetTextExtent( sStr
453 ,(wxCoord *)pWidth
454 ,(wxCoord *)pHeight
455 );
456 if (!accel.empty())
457 {
458 //
459 // Measure the accelerator string, and add its width to
460 // the total item width, plus 16 (Accelerators are right justified,
461 // with the right edge of the text rectangle 16 pixels left of
462 // the right edge of the menu)
463 //
464 int nAccelWidth;
465 int nAccelHeight;
466
467 vDC.GetTextExtent( m_strAccel
468 ,&nAccelWidth
469 ,&nAccelHeight
470 );
471 *pWidth += nAccelWidth;
472 }
473
474 //
475 // Add space at the end of the menu for the submenu expansion arrow.
476 // This will also allow offsetting the accel string from the right edge
477 //
478 *pWidth = (size_t)(*pWidth + GetDefaultMarginWidth() * 1.5);
479
480 //
481 // JACS: items still look too tightly packed, so adding 5 pixels.
482 //
483 (*pHeight) += 5;
484
485 //
486 // Ray Gilbert's changes - Corrects the problem of a BMP
487 // being placed next to text in a menu item, and the BMP does
488 // not match the size expected by the system. This will
489 // resize the space so the BMP will fit. Without this, BMPs
490 // must be no larger or smaller than 16x16.
491 //
492 if (m_bmpChecked.Ok())
493 {
494 //
495 // Is BMP height larger then text height?
496 //
497 size_t nAdjustedHeight = m_bmpChecked.GetHeight() +
498 wxSystemSettings::GetMetric(wxSYS_EDGE_Y);
499 if (*pHeight < nAdjustedHeight)
500 *pHeight = nAdjustedHeight;
501
502 //
503 // Does BMP encroach on default check menu position?
504 //
505 size_t nAdjustedWidth = m_bmpChecked.GetWidth() +
506 (wxSystemSettings::GetMetric(wxSYS_EDGE_X) * 2);
507
508 //
509 // Do we need to widen margin to fit BMP?
510 //
511 if ((size_t)GetMarginWidth() < nAdjustedWidth)
512 SetMarginWidth(nAdjustedWidth);
513
514 //
515 // Add the size of the bitmap to our total size...
516 //
517 *pWidth += GetMarginWidth();
518 }
519
520 //
521 // Add the size of the bitmap to our total size - even if we don't have
522 // a bitmap we leave room for one...
523 //
524 *pWidth += GetMarginWidth();
525
526 //
527 // Make sure that this item is at least as
528 // tall as the user's system settings specify
529 //
530 const size_t heightStd = 6; // FIXME: get value from the system
531 if ( *pHeight < heightStd )
532 *pHeight = heightStd;
533 m_nHeight = *pHeight; // remember height for use in OnDrawItem
534 return true;
535} // end of wxOwnerDrawn::OnMeasureItem
536
537bool wxMenuItem::OnDrawItem( wxDC& rDC,
538 const wxRect& rRect,
539 wxODAction eAction,
540 wxODStatus eStatus )
c5fb56c0 541{
98fbab9e
VZ
542
543 //
544 // Select the font and draw the text
545 // ---------------------------------
546 //
547
548 CHARBUNDLE vCbnd;
549 wxPMDCImpl *impl = (wxPMDCImpl*) rDC.GetImpl();
550 HPS hPS= impl->GetHPS();
551 wxFont vFont;
552 wxColour vColBack;
553 wxColour vColText;
554 COLORREF vRef;
555 RECTL vRect = {rRect.x + 4, rRect.y + 1, rRect.x + (rRect.width - 2), rRect.y + rRect.height};
556
557 memset(&vCbnd, 0, sizeof(CHARBUNDLE));
558
559 GetFontToUse(vFont);
560 GetColourToUse(eStatus, vColText, vColBack);
561
562 rDC.SetFont(vFont);
563 rDC.SetTextBackground(vColBack);
564 rDC.SetTextForeground(vColText);
565 rDC.SetBackgroundMode(wxTRANSPARENT);
566
567 vCbnd.lColor = vColText.GetPixel();
568 vCbnd.lBackColor = vColBack.GetPixel();
569 ::GpiSetAttrs( hPS
570 ,PRIM_CHAR
571 ,CBB_BACK_COLOR | CBB_COLOR
572 ,0
573 ,&vCbnd
574 );
575 ::GpiSetBackMix( hPS
576 ,BM_LEAVEALONE
577 );
578
579 //
580 // Paint the background
581 //
582 ::WinFillRect(hPS, &vRect, vColBack.GetPixel());
583
584 //
585 // Determine where to draw and leave space for a check-mark.
586 //
587 int nX = rRect.x + GetMarginWidth();
588
589 //
590 // Unfortunately, unlike Win32, PM has no owner drawn specific text
591 // drawing methods like ::DrawState that can cleanly handle accel
592 // mnemonics and deal, automatically, with various states, so we have
593 // to handle them ourselves. Notice Win32 can't handle \t in ownerdrawn
594 // strings either. We cannot handle mnemonics either. We display
595 // them, though, in the hope we can figure them out some day.
596 //
597
598 //
599 // Display main text and accel text separately to align better
600 //
601 wxString sTgt = wxT("\t");
602 wxString sFullString = GetItemLabel(); // need to save the original text
603 wxString sAccel;
604 int nIndex;
605 size_t nWidth;
606 size_t nCharWidth;
607 size_t nHeight;
608 bool bFoundMnemonic = false;
609 bool bFoundAccel = false;
610
611 //
612 // Deal with the tab, extracting the Accel text
613 //
614 nIndex = sFullString.Find(sTgt);
615 if (nIndex != -1)
616 {
617 bFoundAccel = true;
618 sAccel = sFullString.Mid(nIndex + 1);
619 sFullString.Remove(nIndex);
620 }
621
622 //
623 // Deal with the mnemonic character
624 //
625 sTgt = wxT("~");
626 nIndex = sFullString.Find(sTgt);
627 if (nIndex != -1)
628 {
629 wxString sTmp = sFullString;
630
631 bFoundMnemonic = true;
632 sTmp.Remove(nIndex);
633 rDC.GetTextExtent( sTmp
634 ,(wxCoord *)&nWidth
635 ,(wxCoord *)&nHeight
636 );
637 sTmp = sFullString[(size_t)(nIndex + 1)];
638 rDC.GetTextExtent( sTmp
639 ,(wxCoord *)&nCharWidth
640 ,(wxCoord *)&nHeight
641 );
642 sFullString.Replace(sTgt.c_str(), wxEmptyString, true);
643 }
644
645 //
646 // Draw the main item text sans the accel text
647 //
648 POINTL vPntStart = {nX, rRect.y + 4};
649 ::GpiCharStringAt( impl->GetHPS()
650 ,&vPntStart
651 ,sFullString.length()
652 ,sFullString.char_str()
653 );
654 if (bFoundMnemonic)
655 {
656 //
657 // Underline the mnemonic -- still won't work, but at least it "looks" right
658 //
659 wxPen vPen;
660 POINTL vPntEnd = {nX + nWidth + nCharWidth - 3, rRect.y + 2}; //CharWidth is bit wide
661
662 vPntStart.x = nX + nWidth - 1;
663 vPntStart.y = rRect.y + 2; // Make it look pretty!
664 vPen = wxPen(vColText, 1, wxSOLID); // Assuming we are always black
665 rDC.SetPen(vPen);
666 ::GpiMove(hPS, &vPntStart);
667 ::GpiLine(hPS, &vPntEnd);
668 }
669
670 //
671 // Now draw the accel text
672 //
673 if (bFoundAccel)
674 {
675 size_t nWidth;
676 size_t nHeight;
677
678 rDC.GetTextExtent( sAccel
679 ,(wxCoord *)&nWidth
680 ,(wxCoord *)&nHeight
681 );
682 //
683 // Back off the starting position from the right edge
684 //
685 vPntStart.x = rRect.width - (nWidth + 7);
686 vPntStart.y = rRect.y + 4;
687 ::GpiCharStringAt( impl->GetHPS()
688 ,&vPntStart
689 ,sAccel.length()
690 ,sAccel.char_str()
691 );
692 }
693
694 //
695 // Draw the bitmap
696 // ---------------
697 //
698 if (IsCheckable() && !m_bmpChecked.Ok())
699 {
700 if (eStatus & wxODChecked)
701 {
702 RECTL vRect;
703 HBITMAP hBmpCheck = ::WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUCHECK);
704
705 vRect.xLeft = rRect.x;
706 vRect.xRight = rRect.x + GetMarginWidth();
707 vRect.yBottom = rRect.y;
708 vRect.yTop = rRect.y + m_nHeight - 3;
709
710 ::WinDrawBitmap( hPS // PS for this menuitem
711 ,hBmpCheck // system checkmark
712 ,NULL // draw the whole bitmap
713 ,(PPOINTL)&vRect // destination -- bottom left corner of the menuitem area
714 ,0L // ignored
715 ,0L // draw a bitmap
716 ,DBM_NORMAL // draw normal size
717 );
718 }
719 }
720 else
721 {
722 //
723 // For uncheckable item we use only the 'checked' bitmap
724 //
725 wxBitmap vBmp(GetBitmap(IsCheckable() ? ((eStatus & wxODChecked) != 0) : TRUE));
726
727 if (vBmp.Ok())
728 {
729
730 wxMemoryDC vDCMem(&rDC);
731 wxMemoryDC* pOldDC = (wxMemoryDC*)vBmp.GetSelectedInto();
732
733 if(pOldDC != NULL)
734 {
735 vBmp.SetSelectedInto(NULL);
736 }
737 vDCMem.SelectObject(vBmp);
738
739 //
740 // Center bitmap
741 //
742 int nBmpWidth = vBmp.GetWidth();
743 int nBmpHeight = vBmp.GetHeight();
744
745 //
746 // There should be enough space!
747 //
748 wxASSERT((nBmpWidth <= rRect.width) && (nBmpHeight <= rRect.height));
749
750 int nHeightDiff = m_nHeight - nBmpHeight;
751
752 rDC.Blit( rRect.x + (GetMarginWidth() - nBmpWidth) / 2
753 ,rRect.y + nHeightDiff / 2
754 ,nBmpWidth
755 ,nBmpHeight
756 ,&vDCMem
757 ,0
758 ,0
759 ,wxCOPY
760 ,true
761 );
762
763 if (eStatus & wxODSelected)
764 {
765 POINTL vPnt1 = {rRect.x + 1, rRect.y + 3}; // Leave a little background border
766 POINTL vPnt2 = {rRect.x + GetMarginWidth(), rRect.y + m_nHeight - 3};
767
768 LINEBUNDLE vLine;
769
770 vLine.lColor = vColBack.GetPixel();
771 ::GpiSetAttrs( hPS
772 ,PRIM_LINE
773 ,LBB_COLOR
774 ,0
775 ,&vLine
776 );
777 ::GpiMove(hPS, &vPnt1);
778 ::GpiBox( hPS
779 ,DRO_OUTLINE
780 ,&vPnt2
781 ,0L
782 ,0L
783 );
784 }
785 vBmp.SetSelectedInto(NULL);
786 }
787 }
788 return true;
789} // end of wxOwnerDrawn::OnDrawItem
790
791#endif // wxUSE_OWNER_DRAWN
c5fb56c0
DW
792
793// ----------------------------------------------------------------------------
794// wxMenuItemBase
795// ----------------------------------------------------------------------------
796
22e90769
DW
797wxMenuItem* wxMenuItemBase::New(
798 wxMenu* pParentMenu
799, int nId
800, const wxString& rName
801, const wxString& rHelp
d65c269b 802, wxItemKind kind
22e90769
DW
803, wxMenu* pSubMenu
804)
c5fb56c0 805{
22e90769
DW
806 return new wxMenuItem( pParentMenu
807 ,nId
808 ,rName
809 ,rHelp
d65c269b 810 ,kind
22e90769
DW
811 ,pSubMenu
812 );
813} // end of wxMenuItemBase::New