]> git.saurik.com Git - wxWidgets.git/blame - src/os2/menuitem.cpp
Fix text input and completion in wxComboCtrl and wxOwnerDrawnComboBox.
[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
4a46a5df 61IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
0e320a79
DW
62
63// ----------------------------------------------------------------------------
64// wxMenuItem
65// ----------------------------------------------------------------------------
66
67// ctor & dtor
68// -----------
69
22e90769
DW
70wxMenuItem::wxMenuItem(
71 wxMenu* pParentMenu
72, int nId
ab4fece8
DW
73, const wxString& rsText
74, const wxString& rsHelp
75, wxItemKind eKind
22e90769
DW
76, wxMenu* pSubMenu
77)
ab4fece8
DW
78: wxMenuItemBase( pParentMenu
79 ,nId
3a7c1253 80 ,wxPMTextToLabel(rsText)
ab4fece8
DW
81 ,rsHelp
82 ,eKind
83 ,pSubMenu
84 )
0e320a79 85{
22e90769 86 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
8635b0db
DW
87 memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
88 m_vMenuData.id = (USHORT)nId;
75f11ad7 89
f95255e2
DW
90 Init();
91} // end of wxMenuItem::wxMenuItem
92
93wxMenuItem::wxMenuItem(
94 wxMenu* pParentMenu
95, int nId
ab4fece8
DW
96, const wxString& rsText
97, const wxString& rsHelp
f95255e2
DW
98, bool bIsCheckable
99, wxMenu* pSubMenu
100)
ab4fece8
DW
101: wxMenuItemBase( pParentMenu
102 ,nId
3a7c1253 103 ,wxPMTextToLabel(rsText)
ab4fece8
DW
104 ,rsHelp
105 ,bIsCheckable ? wxITEM_CHECK : wxITEM_NORMAL
106 ,pSubMenu
107 )
f95255e2
DW
108{
109 wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
938aa9c4
DW
110 memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
111 m_vMenuData.id = (USHORT)nId;
f95255e2
DW
112
113 Init();
114} // end of wxMenuItem::wxMenuItem
115
116void wxMenuItem::Init()
117{
ab4fece8
DW
118 m_vRadioGroup.m_nStart = -1;
119 m_bIsRadioGroupStart = FALSE;
22e90769 120
f95255e2 121#if wxUSE_OWNER_DRAWN
ab4fece8
DW
122 //
123 // Set default menu colors
124 //
98fbab9e
VZ
125 SetTextColour(wxNullColour);
126 SetBackgroundColour(wxNullColour);
75f11ad7 127
ab4fece8
DW
128 //
129 // We don't want normal items be owner-drawn
130 //
98fbab9e 131 SetOwnerDrawn(false);
f95255e2 132#endif // wxUSE_OWNER_DRAWN
ab4fece8 133} // end of wxMenuItem::Init
0e320a79 134
75f11ad7 135wxMenuItem::~wxMenuItem()
0e320a79 136{
22e90769 137} // end of wxMenuItem::~wxMenuItem
0e320a79 138
22e90769
DW
139//
140// Misc
0e320a79
DW
141// ----
142
22e90769
DW
143//
144// Return the id for calling Win32 API functions
145//
75f11ad7
DW
146int wxMenuItem::GetRealId() const
147{
c5fb56c0 148 return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId();
22e90769 149} // end of wxMenuItem::GetRealId
c5fb56c0 150
22e90769
DW
151//
152// Get item state
c5fb56c0 153// --------------
c5fb56c0
DW
154bool wxMenuItem::IsChecked() const
155{
6670f564
WS
156 USHORT uFlag = SHORT1FROMMR(::WinSendMsg( GetHMenuOf(m_parentMenu)
157 ,MM_QUERYITEMATTR
158 ,MPFROM2SHORT(GetId(), TRUE)
159 ,MPFROMSHORT(MIA_CHECKED)
160 ));
22e90769 161
6670f564 162 return (uFlag & MIA_CHECKED) == MIA_CHECKED ;
22e90769
DW
163} // end of wxMenuItem::IsChecked
164
52af3158 165wxString wxMenuItemBase::GetLabelText(
c9667cda 166 const wxString& rsText
22e90769 167)
c5fb56c0 168{
c9667cda
DW
169 wxString sLabel;
170
0fba44b4 171 for (const wxChar* zPc = rsText.c_str(); *zPc; zPc++)
2b33b728 172 {
c9667cda 173 if (*zPc == wxT('~') || *zPc == wxT('&'))
2b33b728 174 {
c9667cda
DW
175 //
176 // '~' is the escape character for OS/2PM and '&' is the one for
77ffb593 177 // wxWidgets - skip both of them
c9667cda 178 //
2b33b728
SN
179 continue;
180 }
c9667cda 181 sLabel += *zPc;
2b33b728 182 }
c9667cda 183 return sLabel;
52af3158 184} // end of wxMenuItemBase::GetLabelText
75f11ad7 185
598d8cac
DW
186//
187// Radio group stuff
f95255e2 188// -----------------
598d8cac 189//
f95255e2
DW
190void wxMenuItem::SetAsRadioGroupStart()
191{
6670f564 192 m_bIsRadioGroupStart = true;
f95255e2
DW
193} // end of wxMenuItem::SetAsRadioGroupStart
194
195void wxMenuItem::SetRadioGroupStart(
196 int nStart
197)
198{
598d8cac 199 wxASSERT_MSG( !m_bIsRadioGroupStart
9a83f860 200 ,wxT("should only be called for the next radio items")
598d8cac 201 );
f95255e2
DW
202
203 m_vRadioGroup.m_nStart = nStart;
598d8cac 204} // wxMenuItem::SetRadioGroupStart
f95255e2
DW
205
206void wxMenuItem::SetRadioGroupEnd(
207 int nEnd
208)
209{
598d8cac 210 wxASSERT_MSG( m_bIsRadioGroupStart
9a83f860 211 ,wxT("should only be called for the first radio item")
598d8cac 212 );
f95255e2
DW
213 m_vRadioGroup.m_nEnd = nEnd;
214} // end of wxMenuItem::SetRadioGroupEnd
215
0e320a79
DW
216// change item state
217// -----------------
218
22e90769
DW
219void wxMenuItem::Enable(
220 bool bEnable
221)
0e320a79 222{
22e90769 223 bool bOk;
75f11ad7 224
22e90769
DW
225 if (m_isEnabled == bEnable)
226 return;
227 if (bEnable)
914589c2
DW
228 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
229 ,MM_SETITEMATTR
230 ,MPFROM2SHORT(GetRealId(), TRUE)
f6bcfd97 231 ,MPFROM2SHORT(MIA_DISABLED, FALSE)
914589c2 232 );
22e90769 233 else
914589c2
DW
234 bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
235 ,MM_SETITEMATTR
236 ,MPFROM2SHORT(GetRealId(), TRUE)
f6bcfd97 237 ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
914589c2 238 );
22e90769
DW
239 if (!bOk)
240 {
2173b18f 241 wxLogLastError(wxT("EnableMenuItem"));
0e320a79 242 }
22e90769
DW
243 wxMenuItemBase::Enable(bEnable);
244} // end of wxMenuItem::Enable
0e320a79 245
22e90769
DW
246void wxMenuItem::Check(
247 bool bCheck
248)
0e320a79 249{
22e90769 250 bool bOk;
75f11ad7 251
d65c269b 252 wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
22e90769 253 if (m_isChecked == bCheck)
c5fb56c0 254 return;
f95255e2 255
50b39f8f 256 HMENU hMenu = GetHmenuOf(m_parentMenu);
598d8cac
DW
257
258 if (GetKind() == wxITEM_RADIO)
ab4fece8
DW
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);
ab4fece8 271
598d8cac 272 wxCHECK_RET( nPos != wxNOT_FOUND
9a83f860 273 ,wxT("menuitem not found in the menu items list?")
598d8cac 274 );
ab4fece8
DW
275
276 //
277 // Get the radio group range
278 //
598d8cac
DW
279 int nStart;
280 int nEnd;
ab4fece8
DW
281
282 if (m_bIsRadioGroupStart)
283 {
598d8cac
DW
284 //
285 // We already have all information we need
286 //
ab4fece8 287 nStart = nPos;
598d8cac 288 nEnd = m_vRadioGroup.m_nEnd;
ab4fece8 289 }
598d8cac 290 else // next radio group item
ab4fece8
DW
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 //
2461cfa0 302 wxMenuItemList::compatibility_iterator node = rItems.Item(nStart);
ab4fece8 303
2461cfa0 304 for (int n = nStart; n <= nEnd && node; n++)
ab4fece8 305 {
ab4fece8
DW
306 if (n == nPos)
307 {
598d8cac
DW
308 ::WinSendMsg( hMenu
309 ,MM_SETITEMATTR
310 ,MPFROM2SHORT(n, TRUE)
311 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
312 );
ab4fece8 313 }
598d8cac 314 if (n != nPos)
ab4fece8 315 {
2461cfa0 316 node->GetData()->m_isChecked = FALSE;
598d8cac
DW
317 ::WinSendMsg( hMenu
318 ,MM_SETITEMATTR
319 ,MPFROM2SHORT(n, TRUE)
320 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
321 );
ab4fece8 322 }
2461cfa0 323 node = node->GetNext();
ab4fece8
DW
324 }
325 }
326 else // check item
327 {
328 if (bCheck)
50b39f8f 329 bOk = (bool)::WinSendMsg( hMenu
ab4fece8
DW
330 ,MM_SETITEMATTR
331 ,MPFROM2SHORT(GetRealId(), TRUE)
332 ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
333 );
334 else
50b39f8f 335 bOk = (bool)::WinSendMsg( hMenu
ab4fece8
DW
336 ,MM_SETITEMATTR
337 ,MPFROM2SHORT(GetRealId(), TRUE)
338 ,MPFROM2SHORT(MIA_CHECKED, FALSE)
339 );
340 }
22e90769
DW
341 if (!bOk)
342 {
2173b18f 343 wxLogLastError(wxT("CheckMenuItem"));
75f11ad7 344 }
22e90769
DW
345 wxMenuItemBase::Check(bCheck);
346} // end of wxMenuItem::Check
75f11ad7 347
52af3158 348void wxMenuItem::SetItemLabel( const wxString& rText )
75f11ad7 349{
22e90769
DW
350 //
351 // Don't do anything if label didn't change
352 //
2b33b728 353
3a7c1253 354 wxString sText = wxPMTextToLabel(rText);
50b39f8f 355 if (m_text == sText)
75f11ad7
DW
356 return;
357
345319d6 358 // wxMenuItemBase will do stock ID checks
52af3158 359 wxMenuItemBase::SetItemLabel(sText);
345319d6 360
98fbab9e 361 HWND hMenu = GetHmenuOf(m_parentMenu);
22e90769
DW
362
363 wxCHECK_RET(hMenu, wxT("menuitem without menu"));
75f11ad7 364
c5fb56c0
DW
365#if wxUSE_ACCEL
366 m_parentMenu->UpdateAccel(this);
367#endif // wxUSE_ACCEL
75f11ad7 368
6670f564
WS
369 USHORT uId = (USHORT)GetRealId();
370 MENUITEM vItem;
371 USHORT uFlagsOld;
914589c2 372
22e90769
DW
373 if (!::WinSendMsg( hMenu
374 ,MM_QUERYITEM
375 ,MPFROM2SHORT(uId, TRUE)
376 ,(MPARAM)&vItem
377 ))
75f11ad7 378 {
2173b18f 379 wxLogLastError(wxT("GetMenuState"));
75f11ad7
DW
380 }
381 else
382 {
22e90769
DW
383 uFlagsOld = vItem.afStyle;
384 if (IsSubMenu())
75f11ad7 385 {
22e90769 386 uFlagsOld |= MIS_SUBMENU;
75f11ad7
DW
387 }
388
f450b5cf 389 char* pData;
c5fb56c0 390
75f11ad7 391#if wxUSE_OWNER_DRAWN
22e90769 392 if (IsOwnerDrawn())
75f11ad7 393 {
22e90769 394 uFlagsOld |= MIS_OWNERDRAW;
f450b5cf 395 pData = (char*)this;
75f11ad7
DW
396 }
397 else
398#endif //owner drawn
399 {
22e90769 400 uFlagsOld |= MIS_TEXT;
404aba09 401 pData = (char*) m_text.wx_str();
22e90769
DW
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"));
75f11ad7
DW
414 }
415
22e90769
DW
416 //
417 // Set the text
418 //
419 if (::WinSendMsg( hMenu
420 ,MM_SETITEMTEXT
421 ,MPFROMSHORT(uId)
422 ,(MPARAM)pData
423 ))
75f11ad7
DW
424 {
425 wxLogLastError(wxT("ModifyMenu"));
426 }
427 }
22e90769 428} // end of wxMenuItem::SetText
0e320a79 429
98fbab9e
VZ
430#if wxUSE_OWNER_DRAWN
431
432wxString wxMenuItem::GetName() const
433{
434 return GetItemLabelText();
435}
436
437bool 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
539bool wxMenuItem::OnDrawItem( wxDC& rDC,
540 const wxRect& rRect,
541 wxODAction eAction,
542 wxODStatus eStatus )
c5fb56c0 543{
98fbab9e
VZ
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
c5fb56c0
DW
794
795// ----------------------------------------------------------------------------
796// wxMenuItemBase
797// ----------------------------------------------------------------------------
798
22e90769
DW
799wxMenuItem* wxMenuItemBase::New(
800 wxMenu* pParentMenu
801, int nId
802, const wxString& rName
803, const wxString& rHelp
d65c269b 804, wxItemKind kind
22e90769
DW
805, wxMenu* pSubMenu
806)
c5fb56c0 807{
22e90769
DW
808 return new wxMenuItem( pParentMenu
809 ,nId
810 ,rName
811 ,rHelp
d65c269b 812 ,kind
22e90769
DW
813 ,pSubMenu
814 );
815} // end of wxMenuItemBase::New