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