1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/window.h"
35 #include "wx/dialog.h"
37 #include "wx/bitmap.h"
38 #include "wx/dcmemory.h"
43 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
45 #include "wx/sysopt.h"
46 #include "wx/dcprint.h"
47 #include "wx/module.h"
48 #include "wx/dynload.h"
50 #ifdef wxHAVE_RAW_BITMAP
51 #include "wx/rawbmp.h"
57 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
66 #define AC_SRC_ALPHA 1
69 /* Quaternary raster codes */
71 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
74 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
76 // ---------------------------------------------------------------------------
78 // ---------------------------------------------------------------------------
80 static const int VIEWPORT_EXTENT
= 1000;
82 static const int MM_POINTS
= 9;
83 static const int MM_METRIC
= 10;
85 // usually this is defined in math.h
87 static const double M_PI
= 3.14159265358979323846;
90 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
99 We currently let Windows do all the translations itself so these macros are
100 not really needed (any more) but keep them to enhance readability of the
101 code by allowing to see where are the logical and where are the device
106 #define XLOG2DEV(x) (x)
107 #define YLOG2DEV(y) (y)
110 #define XDEV2LOG(x) (x)
111 #define YDEV2LOG(y) (y)
113 // ---------------------------------------------------------------------------
115 // ---------------------------------------------------------------------------
117 // convert degrees to radians
118 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
120 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
122 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
123 // to pass it to this function but as we already have it at the point
124 // of call anyhow we do
126 // return true if we could draw the bitmap in one way or the other, false
128 static bool AlphaBlt(HDC hdcDst
,
129 int x
, int y
, int w
, int h
,
131 const wxBitmap
& bmpSrc
);
133 #ifdef wxHAVE_RAW_BITMAP
134 // our (limited) AlphaBlend() replacement
136 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
143 // instead of duplicating the same code which sets and then restores text
144 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
145 // encapsulate this in a small helper class
147 // wxColourChanger: changes the text colours in the ctor if required and
148 // restores them in the dtor
149 class wxColourChanger
152 wxColourChanger(wxDC
& dc
);
158 COLORREF m_colFgOld
, m_colBgOld
;
162 DECLARE_NO_COPY_CLASS(wxColourChanger
)
165 // this class saves the old stretch blit mode during its life time
166 class StretchBltModeChanger
169 StretchBltModeChanger(HDC hdc
, int mode
)
173 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
175 wxLogLastError(_T("SetStretchBltMode"));
179 ~StretchBltModeChanger()
182 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
183 wxLogLastError(_T("SetStretchBltMode"));
192 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
195 // ===========================================================================
197 // ===========================================================================
199 // ----------------------------------------------------------------------------
201 // ----------------------------------------------------------------------------
203 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
205 const wxBrush
& brush
= dc
.GetBrush();
206 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
208 HDC hdc
= GetHdcOf(dc
);
209 m_colFgOld
= ::GetTextColor(hdc
);
210 m_colBgOld
= ::GetBkColor(hdc
);
212 // note that Windows convention is opposite to wxWindows one, this is
213 // why text colour becomes the background one and vice versa
214 const wxColour
& colFg
= dc
.GetTextForeground();
217 ::SetBkColor(hdc
, colFg
.GetPixel());
220 const wxColour
& colBg
= dc
.GetTextBackground();
223 ::SetTextColor(hdc
, colBg
.GetPixel());
227 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
230 // flag which telsl us to undo changes in the dtor
235 // nothing done, nothing to undo
240 wxColourChanger::~wxColourChanger()
244 // restore the colours we changed
245 HDC hdc
= GetHdcOf(m_dc
);
247 ::SetBkMode(hdc
, TRANSPARENT
);
248 ::SetTextColor(hdc
, m_colFgOld
);
249 ::SetBkColor(hdc
, m_colBgOld
);
253 // ---------------------------------------------------------------------------
255 // ---------------------------------------------------------------------------
257 // Default constructor
268 #endif // wxUSE_PALETTE
278 SelectOldObjects(m_hDC
);
280 // if we own the HDC, we delete it, otherwise we just release it
284 ::DeleteDC(GetHdc());
286 else // we don't own our HDC
290 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
294 // Must have been a wxScreenDC
295 ::ReleaseDC((HWND
) NULL
, GetHdc());
301 // This will select current objects out of the DC,
302 // which is what you have to do before deleting the
304 void wxDC::SelectOldObjects(WXHDC dc
)
310 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
312 if (m_selectedBitmap
.Ok())
314 m_selectedBitmap
.SetSelectedInto(NULL
);
321 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
326 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
331 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
338 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
341 #endif // wxUSE_PALETTE
344 m_brush
= wxNullBrush
;
347 m_palette
= wxNullPalette
;
348 #endif // wxUSE_PALETTE
350 m_backgroundBrush
= wxNullBrush
;
351 m_selectedBitmap
= wxNullBitmap
;
354 // ---------------------------------------------------------------------------
356 // ---------------------------------------------------------------------------
358 void wxDC::UpdateClipBox()
360 #ifdef __WXMICROWIN__
361 if (!GetHDC()) return;
365 ::GetClipBox(GetHdc(), &rect
);
367 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
368 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
369 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
370 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
373 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
374 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
376 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
378 #ifdef __WXMICROWIN__
379 if (!GetHdc()) return;
380 #endif // __WXMICROWIN__
382 // note that we combine the new clipping region with the existing one: this
383 // is compatible with what the other ports do and is the documented
384 // behaviour now (starting with 2.3.3)
385 #if defined(__WIN16__) || defined(__WXWINCE__)
387 if ( !::GetClipBox(GetHdc(), &rectClip
) )
390 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
391 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
392 rectClip
.right
, rectClip
.bottom
);
394 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
396 ::SelectClipRgn(GetHdc(), hrgnDest
);
399 ::DeleteObject(hrgnClipOld
);
400 ::DeleteObject(hrgnDest
);
402 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
404 wxLogLastError(_T("ExtSelectClipRgn"));
415 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
417 // the region coords are always the device ones, so do the translation
420 // FIXME: possible +/-1 error here, to check!
421 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
423 LogicalToDeviceX(x
+ w
),
424 LogicalToDeviceY(y
+ h
));
427 wxLogLastError(_T("CreateRectRgn"));
431 SetClippingHrgn((WXHRGN
)hrgn
);
433 ::DeleteObject(hrgn
);
437 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
439 SetClippingHrgn(region
.GetHRGN());
442 void wxDC::DestroyClippingRegion()
444 #ifdef __WXMICROWIN__
445 if (!GetHDC()) return;
448 if (m_clipping
&& m_hDC
)
450 // TODO: this should restore the previous clipping region,
451 // so that OnPaint processing works correctly, and the update
452 // clipping region doesn't get destroyed after the first
453 // DestroyClippingRegion.
454 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
455 ::SelectClipRgn(GetHdc(), rgn
);
462 // ---------------------------------------------------------------------------
463 // query capabilities
464 // ---------------------------------------------------------------------------
466 bool wxDC::CanDrawBitmap() const
471 bool wxDC::CanGetTextExtent() const
473 #ifdef __WXMICROWIN__
474 // TODO Extend MicroWindows' GetDeviceCaps function
477 // What sort of display is it?
478 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
480 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
484 int wxDC::GetDepth() const
486 #ifdef __WXMICROWIN__
487 if (!GetHDC()) return 16;
490 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
493 // ---------------------------------------------------------------------------
495 // ---------------------------------------------------------------------------
499 #ifdef __WXMICROWIN__
500 if (!GetHDC()) return;
506 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
510 // No, I think we should simply ignore this if printing on e.g.
512 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
513 if (!m_selectedBitmap
.Ok())
516 rect
.left
= 0; rect
.top
= 0;
517 rect
.right
= m_selectedBitmap
.GetWidth();
518 rect
.bottom
= m_selectedBitmap
.GetHeight();
522 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
525 DWORD colour
= ::GetBkColor(GetHdc());
526 HBRUSH brush
= ::CreateSolidBrush(colour
);
527 ::FillRect(GetHdc(), &rect
, brush
);
528 ::DeleteObject(brush
);
530 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
531 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
534 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
536 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
537 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
538 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
539 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
543 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
549 #ifdef __WXMICROWIN__
550 if (!GetHDC()) return FALSE
;
553 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
555 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
556 : FLOODFILLBORDER
) ) ;
559 // quoting from the MSDN docs:
561 // Following are some of the reasons this function might fail:
563 // * The filling could not be completed.
564 // * The specified point has the boundary color specified by the
565 // crColor parameter (if FLOODFILLBORDER was requested).
566 // * The specified point does not have the color specified by
567 // crColor (if FLOODFILLSURFACE was requested)
568 // * The point is outside the clipping region that is, it is not
569 // visible on the device.
571 wxLogLastError(wxT("ExtFloodFill"));
574 CalcBoundingBox(x
, y
);
580 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
582 #ifdef __WXMICROWIN__
583 if (!GetHDC()) return FALSE
;
586 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
588 // get the color of the pixel
589 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
591 wxRGBToColour(*col
, pixelcolor
);
596 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
598 #ifdef __WXMICROWIN__
599 if (!GetHDC()) return;
602 wxCoord x1
= x
-VIEWPORT_EXTENT
;
603 wxCoord y1
= y
-VIEWPORT_EXTENT
;
604 wxCoord x2
= x
+VIEWPORT_EXTENT
;
605 wxCoord y2
= y
+VIEWPORT_EXTENT
;
607 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
608 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
610 CalcBoundingBox(x1
, y1
);
611 CalcBoundingBox(x2
, y2
);
614 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
616 #ifdef __WXMICROWIN__
617 if (!GetHDC()) return;
620 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
622 CalcBoundingBox(x1
, y1
);
623 CalcBoundingBox(x2
, y2
);
626 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
627 // and ending at (x2, y2)
628 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
629 wxCoord x2
, wxCoord y2
,
630 wxCoord xc
, wxCoord yc
)
633 // Slower emulation since WinCE doesn't support Pie and Arc
634 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
635 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
636 if( y1
>yc
) sa
= -sa
; // below center
637 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
638 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
641 #ifdef __WXMICROWIN__
642 if (!GetHDC()) return;
645 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
649 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
650 wxCoord r
= (wxCoord
)radius
;
652 // treat the special case of full circle separately
653 if ( x1
== x2
&& y1
== y2
)
655 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
659 wxCoord xx1
= XLOG2DEV(x1
);
660 wxCoord yy1
= YLOG2DEV(y1
);
661 wxCoord xx2
= XLOG2DEV(x2
);
662 wxCoord yy2
= YLOG2DEV(y2
);
663 wxCoord xxc
= XLOG2DEV(xc
);
664 wxCoord yyc
= YLOG2DEV(yc
);
665 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
667 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
668 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
669 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
670 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
672 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
674 // Have to add 1 to bottom-right corner of rectangle
675 // to make semi-circles look right (crooked line otherwise).
676 // Unfortunately this is not a reliable method, depends
677 // on the size of shape.
678 // TODO: figure out why this happens!
679 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
683 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
686 CalcBoundingBox(xc
- r
, yc
- r
);
687 CalcBoundingBox(xc
+ r
, yc
+ r
);
691 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
692 wxCoord width
, wxCoord height
)
694 #ifdef __WXMICROWIN__
695 if (!GetHDC()) return;
698 wxCoord x2
= x1
+ width
,
701 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
709 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
711 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
714 // In WIN16, draw a cross
715 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
716 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
717 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
718 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
719 ::SetROP2(GetHdc(), R2_COPYPEN
);
720 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
721 MoveToEx(GetHdc(), x1
, y1
, NULL
);
722 LineTo(GetHdc(), x2
, y2
);
723 MoveToEx(GetHdc(), x2
, y1
, NULL
);
724 LineTo(GetHdc(), x1
, y2
);
725 ::SelectObject(GetHdc(), hPenOld
);
726 ::SelectObject(GetHdc(), hBrushOld
);
727 ::DeleteObject(blackPen
);
730 CalcBoundingBox(x1
, y1
);
731 CalcBoundingBox(x2
, y2
);
734 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
736 #ifdef __WXMICROWIN__
737 if (!GetHDC()) return;
740 COLORREF color
= 0x00ffffff;
743 color
= m_pen
.GetColour().GetPixel();
746 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
748 CalcBoundingBox(x
, y
);
751 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
753 #ifdef __WXMICROWIN__
754 if (!GetHDC()) return;
757 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
759 // Do things less efficiently if we have offsets
760 if (xoffset
!= 0 || yoffset
!= 0)
762 POINT
*cpoints
= new POINT
[n
];
764 for (i
= 0; i
< n
; i
++)
766 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
767 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
769 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
772 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
774 (void)Polygon(GetHdc(), cpoints
, n
);
776 SetPolyFillMode(GetHdc(),prev
);
783 for (i
= 0; i
< n
; i
++)
784 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
787 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
789 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
791 SetPolyFillMode(GetHdc(),prev
);
796 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
798 #ifdef __WXMICROWIN__
799 if (!GetHDC()) return;
802 // Do things less efficiently if we have offsets
803 if (xoffset
!= 0 || yoffset
!= 0)
805 POINT
*cpoints
= new POINT
[n
];
807 for (i
= 0; i
< n
; i
++)
809 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
810 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
812 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
814 (void)Polyline(GetHdc(), cpoints
, n
);
820 for (i
= 0; i
< n
; i
++)
821 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
823 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
827 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
829 #ifdef __WXMICROWIN__
830 if (!GetHDC()) return;
833 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
835 wxCoord x2
= x
+ width
;
836 wxCoord y2
= y
+ height
;
838 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
841 rect
.left
= XLOG2DEV(x
);
842 rect
.top
= YLOG2DEV(y
);
843 rect
.right
= XLOG2DEV(x2
);
844 rect
.bottom
= YLOG2DEV(y2
);
845 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
849 // Windows draws the filled rectangles without outline (i.e. drawn with a
850 // transparent pen) one pixel smaller in both directions and we want them
851 // to have the same size regardless of which pen is used - adjust
853 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
854 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
860 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
864 CalcBoundingBox(x
, y
);
865 CalcBoundingBox(x2
, y2
);
868 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
870 #ifdef __WXMICROWIN__
871 if (!GetHDC()) return;
874 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
876 // Now, a negative radius value is interpreted to mean
877 // 'the proportion of the smallest X or Y dimension'
881 double smallest
= 0.0;
886 radius
= (- radius
* smallest
);
889 wxCoord x2
= (x
+width
);
890 wxCoord y2
= (y
+height
);
892 // Windows draws the filled rectangles without outline (i.e. drawn with a
893 // transparent pen) one pixel smaller in both directions and we want them
894 // to have the same size regardless of which pen is used - adjust
895 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
901 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
902 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
904 CalcBoundingBox(x
, y
);
905 CalcBoundingBox(x2
, y2
);
908 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
910 #ifdef __WXMICROWIN__
911 if (!GetHDC()) return;
914 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
916 wxCoord x2
= (x
+width
);
917 wxCoord y2
= (y
+height
);
919 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
921 CalcBoundingBox(x
, y
);
922 CalcBoundingBox(x2
, y2
);
925 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
926 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
929 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
932 #ifdef __WXMICROWIN__
933 if (!GetHDC()) return;
936 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
941 int rx1
= XLOG2DEV(x
+w
/2);
942 int ry1
= YLOG2DEV(y
+h
/2);
949 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
950 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
951 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
952 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
954 // draw pie with NULL_PEN first and then outline otherwise a line is
955 // drawn from the start and end points to the centre
956 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
959 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
964 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
965 rx1
, ry1
-1, rx2
, ry2
-1);
968 ::SelectObject(GetHdc(), hpenOld
);
970 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
973 CalcBoundingBox(x
, y
);
974 CalcBoundingBox(x2
, y2
);
978 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
980 #ifdef __WXMICROWIN__
981 if (!GetHDC()) return;
984 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
987 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
989 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
992 CalcBoundingBox(x
, y
);
993 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
996 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
998 #ifdef __WXMICROWIN__
999 if (!GetHDC()) return;
1002 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1004 int width
= bmp
.GetWidth(),
1005 height
= bmp
.GetHeight();
1007 HBITMAP hbmpMask
= 0;
1010 HPALETTE oldPal
= 0;
1011 #endif // wxUSE_PALETTE
1013 if ( bmp
.HasAlpha() )
1016 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1018 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1024 wxMask
*mask
= bmp
.GetMask();
1026 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1030 // don't give assert here because this would break existing
1031 // programs - just silently ignore useMask parameter
1038 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1040 // On some systems, MaskBlt succeeds yet is much much slower
1041 // than the wxWindows fall-back implementation. So we need
1042 // to be able to switch this on and off at runtime.
1044 #if wxUSE_SYSTEM_OPTIONS
1045 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1049 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1050 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1052 wxPalette
*pal
= bmp
.GetPalette();
1053 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1055 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1056 ::RealizePalette(hdcMem
);
1058 #endif // wxUSE_PALETTE
1060 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1063 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1067 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1068 #endif // wxUSE_PALETTE
1070 ::SelectObject(hdcMem
, hOldBitmap
);
1077 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1080 memDC
.SelectObject(bmp
);
1082 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1084 memDC
.SelectObject(wxNullBitmap
);
1087 else // no mask, just use BitBlt()
1090 HDC memdc
= ::CreateCompatibleDC( cdc
);
1091 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1093 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1095 COLORREF old_textground
= ::GetTextColor(GetHdc());
1096 COLORREF old_background
= ::GetBkColor(GetHdc());
1097 if (m_textForegroundColour
.Ok())
1099 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1101 if (m_textBackgroundColour
.Ok())
1103 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1107 wxPalette
*pal
= bmp
.GetPalette();
1108 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1110 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1111 ::RealizePalette(memdc
);
1113 #endif // wxUSE_PALETTE
1115 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1116 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1120 ::SelectPalette(memdc
, oldPal
, FALSE
);
1121 #endif // wxUSE_PALETTE
1123 ::SelectObject( memdc
, hOldBitmap
);
1124 ::DeleteDC( memdc
);
1126 ::SetTextColor(GetHdc(), old_textground
);
1127 ::SetBkColor(GetHdc(), old_background
);
1131 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1133 #ifdef __WXMICROWIN__
1134 if (!GetHDC()) return;
1137 DrawAnyText(text
, x
, y
);
1139 // update the bounding box
1140 CalcBoundingBox(x
, y
);
1143 GetTextExtent(text
, &w
, &h
);
1144 CalcBoundingBox(x
+ w
, y
+ h
);
1147 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1149 #ifdef __WXMICROWIN__
1150 if (!GetHDC()) return;
1153 // prepare for drawing the text
1154 if ( m_textForegroundColour
.Ok() )
1155 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1157 DWORD old_background
= 0;
1158 if ( m_textBackgroundColour
.Ok() )
1160 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1163 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1167 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1168 text
.c_str(), text
.length(), NULL
) == 0 )
1170 wxLogLastError(wxT("TextOut"));
1173 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1174 text
.c_str(), text
.length()) == 0 )
1176 wxLogLastError(wxT("TextOut"));
1180 // restore the old parameters (text foreground colour may be left because
1181 // it never is set to anything else, but background should remain
1182 // transparent even if we just drew an opaque string)
1183 if ( m_textBackgroundColour
.Ok() )
1184 (void)SetBkColor(GetHdc(), old_background
);
1186 SetBkMode(GetHdc(), TRANSPARENT
);
1189 void wxDC::DoDrawRotatedText(const wxString
& text
,
1190 wxCoord x
, wxCoord y
,
1193 #ifdef __WXMICROWIN__
1194 if (!GetHDC()) return;
1197 // we test that we have some font because otherwise we should still use the
1198 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1199 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1200 // font for drawing rotated fonts unfortunately)
1201 if ( (angle
== 0.0) && m_font
.Ok() )
1203 DoDrawText(text
, x
, y
);
1205 #ifndef __WXMICROWIN__
1208 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1209 // because it's not TrueType and so can't have non zero
1210 // orientation/escapement under Win9x
1211 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1212 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1214 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1216 wxLogLastError(wxT("GetObject(hfont)"));
1219 // GDI wants the angle in tenth of degree
1220 long angle10
= (long)(angle
* 10);
1221 lf
.lfEscapement
= angle10
;
1222 lf
. lfOrientation
= angle10
;
1224 hfont
= ::CreateFontIndirect(&lf
);
1227 wxLogLastError(wxT("CreateFont"));
1231 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1233 DrawAnyText(text
, x
, y
);
1235 (void)::SelectObject(GetHdc(), hfontOld
);
1236 (void)::DeleteObject(hfont
);
1239 // call the bounding box by adding all four vertices of the rectangle
1240 // containing the text to it (simpler and probably not slower than
1241 // determining which of them is really topmost/leftmost/...)
1243 GetTextExtent(text
, &w
, &h
);
1245 double rad
= DegToRad(angle
);
1247 // "upper left" and "upper right"
1248 CalcBoundingBox(x
, y
);
1249 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1251 // "bottom left" and "bottom right"
1252 x
+= (wxCoord
)(h
*sin(rad
));
1253 y
+= (wxCoord
)(h
*cos(rad
));
1254 CalcBoundingBox(x
, y
);
1255 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1260 // ---------------------------------------------------------------------------
1262 // ---------------------------------------------------------------------------
1266 void wxDC::DoSelectPalette(bool realize
)
1268 #ifdef __WXMICROWIN__
1269 if (!GetHDC()) return;
1272 // Set the old object temporarily, in case the assignment deletes an object
1273 // that's not yet selected out.
1276 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1280 if ( m_palette
.Ok() )
1282 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1283 GetHpaletteOf(m_palette
),
1286 m_oldPalette
= (WXHPALETTE
) oldPal
;
1289 ::RealizePalette(GetHdc());
1293 void wxDC::SetPalette(const wxPalette
& palette
)
1297 m_palette
= palette
;
1298 DoSelectPalette(TRUE
);
1302 void wxDC::InitializePalette()
1304 if ( wxDisplayDepth() <= 8 )
1306 // look for any window or parent that has a custom palette. If any has
1307 // one then we need to use it in drawing operations
1308 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1310 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1311 if ( m_hasCustomPalette
)
1313 m_palette
= win
->GetPalette();
1315 // turn on MSW translation for this palette
1321 #endif // wxUSE_PALETTE
1323 void wxDC::SetFont(const wxFont
& the_font
)
1325 #ifdef __WXMICROWIN__
1326 if (!GetHDC()) return;
1329 // Set the old object temporarily, in case the assignment deletes an object
1330 // that's not yet selected out.
1333 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1342 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1346 if (m_font
.Ok() && m_font
.GetResourceHandle())
1348 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1349 if (f
== (HFONT
) NULL
)
1351 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1354 m_oldFont
= (WXHFONT
) f
;
1358 void wxDC::SetPen(const wxPen
& pen
)
1360 #ifdef __WXMICROWIN__
1361 if (!GetHDC()) return;
1364 // Set the old object temporarily, in case the assignment deletes an object
1365 // that's not yet selected out.
1368 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1377 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1383 if (m_pen
.GetResourceHandle())
1385 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1387 m_oldPen
= (WXHPEN
) p
;
1392 void wxDC::SetBrush(const wxBrush
& brush
)
1394 #ifdef __WXMICROWIN__
1395 if (!GetHDC()) return;
1398 // Set the old object temporarily, in case the assignment deletes an object
1399 // that's not yet selected out.
1402 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1411 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1417 // to make sure the brush is alligned with the logical coordinates
1418 wxBitmap
*stipple
= m_brush
.GetStipple();
1419 if ( stipple
&& stipple
->Ok() )
1422 ::SetBrushOrgEx(GetHdc(),
1423 m_deviceOriginX
% stipple
->GetWidth(),
1424 m_deviceOriginY
% stipple
->GetHeight(),
1425 NULL
); // don't need previous brush origin
1427 ::SetBrushOrg(GetHdc(),
1428 m_deviceOriginX
% stipple
->GetWidth(),
1429 m_deviceOriginY
% stipple
->GetHeight());
1433 if ( m_brush
.GetResourceHandle() )
1436 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1438 m_oldBrush
= (WXHBRUSH
) b
;
1443 void wxDC::SetBackground(const wxBrush
& brush
)
1445 #ifdef __WXMICROWIN__
1446 if (!GetHDC()) return;
1449 m_backgroundBrush
= brush
;
1451 if ( m_backgroundBrush
.Ok() )
1453 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1457 void wxDC::SetBackgroundMode(int mode
)
1459 #ifdef __WXMICROWIN__
1460 if (!GetHDC()) return;
1463 m_backgroundMode
= mode
;
1465 // SetBackgroundColour now only refers to text background
1466 // and m_backgroundMode is used there
1469 void wxDC::SetLogicalFunction(int function
)
1471 #ifdef __WXMICROWIN__
1472 if (!GetHDC()) return;
1475 m_logicalFunction
= function
;
1480 void wxDC::SetRop(WXHDC dc
)
1482 if ( !dc
|| m_logicalFunction
< 0 )
1487 switch (m_logicalFunction
)
1489 case wxCLEAR
: rop
= R2_BLACK
; break;
1490 case wxXOR
: rop
= R2_XORPEN
; break;
1491 case wxINVERT
: rop
= R2_NOT
; break;
1492 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1493 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1494 case wxCOPY
: rop
= R2_COPYPEN
; break;
1495 case wxAND
: rop
= R2_MASKPEN
; break;
1496 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1497 case wxNO_OP
: rop
= R2_NOP
; break;
1498 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1499 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1500 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1501 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1502 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1503 case wxOR
: rop
= R2_MERGEPEN
; break;
1504 case wxSET
: rop
= R2_WHITE
; break;
1507 wxFAIL_MSG( wxT("unsupported logical function") );
1511 SetROP2(GetHdc(), rop
);
1514 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1516 // We might be previewing, so return TRUE to let it continue.
1524 void wxDC::StartPage()
1528 void wxDC::EndPage()
1532 // ---------------------------------------------------------------------------
1534 // ---------------------------------------------------------------------------
1536 wxCoord
wxDC::GetCharHeight() const
1538 #ifdef __WXMICROWIN__
1539 if (!GetHDC()) return 0;
1542 TEXTMETRIC lpTextMetric
;
1544 GetTextMetrics(GetHdc(), &lpTextMetric
);
1546 return lpTextMetric
.tmHeight
;
1549 wxCoord
wxDC::GetCharWidth() const
1551 #ifdef __WXMICROWIN__
1552 if (!GetHDC()) return 0;
1555 TEXTMETRIC lpTextMetric
;
1557 GetTextMetrics(GetHdc(), &lpTextMetric
);
1559 return lpTextMetric
.tmAveCharWidth
;
1562 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1563 wxCoord
*descent
, wxCoord
*externalLeading
,
1566 #ifdef __WXMICROWIN__
1571 if (descent
) *descent
= 0;
1572 if (externalLeading
) *externalLeading
= 0;
1575 #endif // __WXMICROWIN__
1580 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1582 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1584 else // don't change the font
1592 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1593 GetTextMetrics(GetHdc(), &tm
);
1600 *descent
= tm
.tmDescent
;
1601 if (externalLeading
)
1602 *externalLeading
= tm
.tmExternalLeading
;
1606 ::SelectObject(GetHdc(), hfontOld
);
1610 void wxDC::SetMapMode(int mode
)
1612 #ifdef __WXMICROWIN__
1613 if (!GetHDC()) return;
1616 m_mappingMode
= mode
;
1618 if ( mode
== wxMM_TEXT
)
1621 m_logicalScaleY
= 1.0;
1623 else // need to do some calculations
1625 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1626 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1627 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1628 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1630 if ( (mm_width
== 0) || (mm_height
== 0) )
1632 // we can't calculate mm2pixels[XY] then!
1636 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1637 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1642 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1643 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1647 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1648 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1652 m_logicalScaleX
= mm2pixelsX
;
1653 m_logicalScaleY
= mm2pixelsY
;
1657 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1658 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1662 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1666 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1667 // cases we could do with MM_TEXT and in the remaining 0.9% with
1668 // MM_ISOTROPIC (TODO!)
1670 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1672 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1673 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1675 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1676 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1678 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1679 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1683 void wxDC::SetUserScale(double x
, double y
)
1685 #ifdef __WXMICROWIN__
1686 if (!GetHDC()) return;
1690 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1696 SetMapMode(m_mappingMode
);
1700 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1702 #ifdef __WXMICROWIN__
1703 if (!GetHDC()) return;
1707 int signX
= xLeftRight
? 1 : -1,
1708 signY
= yBottomUp
? -1 : 1;
1710 if ( signX
!= m_signX
|| signY
!= m_signY
)
1715 SetMapMode(m_mappingMode
);
1720 void wxDC::SetSystemScale(double x
, double y
)
1722 #ifdef __WXMICROWIN__
1723 if (!GetHDC()) return;
1727 if ( x
== m_scaleX
&& y
== m_scaleY
)
1733 SetMapMode(m_mappingMode
);
1737 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1739 #ifdef __WXMICROWIN__
1740 if (!GetHDC()) return;
1744 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1747 m_logicalOriginX
= x
;
1748 m_logicalOriginY
= y
;
1750 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1754 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1756 #ifdef __WXMICROWIN__
1757 if (!GetHDC()) return;
1761 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1764 m_deviceOriginX
= x
;
1765 m_deviceOriginY
= y
;
1767 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1771 // ---------------------------------------------------------------------------
1772 // coordinates transformations
1773 // ---------------------------------------------------------------------------
1775 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1777 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1780 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1782 // axis orientation is not taken into account for conversion of a distance
1783 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1786 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1788 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1791 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1793 // axis orientation is not taken into account for conversion of a distance
1794 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1797 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1799 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1802 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1804 // axis orientation is not taken into account for conversion of a distance
1805 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1808 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1810 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1813 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1815 // axis orientation is not taken into account for conversion of a distance
1816 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1819 // ---------------------------------------------------------------------------
1821 // ---------------------------------------------------------------------------
1823 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1824 wxCoord width
, wxCoord height
,
1825 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1826 int rop
, bool useMask
,
1827 wxCoord xsrcMask
, wxCoord ysrcMask
)
1829 wxCHECK_MSG( source
, FALSE
, _T("wxDC::Blit(): NULL wxDC pointer") );
1831 #ifdef __WXMICROWIN__
1832 if (!GetHDC()) return FALSE
;
1835 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1836 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1838 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1839 GetHdcOf(*source
), bmpSrc
) )
1843 wxMask
*mask
= NULL
;
1846 mask
= bmpSrc
.GetMask();
1848 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1850 // don't give assert here because this would break existing
1851 // programs - just silently ignore useMask parameter
1856 if (xsrcMask
== -1 && ysrcMask
== -1)
1858 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1861 COLORREF old_textground
= ::GetTextColor(GetHdc());
1862 COLORREF old_background
= ::GetBkColor(GetHdc());
1863 if (m_textForegroundColour
.Ok())
1865 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1867 if (m_textBackgroundColour
.Ok())
1869 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1872 DWORD dwRop
= SRCCOPY
;
1875 case wxXOR
: dwRop
= SRCINVERT
; break;
1876 case wxINVERT
: dwRop
= DSTINVERT
; break;
1877 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1878 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1879 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1880 case wxSET
: dwRop
= WHITENESS
; break;
1881 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1882 case wxAND
: dwRop
= SRCAND
; break;
1883 case wxOR
: dwRop
= SRCPAINT
; break;
1884 case wxEQUIV
: dwRop
= 0x00990066; break;
1885 case wxNAND
: dwRop
= 0x007700E6; break;
1886 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1887 case wxCOPY
: dwRop
= SRCCOPY
; break;
1888 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1889 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1890 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1892 wxFAIL_MSG( wxT("unsupported logical function") );
1896 bool success
= FALSE
;
1901 // we want the part of the image corresponding to the mask to be
1902 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1903 // meaning of fg and bg is inverted which corresponds to wxWin notion
1904 // of the mask which is also contrary to the Windows one)
1906 // On some systems, MaskBlt succeeds yet is much much slower
1907 // than the wxWindows fall-back implementation. So we need
1908 // to be able to switch this on and off at runtime.
1909 #if wxUSE_SYSTEM_OPTIONS
1910 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1916 xdest
, ydest
, width
, height
,
1919 (HBITMAP
)mask
->GetMaskBitmap(),
1921 MAKEROP4(dwRop
, DSTCOPY
)
1928 // Blit bitmap with mask
1931 HBITMAP buffer_bmap
;
1933 #if wxUSE_DC_CACHEING
1934 // create a temp buffer bitmap and DCs to access it and the mask
1935 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1936 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1938 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1939 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1941 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1944 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1945 #else // !wxUSE_DC_CACHEING
1946 // create a temp buffer bitmap and DCs to access it and the mask
1947 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1948 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1949 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1950 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1951 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1952 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1954 // copy dest to buffer
1955 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1956 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1958 wxLogLastError(wxT("BitBlt"));
1961 // copy src to buffer using selected raster op
1962 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1963 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1965 wxLogLastError(wxT("BitBlt"));
1968 // set masked area in buffer to BLACK (pixel value 0)
1969 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1970 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1971 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1972 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1974 wxLogLastError(wxT("BitBlt"));
1977 // set unmasked area in dest to BLACK
1978 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1979 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1980 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1981 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1983 wxLogLastError(wxT("BitBlt"));
1985 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1986 ::SetTextColor(GetHdc(), prevCol
);
1988 // OR buffer to dest
1989 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1990 (int)width
, (int)height
,
1991 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1994 wxLogLastError(wxT("BitBlt"));
1997 // tidy up temporary DCs and bitmap
1998 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1999 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2001 #if !wxUSE_DC_CACHEING
2003 ::DeleteDC(dc_mask
);
2004 ::DeleteDC(dc_buffer
);
2005 ::DeleteObject(buffer_bmap
);
2010 else // no mask, just BitBlt() it
2012 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2013 // use StretchBlt() if available and finally fall back to BitBlt()
2015 // FIXME: use appropriate WinCE functions
2017 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2018 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2023 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2025 &ds
) == sizeof(ds
) )
2027 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2029 if ( ::StretchDIBits(GetHdc(),
2035 (LPBITMAPINFO
)&ds
.dsBmih
,
2038 ) == (int)GDI_ERROR
)
2040 wxLogLastError(wxT("StretchDIBits"));
2049 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2054 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2060 xdest
, ydest
, width
, height
,
2062 xsrc
, ysrc
, width
, height
,
2066 wxLogLastError(_T("StretchBlt"));
2080 (int)width
, (int)height
,
2086 wxLogLastError(_T("BitBlt"));
2095 ::SetTextColor(GetHdc(), old_textground
);
2096 ::SetBkColor(GetHdc(), old_background
);
2101 void wxDC::DoGetSize(int *w
, int *h
) const
2103 #ifdef __WXMICROWIN__
2104 if (!GetHDC()) return;
2107 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2108 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2111 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2113 #ifdef __WXMICROWIN__
2114 if (!GetHDC()) return;
2117 // if we implement it in terms of DoGetSize() instead of directly using the
2118 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2119 // will also work for wxWindowDC and wxClientDC even though their size is
2120 // not the same as the total size of the screen
2121 int wPixels
, hPixels
;
2122 DoGetSize(&wPixels
, &hPixels
);
2126 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2128 wxCHECK_RET( wTotal
, _T("0 width device?") );
2130 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2135 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2137 wxCHECK_RET( hTotal
, _T("0 height device?") );
2139 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2143 wxSize
wxDC::GetPPI() const
2145 #ifdef __WXMICROWIN__
2146 if (!GetHDC()) return wxSize();
2149 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2150 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2152 return wxSize(x
, y
);
2155 // For use by wxWindows only, unless custom units are required.
2156 void wxDC::SetLogicalScale(double x
, double y
)
2158 #ifdef __WXMICROWIN__
2159 if (!GetHDC()) return;
2162 m_logicalScaleX
= x
;
2163 m_logicalScaleY
= y
;
2166 // ----------------------------------------------------------------------------
2168 // ----------------------------------------------------------------------------
2170 #if wxUSE_DC_CACHEING
2173 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2174 * improve it in due course, either using arrays, or simply storing pointers to one
2175 * entry for the bitmap, and two for the DCs. -- JACS
2178 wxList
wxDC::sm_bitmapCache
;
2179 wxList
wxDC::sm_dcCache
;
2181 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2190 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2199 wxDCCacheEntry::~wxDCCacheEntry()
2202 ::DeleteObject((HBITMAP
) m_bitmap
);
2204 ::DeleteDC((HDC
) m_dc
);
2207 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2209 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2210 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2213 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2215 if (entry
->m_depth
== depth
)
2217 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2219 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2220 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2221 if ( !entry
->m_bitmap
)
2223 wxLogLastError(wxT("CreateCompatibleBitmap"));
2225 entry
->m_width
= w
; entry
->m_height
= h
;
2231 node
= node
->GetNext();
2233 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2236 wxLogLastError(wxT("CreateCompatibleBitmap"));
2238 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2239 AddToBitmapCache(entry
);
2243 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2245 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2246 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2249 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2251 // Don't return the same one as we already have
2252 if (!notThis
|| (notThis
!= entry
))
2254 if (entry
->m_depth
== depth
)
2260 node
= node
->GetNext();
2262 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2265 wxLogLastError(wxT("CreateCompatibleDC"));
2267 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2268 AddToDCCache(entry
);
2272 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2274 sm_bitmapCache
.Append(entry
);
2277 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2279 sm_dcCache
.Append(entry
);
2282 void wxDC::ClearCache()
2284 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2285 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2288 // Clean up cache at app exit
2289 class wxDCModule
: public wxModule
2292 virtual bool OnInit() { return TRUE
; }
2293 virtual void OnExit() { wxDC::ClearCache(); }
2296 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2299 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2301 #endif // wxUSE_DC_CACHEING
2303 // ----------------------------------------------------------------------------
2304 // alpha channel support
2305 // ----------------------------------------------------------------------------
2307 static bool AlphaBlt(HDC hdcDst
,
2308 int x
, int y
, int width
, int height
,
2310 const wxBitmap
& bmp
)
2312 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2313 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2315 // do we have AlphaBlend() and company in the headers?
2316 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2317 // yes, now try to see if we have it during run-time
2318 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2319 HDC
,int,int,int,int,
2322 // bitmaps can be drawn only from GUI thread so there is no need to
2323 // protect this static variable from multiple threads
2324 static bool s_triedToLoad
= FALSE
;
2325 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2326 if ( !s_triedToLoad
)
2328 s_triedToLoad
= TRUE
;
2330 // don't give errors about the DLL being unavailable, we're
2331 // prepared to handle this
2334 wxDynamicLibrary
dll(_T("msimg32.dll"));
2335 if ( dll
.IsLoaded() )
2337 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2338 if ( pfnAlphaBlend
)
2340 // we must keep the DLL loaded if we want to be able to
2341 // call AlphaBlend() so just never unload it at all, not a
2348 if ( pfnAlphaBlend
)
2351 bf
.BlendOp
= AC_SRC_OVER
;
2353 bf
.SourceConstantAlpha
= 0xff;
2354 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2356 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2357 hdcSrc
, 0, 0, width
, height
,
2360 // skip wxAlphaBlend() call below
2364 wxLogLastError(_T("AlphaBlend"));
2366 #endif // defined(AC_SRC_OVER)
2368 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2370 #ifdef wxHAVE_RAW_BITMAP
2371 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2374 #else // !wxHAVE_RAW_BITMAP
2375 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2376 // alpha but at least something will be shown like this)
2378 #endif // wxHAVE_RAW_BITMAP
2382 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2383 #ifdef wxHAVE_RAW_BITMAP
2386 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2388 // get the destination DC pixels
2389 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2391 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2393 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2395 wxLogLastError(_T("BitBlt"));
2398 // combine them with the source bitmap using alpha
2399 wxAlphaPixelData
dataDst(bmpDst
),
2400 dataSrc((wxBitmap
&)bmpSrc
);
2402 wxCHECK_RET( dataDst
&& dataSrc
,
2403 _T("failed to get raw data in wxAlphaBlend") );
2405 wxAlphaPixelData::Iterator
pDst(dataDst
),
2408 for ( int y
= 0; y
< h
; y
++ )
2410 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2411 pSrcRowStart
= pSrc
;
2413 for ( int x
= 0; x
< w
; x
++ )
2415 // note that source bitmap uses premultiplied alpha (as required by
2416 // the real AlphaBlend)
2417 const unsigned beta
= 255 - pSrc
.Alpha();
2419 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2420 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2421 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2427 pDst
= pDstRowStart
;
2428 pSrc
= pSrcRowStart
;
2429 pDst
.OffsetY(dataDst
, 1);
2430 pSrc
.OffsetY(dataSrc
, 1);
2433 // and finally blit them back to the destination DC
2434 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2436 wxLogLastError(_T("BitBlt"));
2440 #endif // #ifdef wxHAVE_RAW_BITMAP