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