1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
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
;
163 // this class saves the old stretch blit mode during its life time
164 class StretchBltModeChanger
167 StretchBltModeChanger(HDC hdc
, int mode
)
171 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
173 wxLogLastError(_T("SetStretchBltMode"));
177 ~StretchBltModeChanger()
180 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
181 wxLogLastError(_T("SetStretchBltMode"));
191 // ===========================================================================
193 // ===========================================================================
195 // ----------------------------------------------------------------------------
197 // ----------------------------------------------------------------------------
199 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
201 const wxBrush
& brush
= dc
.GetBrush();
202 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
204 HDC hdc
= GetHdcOf(dc
);
205 m_colFgOld
= ::GetTextColor(hdc
);
206 m_colBgOld
= ::GetBkColor(hdc
);
208 // note that Windows convention is opposite to wxWindows one, this is
209 // why text colour becomes the background one and vice versa
210 const wxColour
& colFg
= dc
.GetTextForeground();
213 ::SetBkColor(hdc
, colFg
.GetPixel());
216 const wxColour
& colBg
= dc
.GetTextBackground();
219 ::SetTextColor(hdc
, colBg
.GetPixel());
223 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
226 // flag which telsl us to undo changes in the dtor
231 // nothing done, nothing to undo
236 wxColourChanger::~wxColourChanger()
240 // restore the colours we changed
241 HDC hdc
= GetHdcOf(m_dc
);
243 ::SetBkMode(hdc
, TRANSPARENT
);
244 ::SetTextColor(hdc
, m_colFgOld
);
245 ::SetBkColor(hdc
, m_colBgOld
);
249 // ---------------------------------------------------------------------------
251 // ---------------------------------------------------------------------------
253 // Default constructor
264 #endif // wxUSE_PALETTE
274 SelectOldObjects(m_hDC
);
276 // if we own the HDC, we delete it, otherwise we just release it
280 ::DeleteDC(GetHdc());
282 else // we don't own our HDC
286 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
290 // Must have been a wxScreenDC
291 ::ReleaseDC((HWND
) NULL
, GetHdc());
297 // This will select current objects out of the DC,
298 // which is what you have to do before deleting the
300 void wxDC::SelectOldObjects(WXHDC dc
)
306 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
308 if (m_selectedBitmap
.Ok())
310 m_selectedBitmap
.SetSelectedInto(NULL
);
317 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
322 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
327 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
334 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
337 #endif // wxUSE_PALETTE
340 m_brush
= wxNullBrush
;
343 m_palette
= wxNullPalette
;
344 #endif // wxUSE_PALETTE
346 m_backgroundBrush
= wxNullBrush
;
347 m_selectedBitmap
= wxNullBitmap
;
350 // ---------------------------------------------------------------------------
352 // ---------------------------------------------------------------------------
354 void wxDC::UpdateClipBox()
356 #ifdef __WXMICROWIN__
357 if (!GetHDC()) return;
361 ::GetClipBox(GetHdc(), &rect
);
363 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
364 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
365 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
366 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
369 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
370 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
372 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
374 #ifdef __WXMICROWIN__
375 if (!GetHdc()) return;
376 #endif // __WXMICROWIN__
378 // note that we combine the new clipping region with the existing one: this
379 // is compatible with what the other ports do and is the documented
380 // behaviour now (starting with 2.3.3)
381 #if defined(__WIN16__) || defined(__WXWINCE__)
383 if ( !::GetClipBox(GetHdc(), &rectClip
) )
386 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
387 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
388 rectClip
.right
, rectClip
.bottom
);
390 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
392 ::SelectClipRgn(GetHdc(), hrgnDest
);
395 ::DeleteObject(hrgnClipOld
);
396 ::DeleteObject(hrgnDest
);
398 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
400 wxLogLastError(_T("ExtSelectClipRgn"));
411 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
413 // the region coords are always the device ones, so do the translation
416 // FIXME: possible +/-1 error here, to check!
417 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
419 LogicalToDeviceX(x
+ w
),
420 LogicalToDeviceY(y
+ h
));
423 wxLogLastError(_T("CreateRectRgn"));
427 SetClippingHrgn((WXHRGN
)hrgn
);
429 ::DeleteObject(hrgn
);
433 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
435 SetClippingHrgn(region
.GetHRGN());
438 void wxDC::DestroyClippingRegion()
440 #ifdef __WXMICROWIN__
441 if (!GetHDC()) return;
444 if (m_clipping
&& m_hDC
)
446 // TODO: this should restore the previous clipping region,
447 // so that OnPaint processing works correctly, and the update
448 // clipping region doesn't get destroyed after the first
449 // DestroyClippingRegion.
450 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
451 ::SelectClipRgn(GetHdc(), rgn
);
458 // ---------------------------------------------------------------------------
459 // query capabilities
460 // ---------------------------------------------------------------------------
462 bool wxDC::CanDrawBitmap() const
467 bool wxDC::CanGetTextExtent() const
469 #ifdef __WXMICROWIN__
470 // TODO Extend MicroWindows' GetDeviceCaps function
473 // What sort of display is it?
474 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
476 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
480 int wxDC::GetDepth() const
482 #ifdef __WXMICROWIN__
483 if (!GetHDC()) return 16;
486 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
489 // ---------------------------------------------------------------------------
491 // ---------------------------------------------------------------------------
495 #ifdef __WXMICROWIN__
496 if (!GetHDC()) return;
502 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
506 // No, I think we should simply ignore this if printing on e.g.
508 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
509 if (!m_selectedBitmap
.Ok())
512 rect
.left
= 0; rect
.top
= 0;
513 rect
.right
= m_selectedBitmap
.GetWidth();
514 rect
.bottom
= m_selectedBitmap
.GetHeight();
518 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
521 DWORD colour
= ::GetBkColor(GetHdc());
522 HBRUSH brush
= ::CreateSolidBrush(colour
);
523 ::FillRect(GetHdc(), &rect
, brush
);
524 ::DeleteObject(brush
);
526 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
527 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
530 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
532 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
533 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
534 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
535 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
539 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
545 #ifdef __WXMICROWIN__
546 if (!GetHDC()) return FALSE
;
549 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
551 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
552 : FLOODFILLBORDER
) ) ;
555 // quoting from the MSDN docs:
557 // Following are some of the reasons this function might fail:
559 // * The filling could not be completed.
560 // * The specified point has the boundary color specified by the
561 // crColor parameter (if FLOODFILLBORDER was requested).
562 // * The specified point does not have the color specified by
563 // crColor (if FLOODFILLSURFACE was requested)
564 // * The point is outside the clipping region that is, it is not
565 // visible on the device.
567 wxLogLastError(wxT("ExtFloodFill"));
570 CalcBoundingBox(x
, y
);
576 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
578 #ifdef __WXMICROWIN__
579 if (!GetHDC()) return FALSE
;
582 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
584 // get the color of the pixel
585 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
587 wxRGBToColour(*col
, pixelcolor
);
592 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
594 #ifdef __WXMICROWIN__
595 if (!GetHDC()) return;
598 wxCoord x1
= x
-VIEWPORT_EXTENT
;
599 wxCoord y1
= y
-VIEWPORT_EXTENT
;
600 wxCoord x2
= x
+VIEWPORT_EXTENT
;
601 wxCoord y2
= y
+VIEWPORT_EXTENT
;
603 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
604 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
606 CalcBoundingBox(x1
, y1
);
607 CalcBoundingBox(x2
, y2
);
610 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
612 #ifdef __WXMICROWIN__
613 if (!GetHDC()) return;
616 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
618 CalcBoundingBox(x1
, y1
);
619 CalcBoundingBox(x2
, y2
);
622 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
623 // and ending at (x2, y2)
624 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
625 wxCoord x2
, wxCoord y2
,
626 wxCoord xc
, wxCoord yc
)
629 // FIXME: emulate Arc
632 #ifdef __WXMICROWIN__
633 if (!GetHDC()) return;
636 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
640 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
641 wxCoord r
= (wxCoord
)radius
;
643 // treat the special case of full circle separately
644 if ( x1
== x2
&& y1
== y2
)
646 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
650 wxCoord xx1
= XLOG2DEV(x1
);
651 wxCoord yy1
= YLOG2DEV(y1
);
652 wxCoord xx2
= XLOG2DEV(x2
);
653 wxCoord yy2
= YLOG2DEV(y2
);
654 wxCoord xxc
= XLOG2DEV(xc
);
655 wxCoord yyc
= YLOG2DEV(yc
);
656 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
658 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
659 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
660 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
661 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
663 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
665 // Have to add 1 to bottom-right corner of rectangle
666 // to make semi-circles look right (crooked line otherwise).
667 // Unfortunately this is not a reliable method, depends
668 // on the size of shape.
669 // TODO: figure out why this happens!
670 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
674 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
677 CalcBoundingBox(xc
- r
, yc
- r
);
678 CalcBoundingBox(xc
+ r
, yc
+ r
);
682 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
683 wxCoord width
, wxCoord height
)
685 #ifdef __WXMICROWIN__
686 if (!GetHDC()) return;
689 wxCoord x2
= x1
+ width
,
692 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
700 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
702 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
705 // In WIN16, draw a cross
706 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
707 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
708 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
709 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
710 ::SetROP2(GetHdc(), R2_COPYPEN
);
711 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
712 MoveToEx(GetHdc(), x1
, y1
, NULL
);
713 LineTo(GetHdc(), x2
, y2
);
714 MoveToEx(GetHdc(), x2
, y1
, NULL
);
715 LineTo(GetHdc(), x1
, y2
);
716 ::SelectObject(GetHdc(), hPenOld
);
717 ::SelectObject(GetHdc(), hBrushOld
);
718 ::DeleteObject(blackPen
);
721 CalcBoundingBox(x1
, y1
);
722 CalcBoundingBox(x2
, y2
);
725 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
727 #ifdef __WXMICROWIN__
728 if (!GetHDC()) return;
731 COLORREF color
= 0x00ffffff;
734 color
= m_pen
.GetColour().GetPixel();
737 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
739 CalcBoundingBox(x
, y
);
742 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
744 #ifdef __WXMICROWIN__
745 if (!GetHDC()) return;
748 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
750 // Do things less efficiently if we have offsets
751 if (xoffset
!= 0 || yoffset
!= 0)
753 POINT
*cpoints
= new POINT
[n
];
755 for (i
= 0; i
< n
; i
++)
757 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
758 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
760 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
763 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
765 (void)Polygon(GetHdc(), cpoints
, n
);
767 SetPolyFillMode(GetHdc(),prev
);
774 for (i
= 0; i
< n
; i
++)
775 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
778 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
780 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
782 SetPolyFillMode(GetHdc(),prev
);
787 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
789 #ifdef __WXMICROWIN__
790 if (!GetHDC()) return;
793 // Do things less efficiently if we have offsets
794 if (xoffset
!= 0 || yoffset
!= 0)
796 POINT
*cpoints
= new POINT
[n
];
798 for (i
= 0; i
< n
; i
++)
800 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
801 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
803 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
805 (void)Polyline(GetHdc(), cpoints
, n
);
811 for (i
= 0; i
< n
; i
++)
812 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
814 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
818 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
820 #ifdef __WXMICROWIN__
821 if (!GetHDC()) return;
824 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
826 wxCoord x2
= x
+ width
;
827 wxCoord y2
= y
+ height
;
829 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
832 rect
.left
= XLOG2DEV(x
);
833 rect
.top
= YLOG2DEV(y
);
834 rect
.right
= XLOG2DEV(x2
);
835 rect
.bottom
= YLOG2DEV(y2
);
836 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
840 // Windows draws the filled rectangles without outline (i.e. drawn with a
841 // transparent pen) one pixel smaller in both directions and we want them
842 // to have the same size regardless of which pen is used - adjust
844 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
845 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
851 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
855 CalcBoundingBox(x
, y
);
856 CalcBoundingBox(x2
, y2
);
859 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
861 #ifdef __WXMICROWIN__
862 if (!GetHDC()) return;
865 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
867 // Now, a negative radius value is interpreted to mean
868 // 'the proportion of the smallest X or Y dimension'
872 double smallest
= 0.0;
877 radius
= (- radius
* smallest
);
880 wxCoord x2
= (x
+width
);
881 wxCoord y2
= (y
+height
);
883 // Windows draws the filled rectangles without outline (i.e. drawn with a
884 // transparent pen) one pixel smaller in both directions and we want them
885 // to have the same size regardless of which pen is used - adjust
886 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
892 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
893 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
895 CalcBoundingBox(x
, y
);
896 CalcBoundingBox(x2
, y2
);
899 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
901 #ifdef __WXMICROWIN__
902 if (!GetHDC()) return;
905 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
907 wxCoord x2
= (x
+width
);
908 wxCoord y2
= (y
+height
);
910 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
912 CalcBoundingBox(x
, y
);
913 CalcBoundingBox(x2
, y2
);
916 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
917 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
923 #ifdef __WXMICROWIN__
924 if (!GetHDC()) return;
927 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
932 int rx1
= XLOG2DEV(x
+w
/2);
933 int ry1
= YLOG2DEV(y
+h
/2);
940 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
941 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
942 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
943 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
945 // draw pie with NULL_PEN first and then outline otherwise a line is
946 // drawn from the start and end points to the centre
947 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
950 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
955 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
956 rx1
, ry1
-1, rx2
, ry2
-1);
959 ::SelectObject(GetHdc(), hpenOld
);
961 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
964 CalcBoundingBox(x
, y
);
965 CalcBoundingBox(x2
, y2
);
969 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
971 #ifdef __WXMICROWIN__
972 if (!GetHDC()) return;
975 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
978 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
980 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
983 CalcBoundingBox(x
, y
);
984 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
987 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
989 #ifdef __WXMICROWIN__
990 if (!GetHDC()) return;
993 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
995 int width
= bmp
.GetWidth(),
996 height
= bmp
.GetHeight();
998 HBITMAP hbmpMask
= 0;
1001 HPALETTE oldPal
= 0;
1002 #endif // wxUSE_PALETTE
1004 if ( bmp
.HasAlpha() )
1007 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1009 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1015 wxMask
*mask
= bmp
.GetMask();
1017 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1021 // don't give assert here because this would break existing
1022 // programs - just silently ignore useMask parameter
1029 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1031 // On some systems, MaskBlt succeeds yet is much much slower
1032 // than the wxWindows fall-back implementation. So we need
1033 // to be able to switch this on and off at runtime.
1035 #if wxUSE_SYSTEM_OPTIONS
1036 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1040 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1041 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1043 wxPalette
*pal
= bmp
.GetPalette();
1044 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1046 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1047 ::RealizePalette(hdcMem
);
1049 #endif // wxUSE_PALETTE
1051 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1054 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1058 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1059 #endif // wxUSE_PALETTE
1061 ::SelectObject(hdcMem
, hOldBitmap
);
1068 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1071 memDC
.SelectObject(bmp
);
1073 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1075 memDC
.SelectObject(wxNullBitmap
);
1078 else // no mask, just use BitBlt()
1081 HDC memdc
= ::CreateCompatibleDC( cdc
);
1082 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1084 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1086 COLORREF old_textground
= ::GetTextColor(GetHdc());
1087 COLORREF old_background
= ::GetBkColor(GetHdc());
1088 if (m_textForegroundColour
.Ok())
1090 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1092 if (m_textBackgroundColour
.Ok())
1094 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1098 wxPalette
*pal
= bmp
.GetPalette();
1099 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1101 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1102 ::RealizePalette(memdc
);
1104 #endif // wxUSE_PALETTE
1106 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1107 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1111 ::SelectPalette(memdc
, oldPal
, FALSE
);
1112 #endif // wxUSE_PALETTE
1114 ::SelectObject( memdc
, hOldBitmap
);
1115 ::DeleteDC( memdc
);
1117 ::SetTextColor(GetHdc(), old_textground
);
1118 ::SetBkColor(GetHdc(), old_background
);
1122 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1124 #ifdef __WXMICROWIN__
1125 if (!GetHDC()) return;
1128 DrawAnyText(text
, x
, y
);
1130 // update the bounding box
1131 CalcBoundingBox(x
, y
);
1134 GetTextExtent(text
, &w
, &h
);
1135 CalcBoundingBox(x
+ w
, y
+ h
);
1138 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1140 #ifdef __WXMICROWIN__
1141 if (!GetHDC()) return;
1144 // prepare for drawing the text
1145 if ( m_textForegroundColour
.Ok() )
1146 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1148 DWORD old_background
= 0;
1149 if ( m_textBackgroundColour
.Ok() )
1151 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1154 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1158 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1159 text
.c_str(), text
.length(), NULL
) == 0 )
1161 wxLogLastError(wxT("TextOut"));
1164 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1165 text
.c_str(), text
.length()) == 0 )
1167 wxLogLastError(wxT("TextOut"));
1171 // restore the old parameters (text foreground colour may be left because
1172 // it never is set to anything else, but background should remain
1173 // transparent even if we just drew an opaque string)
1174 if ( m_textBackgroundColour
.Ok() )
1175 (void)SetBkColor(GetHdc(), old_background
);
1177 SetBkMode(GetHdc(), TRANSPARENT
);
1180 void wxDC::DoDrawRotatedText(const wxString
& text
,
1181 wxCoord x
, wxCoord y
,
1184 #ifdef __WXMICROWIN__
1185 if (!GetHDC()) return;
1188 // we test that we have some font because otherwise we should still use the
1189 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1190 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1191 // font for drawing rotated fonts unfortunately)
1192 if ( (angle
== 0.0) && m_font
.Ok() )
1194 DoDrawText(text
, x
, y
);
1196 #ifndef __WXMICROWIN__
1199 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1200 // because it's not TrueType and so can't have non zero
1201 // orientation/escapement under Win9x
1202 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1203 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1205 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1207 wxLogLastError(wxT("GetObject(hfont)"));
1210 // GDI wants the angle in tenth of degree
1211 long angle10
= (long)(angle
* 10);
1212 lf
.lfEscapement
= angle10
;
1213 lf
. lfOrientation
= angle10
;
1215 hfont
= ::CreateFontIndirect(&lf
);
1218 wxLogLastError(wxT("CreateFont"));
1222 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1224 DrawAnyText(text
, x
, y
);
1226 (void)::SelectObject(GetHdc(), hfontOld
);
1227 (void)::DeleteObject(hfont
);
1230 // call the bounding box by adding all four vertices of the rectangle
1231 // containing the text to it (simpler and probably not slower than
1232 // determining which of them is really topmost/leftmost/...)
1234 GetTextExtent(text
, &w
, &h
);
1236 double rad
= DegToRad(angle
);
1238 // "upper left" and "upper right"
1239 CalcBoundingBox(x
, y
);
1240 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1242 // "bottom left" and "bottom right"
1243 x
+= (wxCoord
)(h
*sin(rad
));
1244 y
+= (wxCoord
)(h
*cos(rad
));
1245 CalcBoundingBox(x
, y
);
1246 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1251 // ---------------------------------------------------------------------------
1253 // ---------------------------------------------------------------------------
1257 void wxDC::DoSelectPalette(bool realize
)
1259 #ifdef __WXMICROWIN__
1260 if (!GetHDC()) return;
1263 // Set the old object temporarily, in case the assignment deletes an object
1264 // that's not yet selected out.
1267 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1271 if ( m_palette
.Ok() )
1273 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1274 GetHpaletteOf(m_palette
),
1277 m_oldPalette
= (WXHPALETTE
) oldPal
;
1280 ::RealizePalette(GetHdc());
1284 void wxDC::SetPalette(const wxPalette
& palette
)
1288 m_palette
= palette
;
1289 DoSelectPalette(TRUE
);
1293 void wxDC::InitializePalette()
1295 if ( wxDisplayDepth() <= 8 )
1297 // look for any window or parent that has a custom palette. If any has
1298 // one then we need to use it in drawing operations
1299 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1301 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1302 if ( m_hasCustomPalette
)
1304 m_palette
= win
->GetPalette();
1306 // turn on MSW translation for this palette
1312 #endif // wxUSE_PALETTE
1314 void wxDC::SetFont(const wxFont
& the_font
)
1316 #ifdef __WXMICROWIN__
1317 if (!GetHDC()) return;
1320 // Set the old object temporarily, in case the assignment deletes an object
1321 // that's not yet selected out.
1324 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1333 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1337 if (m_font
.Ok() && m_font
.GetResourceHandle())
1339 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1340 if (f
== (HFONT
) NULL
)
1342 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1345 m_oldFont
= (WXHFONT
) f
;
1349 void wxDC::SetPen(const wxPen
& pen
)
1351 #ifdef __WXMICROWIN__
1352 if (!GetHDC()) return;
1355 // Set the old object temporarily, in case the assignment deletes an object
1356 // that's not yet selected out.
1359 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1368 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1374 if (m_pen
.GetResourceHandle())
1376 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1378 m_oldPen
= (WXHPEN
) p
;
1383 void wxDC::SetBrush(const wxBrush
& brush
)
1385 #ifdef __WXMICROWIN__
1386 if (!GetHDC()) return;
1389 // Set the old object temporarily, in case the assignment deletes an object
1390 // that's not yet selected out.
1393 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1402 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1408 // to make sure the brush is alligned with the logical coordinates
1409 wxBitmap
*stipple
= m_brush
.GetStipple();
1410 if ( stipple
&& stipple
->Ok() )
1413 ::SetBrushOrgEx(GetHdc(),
1414 m_deviceOriginX
% stipple
->GetWidth(),
1415 m_deviceOriginY
% stipple
->GetHeight(),
1416 NULL
); // don't need previous brush origin
1418 ::SetBrushOrg(GetHdc(),
1419 m_deviceOriginX
% stipple
->GetWidth(),
1420 m_deviceOriginY
% stipple
->GetHeight());
1424 if ( m_brush
.GetResourceHandle() )
1427 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1429 m_oldBrush
= (WXHBRUSH
) b
;
1434 void wxDC::SetBackground(const wxBrush
& brush
)
1436 #ifdef __WXMICROWIN__
1437 if (!GetHDC()) return;
1440 m_backgroundBrush
= brush
;
1442 if ( m_backgroundBrush
.Ok() )
1444 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1448 void wxDC::SetBackgroundMode(int mode
)
1450 #ifdef __WXMICROWIN__
1451 if (!GetHDC()) return;
1454 m_backgroundMode
= mode
;
1456 // SetBackgroundColour now only refers to text background
1457 // and m_backgroundMode is used there
1460 void wxDC::SetLogicalFunction(int function
)
1462 #ifdef __WXMICROWIN__
1463 if (!GetHDC()) return;
1466 m_logicalFunction
= function
;
1471 void wxDC::SetRop(WXHDC dc
)
1473 if ( !dc
|| m_logicalFunction
< 0 )
1478 switch (m_logicalFunction
)
1480 case wxCLEAR
: rop
= R2_BLACK
; break;
1481 case wxXOR
: rop
= R2_XORPEN
; break;
1482 case wxINVERT
: rop
= R2_NOT
; break;
1483 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1484 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1485 case wxCOPY
: rop
= R2_COPYPEN
; break;
1486 case wxAND
: rop
= R2_MASKPEN
; break;
1487 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1488 case wxNO_OP
: rop
= R2_NOP
; break;
1489 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1490 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1491 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1492 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1493 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1494 case wxOR
: rop
= R2_MERGEPEN
; break;
1495 case wxSET
: rop
= R2_WHITE
; break;
1498 wxFAIL_MSG( wxT("unsupported logical function") );
1502 SetROP2(GetHdc(), rop
);
1505 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1507 // We might be previewing, so return TRUE to let it continue.
1515 void wxDC::StartPage()
1519 void wxDC::EndPage()
1523 // ---------------------------------------------------------------------------
1525 // ---------------------------------------------------------------------------
1527 wxCoord
wxDC::GetCharHeight() const
1529 #ifdef __WXMICROWIN__
1530 if (!GetHDC()) return 0;
1533 TEXTMETRIC lpTextMetric
;
1535 GetTextMetrics(GetHdc(), &lpTextMetric
);
1537 return lpTextMetric
.tmHeight
;
1540 wxCoord
wxDC::GetCharWidth() const
1542 #ifdef __WXMICROWIN__
1543 if (!GetHDC()) return 0;
1546 TEXTMETRIC lpTextMetric
;
1548 GetTextMetrics(GetHdc(), &lpTextMetric
);
1550 return lpTextMetric
.tmAveCharWidth
;
1553 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1554 wxCoord
*descent
, wxCoord
*externalLeading
,
1557 #ifdef __WXMICROWIN__
1562 if (descent
) *descent
= 0;
1563 if (externalLeading
) *externalLeading
= 0;
1566 #endif // __WXMICROWIN__
1571 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1573 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1575 else // don't change the font
1583 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1584 GetTextMetrics(GetHdc(), &tm
);
1591 *descent
= tm
.tmDescent
;
1592 if (externalLeading
)
1593 *externalLeading
= tm
.tmExternalLeading
;
1597 ::SelectObject(GetHdc(), hfontOld
);
1601 void wxDC::SetMapMode(int mode
)
1603 #ifdef __WXMICROWIN__
1604 if (!GetHDC()) return;
1607 m_mappingMode
= mode
;
1609 if ( mode
== wxMM_TEXT
)
1612 m_logicalScaleY
= 1.0;
1614 else // need to do some calculations
1616 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1617 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1618 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1619 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1621 if ( (mm_width
== 0) || (mm_height
== 0) )
1623 // we can't calculate mm2pixels[XY] then!
1627 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1628 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1633 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1634 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1638 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1639 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1643 m_logicalScaleX
= mm2pixelsX
;
1644 m_logicalScaleY
= mm2pixelsY
;
1648 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1649 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1653 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1657 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1658 // cases we could do with MM_TEXT and in the remaining 0.9% with
1659 // MM_ISOTROPIC (TODO!)
1661 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1663 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1664 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1666 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1667 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1669 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1670 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1674 void wxDC::SetUserScale(double x
, double y
)
1676 #ifdef __WXMICROWIN__
1677 if (!GetHDC()) return;
1681 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1687 SetMapMode(m_mappingMode
);
1691 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1693 #ifdef __WXMICROWIN__
1694 if (!GetHDC()) return;
1698 int signX
= xLeftRight
? 1 : -1,
1699 signY
= yBottomUp
? -1 : 1;
1701 if ( signX
!= m_signX
|| signY
!= m_signY
)
1706 SetMapMode(m_mappingMode
);
1711 void wxDC::SetSystemScale(double x
, double y
)
1713 #ifdef __WXMICROWIN__
1714 if (!GetHDC()) return;
1718 if ( x
== m_scaleX
&& y
== m_scaleY
)
1724 SetMapMode(m_mappingMode
);
1728 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1730 #ifdef __WXMICROWIN__
1731 if (!GetHDC()) return;
1735 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1738 m_logicalOriginX
= x
;
1739 m_logicalOriginY
= y
;
1741 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1745 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1747 #ifdef __WXMICROWIN__
1748 if (!GetHDC()) return;
1752 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1755 m_deviceOriginX
= x
;
1756 m_deviceOriginY
= y
;
1758 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1762 // ---------------------------------------------------------------------------
1763 // coordinates transformations
1764 // ---------------------------------------------------------------------------
1766 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1768 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1771 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1773 // axis orientation is not taken into account for conversion of a distance
1774 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1777 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1779 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1782 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1784 // axis orientation is not taken into account for conversion of a distance
1785 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1788 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1790 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1793 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1795 // axis orientation is not taken into account for conversion of a distance
1796 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1799 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1801 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1804 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1806 // axis orientation is not taken into account for conversion of a distance
1807 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1810 // ---------------------------------------------------------------------------
1812 // ---------------------------------------------------------------------------
1814 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1815 wxCoord width
, wxCoord height
,
1816 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1817 int rop
, bool useMask
,
1818 wxCoord xsrcMask
, wxCoord ysrcMask
)
1820 wxCHECK_MSG( source
, FALSE
, _T("wxDC::Blit(): NULL wxDC pointer") );
1822 #ifdef __WXMICROWIN__
1823 if (!GetHDC()) return FALSE
;
1826 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1827 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1829 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1830 GetHdcOf(*source
), bmpSrc
) )
1834 wxMask
*mask
= NULL
;
1837 mask
= bmpSrc
.GetMask();
1839 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1841 // don't give assert here because this would break existing
1842 // programs - just silently ignore useMask parameter
1847 if (xsrcMask
== -1 && ysrcMask
== -1)
1849 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1852 COLORREF old_textground
= ::GetTextColor(GetHdc());
1853 COLORREF old_background
= ::GetBkColor(GetHdc());
1854 if (m_textForegroundColour
.Ok())
1856 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1858 if (m_textBackgroundColour
.Ok())
1860 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1863 DWORD dwRop
= SRCCOPY
;
1866 case wxXOR
: dwRop
= SRCINVERT
; break;
1867 case wxINVERT
: dwRop
= DSTINVERT
; break;
1868 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1869 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1870 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1871 case wxSET
: dwRop
= WHITENESS
; break;
1872 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1873 case wxAND
: dwRop
= SRCAND
; break;
1874 case wxOR
: dwRop
= SRCPAINT
; break;
1875 case wxEQUIV
: dwRop
= 0x00990066; break;
1876 case wxNAND
: dwRop
= 0x007700E6; break;
1877 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1878 case wxCOPY
: dwRop
= SRCCOPY
; break;
1879 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1880 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1881 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1883 wxFAIL_MSG( wxT("unsupported logical function") );
1887 bool success
= FALSE
;
1892 // we want the part of the image corresponding to the mask to be
1893 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1894 // meaning of fg and bg is inverted which corresponds to wxWin notion
1895 // of the mask which is also contrary to the Windows one)
1897 // On some systems, MaskBlt succeeds yet is much much slower
1898 // than the wxWindows fall-back implementation. So we need
1899 // to be able to switch this on and off at runtime.
1900 #if wxUSE_SYSTEM_OPTIONS
1901 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1907 xdest
, ydest
, width
, height
,
1910 (HBITMAP
)mask
->GetMaskBitmap(),
1912 MAKEROP4(dwRop
, DSTCOPY
)
1919 // Blit bitmap with mask
1922 HBITMAP buffer_bmap
;
1924 #if wxUSE_DC_CACHEING
1925 // create a temp buffer bitmap and DCs to access it and the mask
1926 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1927 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1929 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1930 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1932 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1935 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1936 #else // !wxUSE_DC_CACHEING
1937 // create a temp buffer bitmap and DCs to access it and the mask
1938 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1939 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1940 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1941 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1942 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1943 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1945 // copy dest to buffer
1946 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1947 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1949 wxLogLastError(wxT("BitBlt"));
1952 // copy src to buffer using selected raster op
1953 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1954 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1956 wxLogLastError(wxT("BitBlt"));
1959 // set masked area in buffer to BLACK (pixel value 0)
1960 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1961 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1962 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1963 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1965 wxLogLastError(wxT("BitBlt"));
1968 // set unmasked area in dest to BLACK
1969 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1970 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1971 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1972 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1974 wxLogLastError(wxT("BitBlt"));
1976 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1977 ::SetTextColor(GetHdc(), prevCol
);
1979 // OR buffer to dest
1980 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1981 (int)width
, (int)height
,
1982 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1985 wxLogLastError(wxT("BitBlt"));
1988 // tidy up temporary DCs and bitmap
1989 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1990 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1992 #if !wxUSE_DC_CACHEING
1994 ::DeleteDC(dc_mask
);
1995 ::DeleteDC(dc_buffer
);
1996 ::DeleteObject(buffer_bmap
);
2001 else // no mask, just BitBlt() it
2003 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2004 // use StretchBlt() if available and finally fall back to BitBlt()
2006 // FIXME: use appropriate WinCE functions
2008 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2009 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2014 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2016 &ds
) == sizeof(ds
) )
2018 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2020 if ( ::StretchDIBits(GetHdc(),
2026 (LPBITMAPINFO
)&ds
.dsBmih
,
2029 ) == (int)GDI_ERROR
)
2031 wxLogLastError(wxT("StretchDIBits"));
2040 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2042 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2047 xdest
, ydest
, width
, height
,
2049 xsrc
, ysrc
, width
, height
,
2053 wxLogLastError(_T("StretchBlt"));
2067 (int)width
, (int)height
,
2073 wxLogLastError(_T("BitBlt"));
2084 ::SetTextColor(GetHdc(), old_textground
);
2085 ::SetBkColor(GetHdc(), old_background
);
2090 void wxDC::DoGetSize(int *w
, int *h
) const
2092 #ifdef __WXMICROWIN__
2093 if (!GetHDC()) return;
2096 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2097 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2100 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2102 #ifdef __WXMICROWIN__
2103 if (!GetHDC()) return;
2106 // if we implement it in terms of DoGetSize() instead of directly using the
2107 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2108 // will also work for wxWindowDC and wxClientDC even though their size is
2109 // not the same as the total size of the screen
2110 int wPixels
, hPixels
;
2111 DoGetSize(&wPixels
, &hPixels
);
2115 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2117 wxCHECK_RET( wTotal
, _T("0 width device?") );
2119 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2124 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2126 wxCHECK_RET( hTotal
, _T("0 height device?") );
2128 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2132 wxSize
wxDC::GetPPI() const
2134 #ifdef __WXMICROWIN__
2135 if (!GetHDC()) return wxSize();
2138 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2139 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2141 return wxSize(x
, y
);
2144 // For use by wxWindows only, unless custom units are required.
2145 void wxDC::SetLogicalScale(double x
, double y
)
2147 #ifdef __WXMICROWIN__
2148 if (!GetHDC()) return;
2151 m_logicalScaleX
= x
;
2152 m_logicalScaleY
= y
;
2155 // ----------------------------------------------------------------------------
2157 // ----------------------------------------------------------------------------
2159 #if wxUSE_DC_CACHEING
2162 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2163 * improve it in due course, either using arrays, or simply storing pointers to one
2164 * entry for the bitmap, and two for the DCs. -- JACS
2167 wxList
wxDC::sm_bitmapCache
;
2168 wxList
wxDC::sm_dcCache
;
2170 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2179 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2188 wxDCCacheEntry::~wxDCCacheEntry()
2191 ::DeleteObject((HBITMAP
) m_bitmap
);
2193 ::DeleteDC((HDC
) m_dc
);
2196 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2198 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2199 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2202 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2204 if (entry
->m_depth
== depth
)
2206 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2208 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2209 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2210 if ( !entry
->m_bitmap
)
2212 wxLogLastError(wxT("CreateCompatibleBitmap"));
2214 entry
->m_width
= w
; entry
->m_height
= h
;
2220 node
= node
->GetNext();
2222 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2225 wxLogLastError(wxT("CreateCompatibleBitmap"));
2227 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2228 AddToBitmapCache(entry
);
2232 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2234 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2235 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2238 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2240 // Don't return the same one as we already have
2241 if (!notThis
|| (notThis
!= entry
))
2243 if (entry
->m_depth
== depth
)
2249 node
= node
->GetNext();
2251 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2254 wxLogLastError(wxT("CreateCompatibleDC"));
2256 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2257 AddToDCCache(entry
);
2261 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2263 sm_bitmapCache
.Append(entry
);
2266 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2268 sm_dcCache
.Append(entry
);
2271 void wxDC::ClearCache()
2273 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2274 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2277 // Clean up cache at app exit
2278 class wxDCModule
: public wxModule
2281 virtual bool OnInit() { return TRUE
; }
2282 virtual void OnExit() { wxDC::ClearCache(); }
2285 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2288 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2290 #endif // wxUSE_DC_CACHEING
2292 // ----------------------------------------------------------------------------
2293 // alpha channel support
2294 // ----------------------------------------------------------------------------
2296 static bool AlphaBlt(HDC hdcDst
,
2297 int x
, int y
, int width
, int height
,
2299 const wxBitmap
& bmp
)
2301 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2302 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2304 // do we have AlphaBlend() and company in the headers?
2305 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2306 // yes, now try to see if we have it during run-time
2307 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2308 HDC
,int,int,int,int,
2311 // bitmaps can be drawn only from GUI thread so there is no need to
2312 // protect this static variable from multiple threads
2313 static bool s_triedToLoad
= FALSE
;
2314 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2315 if ( !s_triedToLoad
)
2317 s_triedToLoad
= TRUE
;
2319 // don't give errors about the DLL being unavailable, we're
2320 // prepared to handle this
2323 wxDynamicLibrary
dll(_T("msimg32.dll"));
2324 if ( dll
.IsLoaded() )
2326 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2327 if ( pfnAlphaBlend
)
2329 // we must keep the DLL loaded if we want to be able to
2330 // call AlphaBlend() so just never unload it at all, not a
2337 if ( pfnAlphaBlend
)
2340 bf
.BlendOp
= AC_SRC_OVER
;
2342 bf
.SourceConstantAlpha
= 0xff;
2343 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2345 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2346 hdcSrc
, 0, 0, width
, height
,
2349 // skip wxAlphaBlend() call below
2353 wxLogLastError(_T("AlphaBlend"));
2355 #endif // defined(AC_SRC_OVER)
2357 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2359 #ifdef wxHAVE_RAW_BITMAP
2360 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2363 #else // !wxHAVE_RAW_BITMAP
2364 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2365 // alpha but at least something will be shown like this)
2367 #endif // wxHAVE_RAW_BITMAP
2371 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2372 #ifdef wxHAVE_RAW_BITMAP
2375 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2377 // get the destination DC pixels
2378 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2380 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2382 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2384 wxLogLastError(_T("BitBlt"));
2387 // combine them with the source bitmap using alpha
2388 wxAlphaPixelData
dataDst(bmpDst
),
2389 dataSrc((wxBitmap
&)bmpSrc
);
2391 wxCHECK_RET( dataDst
&& dataSrc
,
2392 _T("failed to get raw data in wxAlphaBlend") );
2394 wxAlphaPixelData::Iterator
pDst(dataDst
),
2397 for ( int y
= 0; y
< h
; y
++ )
2399 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2400 pSrcRowStart
= pSrc
;
2402 for ( int x
= 0; x
< w
; x
++ )
2404 // note that source bitmap uses premultiplied alpha (as required by
2405 // the real AlphaBlend)
2406 const unsigned beta
= 255 - pSrc
.Alpha();
2408 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2409 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2410 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2416 pDst
= pDstRowStart
;
2417 pSrc
= pSrcRowStart
;
2418 pDst
.OffsetY(dataDst
, 1);
2419 pSrc
.OffsetY(dataSrc
, 1);
2422 // and finally blit them back to the destination DC
2423 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2425 wxLogLastError(_T("BitBlt"));
2429 #endif // #ifdef wxHAVE_RAW_BITMAP