1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
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/sysopt.h"
44 #include "wx/dcprint.h"
45 #include "wx/module.h"
46 #include "wx/dynload.h"
51 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
53 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
61 /* Quaternary raster codes */
63 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
66 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
68 // ---------------------------------------------------------------------------
70 // ---------------------------------------------------------------------------
72 static const int VIEWPORT_EXTENT
= 1000;
74 static const int MM_POINTS
= 9;
75 static const int MM_METRIC
= 10;
77 // usually this is defined in math.h
79 static const double M_PI
= 3.14159265358979323846;
82 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
83 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
84 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
86 // ----------------------------------------------------------------------------
87 // macros for logical <-> device coords conversion
88 // ----------------------------------------------------------------------------
91 We currently let Windows do all the translations itself so these macros are
92 not really needed (any more) but keep them to enhance readability of the
93 code by allowing to see where are the logical and where are the device
98 #define XLOG2DEV(x) (x)
99 #define YLOG2DEV(y) (y)
102 #define XDEV2LOG(x) (x)
103 #define YDEV2LOG(y) (y)
105 // ---------------------------------------------------------------------------
107 // ---------------------------------------------------------------------------
109 // convert degrees to radians
110 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
112 // ----------------------------------------------------------------------------
114 // ----------------------------------------------------------------------------
116 // instead of duplicating the same code which sets and then restores text
117 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
118 // encapsulate this in a small helper class
120 // wxColourChanger: changes the text colours in the ctor if required and
121 // restores them in the dtor
122 class wxColourChanger
125 wxColourChanger(wxDC
& dc
);
131 COLORREF m_colFgOld
, m_colBgOld
;
136 // this class saves the old stretch blit mode during its life time
137 class StretchBltModeChanger
140 StretchBltModeChanger(HDC hdc
, int mode
)
143 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
145 wxLogLastError(_T("SetStretchBltMode"));
148 ~StretchBltModeChanger()
150 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
151 wxLogLastError(_T("SetStretchBltMode"));
160 // ===========================================================================
162 // ===========================================================================
164 // ----------------------------------------------------------------------------
166 // ----------------------------------------------------------------------------
168 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
170 const wxBrush
& brush
= dc
.GetBrush();
171 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
173 HDC hdc
= GetHdcOf(dc
);
174 m_colFgOld
= ::GetTextColor(hdc
);
175 m_colBgOld
= ::GetBkColor(hdc
);
177 // note that Windows convention is opposite to wxWindows one, this is
178 // why text colour becomes the background one and vice versa
179 const wxColour
& colFg
= dc
.GetTextForeground();
182 ::SetBkColor(hdc
, colFg
.GetPixel());
185 const wxColour
& colBg
= dc
.GetTextBackground();
188 ::SetTextColor(hdc
, colBg
.GetPixel());
192 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
195 // flag which telsl us to undo changes in the dtor
200 // nothing done, nothing to undo
205 wxColourChanger::~wxColourChanger()
209 // restore the colours we changed
210 HDC hdc
= GetHdcOf(m_dc
);
212 ::SetBkMode(hdc
, TRANSPARENT
);
213 ::SetTextColor(hdc
, m_colFgOld
);
214 ::SetBkColor(hdc
, m_colBgOld
);
218 // ---------------------------------------------------------------------------
220 // ---------------------------------------------------------------------------
222 // Default constructor
233 #endif // wxUSE_PALETTE
243 SelectOldObjects(m_hDC
);
245 // if we own the HDC, we delete it, otherwise we just release it
249 ::DeleteDC(GetHdc());
251 else // we don't own our HDC
255 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
259 // Must have been a wxScreenDC
260 ::ReleaseDC((HWND
) NULL
, GetHdc());
266 // This will select current objects out of the DC,
267 // which is what you have to do before deleting the
269 void wxDC::SelectOldObjects(WXHDC dc
)
275 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
277 if (m_selectedBitmap
.Ok())
279 m_selectedBitmap
.SetSelectedInto(NULL
);
286 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
291 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
296 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
303 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
306 #endif // wxUSE_PALETTE
309 m_brush
= wxNullBrush
;
312 m_palette
= wxNullPalette
;
313 #endif // wxUSE_PALETTE
315 m_backgroundBrush
= wxNullBrush
;
316 m_selectedBitmap
= wxNullBitmap
;
319 // ---------------------------------------------------------------------------
321 // ---------------------------------------------------------------------------
323 void wxDC::UpdateClipBox()
325 #ifdef __WXMICROWIN__
326 if (!GetHDC()) return;
330 ::GetClipBox(GetHdc(), &rect
);
332 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
333 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
334 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
335 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
338 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
339 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
341 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
343 #ifdef __WXMICROWIN__
344 if (!GetHdc()) return;
345 #endif // __WXMICROWIN__
347 // note that we combine the new clipping region with the existing one: this
348 // is compatible with what the other ports do and is the documented
349 // behaviour now (starting with 2.3.3)
352 if ( !::GetClipBox(GetHdc(), &rectClip
) )
355 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
356 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
357 rectClip
.right
, rectClip
.bottom
);
359 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
361 ::SelectClipRgn(GetHdc(), hrgnDest
);
364 ::DeleteObject(hrgnClipOld
);
365 ::DeleteObject(hrgnDest
);
367 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
369 wxLogLastError(_T("ExtSelectClipRgn"));
380 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
382 // the region coords are always the device ones, so do the translation
385 // FIXME: possible +/-1 error here, to check!
386 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
388 LogicalToDeviceX(x
+ w
),
389 LogicalToDeviceY(y
+ h
));
392 wxLogLastError(_T("CreateRectRgn"));
396 SetClippingHrgn((WXHRGN
)hrgn
);
398 ::DeleteObject(hrgn
);
402 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
404 SetClippingHrgn(region
.GetHRGN());
407 void wxDC::DestroyClippingRegion()
409 #ifdef __WXMICROWIN__
410 if (!GetHDC()) return;
413 if (m_clipping
&& m_hDC
)
415 // TODO: this should restore the previous clipping region,
416 // so that OnPaint processing works correctly, and the update
417 // clipping region doesn't get destroyed after the first
418 // DestroyClippingRegion.
419 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
420 ::SelectClipRgn(GetHdc(), rgn
);
427 // ---------------------------------------------------------------------------
428 // query capabilities
429 // ---------------------------------------------------------------------------
431 bool wxDC::CanDrawBitmap() const
436 bool wxDC::CanGetTextExtent() const
438 #ifdef __WXMICROWIN__
439 // TODO Extend MicroWindows' GetDeviceCaps function
442 // What sort of display is it?
443 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
445 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
449 int wxDC::GetDepth() const
451 #ifdef __WXMICROWIN__
452 if (!GetHDC()) return 16;
455 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
458 // ---------------------------------------------------------------------------
460 // ---------------------------------------------------------------------------
464 #ifdef __WXMICROWIN__
465 if (!GetHDC()) return;
471 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
475 // No, I think we should simply ignore this if printing on e.g.
477 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
478 if (!m_selectedBitmap
.Ok())
481 rect
.left
= 0; rect
.top
= 0;
482 rect
.right
= m_selectedBitmap
.GetWidth();
483 rect
.bottom
= m_selectedBitmap
.GetHeight();
486 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
488 DWORD colour
= ::GetBkColor(GetHdc());
489 HBRUSH brush
= ::CreateSolidBrush(colour
);
490 ::FillRect(GetHdc(), &rect
, brush
);
491 ::DeleteObject(brush
);
493 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
494 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
496 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
497 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
498 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
499 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
500 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
503 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
505 #ifdef __WXMICROWIN__
506 if (!GetHDC()) return FALSE
;
509 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
511 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
512 : FLOODFILLBORDER
) ) ;
515 // quoting from the MSDN docs:
517 // Following are some of the reasons this function might fail:
519 // * The filling could not be completed.
520 // * The specified point has the boundary color specified by the
521 // crColor parameter (if FLOODFILLBORDER was requested).
522 // * The specified point does not have the color specified by
523 // crColor (if FLOODFILLSURFACE was requested)
524 // * The point is outside the clipping region that is, it is not
525 // visible on the device.
527 wxLogLastError(wxT("ExtFloodFill"));
530 CalcBoundingBox(x
, y
);
535 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
537 #ifdef __WXMICROWIN__
538 if (!GetHDC()) return FALSE
;
541 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
543 // get the color of the pixel
544 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
546 wxRGBToColour(*col
, pixelcolor
);
551 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
553 #ifdef __WXMICROWIN__
554 if (!GetHDC()) return;
557 wxCoord x1
= x
-VIEWPORT_EXTENT
;
558 wxCoord y1
= y
-VIEWPORT_EXTENT
;
559 wxCoord x2
= x
+VIEWPORT_EXTENT
;
560 wxCoord y2
= y
+VIEWPORT_EXTENT
;
562 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
563 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
565 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
566 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
568 CalcBoundingBox(x1
, y1
);
569 CalcBoundingBox(x2
, y2
);
572 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
574 #ifdef __WXMICROWIN__
575 if (!GetHDC()) return;
578 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
579 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
581 CalcBoundingBox(x1
, y1
);
582 CalcBoundingBox(x2
, y2
);
585 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
586 // and ending at (x2, y2)
587 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
588 wxCoord x2
, wxCoord y2
,
589 wxCoord xc
, wxCoord yc
)
591 #ifdef __WXMICROWIN__
592 if (!GetHDC()) return;
595 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
599 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
600 wxCoord r
= (wxCoord
)radius
;
602 // treat the special case of full circle separately
603 if ( x1
== x2
&& y1
== y2
)
605 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
609 wxCoord xx1
= XLOG2DEV(x1
);
610 wxCoord yy1
= YLOG2DEV(y1
);
611 wxCoord xx2
= XLOG2DEV(x2
);
612 wxCoord yy2
= YLOG2DEV(y2
);
613 wxCoord xxc
= XLOG2DEV(xc
);
614 wxCoord yyc
= YLOG2DEV(yc
);
615 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
617 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
618 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
619 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
620 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
622 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
624 // Have to add 1 to bottom-right corner of rectangle
625 // to make semi-circles look right (crooked line otherwise).
626 // Unfortunately this is not a reliable method, depends
627 // on the size of shape.
628 // TODO: figure out why this happens!
629 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
633 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
636 CalcBoundingBox(xc
- r
, yc
- r
);
637 CalcBoundingBox(xc
+ r
, yc
+ r
);
640 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
641 wxCoord width
, wxCoord height
)
643 #ifdef __WXMICROWIN__
644 if (!GetHDC()) return;
647 wxCoord x2
= x1
+ width
,
650 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__)
657 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
659 // In WIN16, draw a cross
660 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
661 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
662 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
663 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
664 ::SetROP2(GetHdc(), R2_COPYPEN
);
665 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
666 MoveToEx(GetHdc(), x1
, y1
, NULL
);
667 LineTo(GetHdc(), x2
, y2
);
668 MoveToEx(GetHdc(), x2
, y1
, NULL
);
669 LineTo(GetHdc(), x1
, y2
);
670 ::SelectObject(GetHdc(), hPenOld
);
671 ::SelectObject(GetHdc(), hBrushOld
);
672 ::DeleteObject(blackPen
);
675 CalcBoundingBox(x1
, y1
);
676 CalcBoundingBox(x2
, y2
);
679 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
681 #ifdef __WXMICROWIN__
682 if (!GetHDC()) return;
685 COLORREF color
= 0x00ffffff;
688 color
= m_pen
.GetColour().GetPixel();
691 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
693 CalcBoundingBox(x
, y
);
696 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
698 #ifdef __WXMICROWIN__
699 if (!GetHDC()) return;
702 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
704 // Do things less efficiently if we have offsets
705 if (xoffset
!= 0 || yoffset
!= 0)
707 POINT
*cpoints
= new POINT
[n
];
709 for (i
= 0; i
< n
; i
++)
711 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
712 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
714 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
716 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
717 (void)Polygon(GetHdc(), cpoints
, n
);
718 SetPolyFillMode(GetHdc(),prev
);
724 for (i
= 0; i
< n
; i
++)
725 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
727 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
728 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
729 SetPolyFillMode(GetHdc(),prev
);
733 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
735 #ifdef __WXMICROWIN__
736 if (!GetHDC()) return;
739 // Do things less efficiently if we have offsets
740 if (xoffset
!= 0 || yoffset
!= 0)
742 POINT
*cpoints
= new POINT
[n
];
744 for (i
= 0; i
< n
; i
++)
746 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
747 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
749 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
751 (void)Polyline(GetHdc(), cpoints
, n
);
757 for (i
= 0; i
< n
; i
++)
758 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
760 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
764 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
766 #ifdef __WXMICROWIN__
767 if (!GetHDC()) return;
770 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
772 wxCoord x2
= x
+ width
;
773 wxCoord y2
= y
+ height
;
775 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
778 rect
.left
= XLOG2DEV(x
);
779 rect
.top
= YLOG2DEV(y
);
780 rect
.right
= XLOG2DEV(x2
);
781 rect
.bottom
= YLOG2DEV(y2
);
782 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
786 // Windows draws the filled rectangles without outline (i.e. drawn with a
787 // transparent pen) one pixel smaller in both directions and we want them
788 // to have the same size regardless of which pen is used - adjust
790 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
791 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
797 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
801 CalcBoundingBox(x
, y
);
802 CalcBoundingBox(x2
, y2
);
805 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
807 #ifdef __WXMICROWIN__
808 if (!GetHDC()) return;
811 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
813 // Now, a negative radius value is interpreted to mean
814 // 'the proportion of the smallest X or Y dimension'
818 double smallest
= 0.0;
823 radius
= (- radius
* smallest
);
826 wxCoord x2
= (x
+width
);
827 wxCoord y2
= (y
+height
);
829 // Windows draws the filled rectangles without outline (i.e. drawn with a
830 // transparent pen) one pixel smaller in both directions and we want them
831 // to have the same size regardless of which pen is used - adjust
832 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
838 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
839 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
841 CalcBoundingBox(x
, y
);
842 CalcBoundingBox(x2
, y2
);
845 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
847 #ifdef __WXMICROWIN__
848 if (!GetHDC()) return;
851 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
853 wxCoord x2
= (x
+width
);
854 wxCoord y2
= (y
+height
);
856 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
858 CalcBoundingBox(x
, y
);
859 CalcBoundingBox(x2
, y2
);
862 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
863 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
865 #ifdef __WXMICROWIN__
866 if (!GetHDC()) return;
869 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
874 int rx1
= XLOG2DEV(x
+w
/2);
875 int ry1
= YLOG2DEV(y
+h
/2);
882 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
883 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
884 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
885 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
887 // draw pie with NULL_PEN first and then outline otherwise a line is
888 // drawn from the start and end points to the centre
889 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
892 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
897 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
898 rx1
, ry1
-1, rx2
, ry2
-1);
901 ::SelectObject(GetHdc(), hpenOld
);
903 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
906 CalcBoundingBox(x
, y
);
907 CalcBoundingBox(x2
, y2
);
910 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
912 #ifdef __WXMICROWIN__
913 if (!GetHDC()) return;
916 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
919 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
921 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
924 CalcBoundingBox(x
, y
);
925 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
928 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
930 #ifdef __WXMICROWIN__
931 if (!GetHDC()) return;
934 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
936 int width
= bmp
.GetWidth(),
937 height
= bmp
.GetHeight();
939 HBITMAP hbmpMask
= 0;
943 #endif // wxUSE_PALETTE
945 // do we have AlphaBlend() and company in the headers?
947 if ( bmp
.HasAlpha() )
949 // yes, now try to see if we have it during run-time
951 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
955 // bitmaps can be drawn only from GUI thread so there is no need to
956 // protect this static variable from multiple threads
957 static bool s_triedToLoad
= FALSE
;
958 static AlphaBlend_t pfnAlphaBlend
= NULL
;
959 if ( !s_triedToLoad
)
961 s_triedToLoad
= TRUE
;
963 wxDynamicLibrary
dll(_T("msimg32.dll"));
964 if ( dll
.IsLoaded() )
966 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
969 // we must keep the DLL loaded if we want to be able to
970 // call AlphaBlend() so just never unload it at all
979 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
982 #define AC_SRC_ALPHA 1
986 bf
.BlendOp
= AC_SRC_OVER
;
988 bf
.SourceConstantAlpha
= 0xff;
989 bf
.AlphaFormat
= AC_SRC_ALPHA
;
991 if ( !pfnAlphaBlend(GetHdc(), x
, y
, width
, height
,
992 hdcMem
, 0, 0, width
, height
,
995 wxLogLastError(_T("AlphaBlend"));
1000 //else: AlphaBlend() not available
1002 #endif // defined(AC_SRC_OVER)
1006 wxMask
*mask
= bmp
.GetMask();
1008 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1012 // don't give assert here because this would break existing
1013 // programs - just silently ignore useMask parameter
1020 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1022 // On some systems, MaskBlt succeeds yet is much much slower
1023 // than the wxWindows fall-back implementation. So we need
1024 // to be able to switch this on and off at runtime.
1026 #if wxUSE_SYSTEM_OPTIONS
1027 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1031 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1032 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1034 wxPalette
*pal
= bmp
.GetPalette();
1035 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1037 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1038 ::RealizePalette(hdcMem
);
1040 #endif // wxUSE_PALETTE
1042 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1045 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1049 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1050 #endif // wxUSE_PALETTE
1052 ::SelectObject(hdcMem
, hOldBitmap
);
1059 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1062 memDC
.SelectObject(bmp
);
1064 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1066 memDC
.SelectObject(wxNullBitmap
);
1069 else // no mask, just use BitBlt()
1072 HDC memdc
= ::CreateCompatibleDC( cdc
);
1073 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1075 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1077 COLORREF old_textground
= ::GetTextColor(GetHdc());
1078 COLORREF old_background
= ::GetBkColor(GetHdc());
1079 if (m_textForegroundColour
.Ok())
1081 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1083 if (m_textBackgroundColour
.Ok())
1085 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1089 wxPalette
*pal
= bmp
.GetPalette();
1090 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1092 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1093 ::RealizePalette(memdc
);
1095 #endif // wxUSE_PALETTE
1097 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1098 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1102 ::SelectPalette(memdc
, oldPal
, FALSE
);
1103 #endif // wxUSE_PALETTE
1105 ::SelectObject( memdc
, hOldBitmap
);
1106 ::DeleteDC( memdc
);
1108 ::SetTextColor(GetHdc(), old_textground
);
1109 ::SetBkColor(GetHdc(), old_background
);
1113 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1115 #ifdef __WXMICROWIN__
1116 if (!GetHDC()) return;
1119 DrawAnyText(text
, x
, y
);
1121 // update the bounding box
1122 CalcBoundingBox(x
, y
);
1125 GetTextExtent(text
, &w
, &h
);
1126 CalcBoundingBox(x
+ w
, y
+ h
);
1129 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1131 #ifdef __WXMICROWIN__
1132 if (!GetHDC()) return;
1135 // prepare for drawing the text
1136 if ( m_textForegroundColour
.Ok() )
1137 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1139 DWORD old_background
= 0;
1140 if ( m_textBackgroundColour
.Ok() )
1142 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1145 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1148 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1149 text
.c_str(), text
.length()) == 0 )
1151 wxLogLastError(wxT("TextOut"));
1154 // restore the old parameters (text foreground colour may be left because
1155 // it never is set to anything else, but background should remain
1156 // transparent even if we just drew an opaque string)
1157 if ( m_textBackgroundColour
.Ok() )
1158 (void)SetBkColor(GetHdc(), old_background
);
1160 SetBkMode(GetHdc(), TRANSPARENT
);
1163 void wxDC::DoDrawRotatedText(const wxString
& text
,
1164 wxCoord x
, wxCoord y
,
1167 #ifdef __WXMICROWIN__
1168 if (!GetHDC()) return;
1171 // we test that we have some font because otherwise we should still use the
1172 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1173 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1174 // font for drawing rotated fonts unfortunately)
1175 if ( (angle
== 0.0) && m_font
.Ok() )
1177 DoDrawText(text
, x
, y
);
1179 #ifndef __WXMICROWIN__
1182 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1183 // because it's not TrueType and so can't have non zero
1184 // orientation/escapement under Win9x
1185 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1186 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1188 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1190 wxLogLastError(wxT("GetObject(hfont)"));
1193 // GDI wants the angle in tenth of degree
1194 long angle10
= (long)(angle
* 10);
1195 lf
.lfEscapement
= angle10
;
1196 lf
. lfOrientation
= angle10
;
1198 hfont
= ::CreateFontIndirect(&lf
);
1201 wxLogLastError(wxT("CreateFont"));
1205 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1207 DrawAnyText(text
, x
, y
);
1209 (void)::SelectObject(GetHdc(), hfontOld
);
1210 (void)::DeleteObject(hfont
);
1213 // call the bounding box by adding all four vertices of the rectangle
1214 // containing the text to it (simpler and probably not slower than
1215 // determining which of them is really topmost/leftmost/...)
1217 GetTextExtent(text
, &w
, &h
);
1219 double rad
= DegToRad(angle
);
1221 // "upper left" and "upper right"
1222 CalcBoundingBox(x
, y
);
1223 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1225 // "bottom left" and "bottom right"
1226 x
+= (wxCoord
)(h
*sin(rad
));
1227 y
+= (wxCoord
)(h
*cos(rad
));
1228 CalcBoundingBox(x
, y
);
1229 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1234 // ---------------------------------------------------------------------------
1236 // ---------------------------------------------------------------------------
1240 void wxDC::DoSelectPalette(bool realize
)
1242 #ifdef __WXMICROWIN__
1243 if (!GetHDC()) return;
1246 // Set the old object temporarily, in case the assignment deletes an object
1247 // that's not yet selected out.
1250 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1254 if ( m_palette
.Ok() )
1256 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1257 GetHpaletteOf(m_palette
),
1260 m_oldPalette
= (WXHPALETTE
) oldPal
;
1263 ::RealizePalette(GetHdc());
1267 void wxDC::SetPalette(const wxPalette
& palette
)
1271 m_palette
= palette
;
1272 DoSelectPalette(TRUE
);
1276 void wxDC::InitializePalette()
1278 if ( wxDisplayDepth() <= 8 )
1280 // look for any window or parent that has a custom palette. If any has
1281 // one then we need to use it in drawing operations
1282 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1284 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1285 if ( m_hasCustomPalette
)
1287 m_palette
= win
->GetPalette();
1289 // turn on MSW translation for this palette
1295 #endif // wxUSE_PALETTE
1297 void wxDC::SetFont(const wxFont
& the_font
)
1299 #ifdef __WXMICROWIN__
1300 if (!GetHDC()) return;
1303 // Set the old object temporarily, in case the assignment deletes an object
1304 // that's not yet selected out.
1307 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1316 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1320 if (m_font
.Ok() && m_font
.GetResourceHandle())
1322 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1323 if (f
== (HFONT
) NULL
)
1325 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1328 m_oldFont
= (WXHFONT
) f
;
1332 void wxDC::SetPen(const wxPen
& pen
)
1334 #ifdef __WXMICROWIN__
1335 if (!GetHDC()) return;
1338 // Set the old object temporarily, in case the assignment deletes an object
1339 // that's not yet selected out.
1342 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1351 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1357 if (m_pen
.GetResourceHandle())
1359 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1361 m_oldPen
= (WXHPEN
) p
;
1366 void wxDC::SetBrush(const wxBrush
& brush
)
1368 #ifdef __WXMICROWIN__
1369 if (!GetHDC()) return;
1372 // Set the old object temporarily, in case the assignment deletes an object
1373 // that's not yet selected out.
1376 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1385 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1391 // to make sure the brush is alligned with the logical coordinates
1392 wxBitmap
*stipple
= m_brush
.GetStipple();
1393 if ( stipple
&& stipple
->Ok() )
1396 ::SetBrushOrgEx(GetHdc(),
1397 m_deviceOriginX
% stipple
->GetWidth(),
1398 m_deviceOriginY
% stipple
->GetHeight(),
1399 NULL
); // don't need previous brush origin
1401 ::SetBrushOrg(GetHdc(),
1402 m_deviceOriginX
% stipple
->GetWidth(),
1403 m_deviceOriginY
% stipple
->GetHeight());
1407 if ( m_brush
.GetResourceHandle() )
1410 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1412 m_oldBrush
= (WXHBRUSH
) b
;
1417 void wxDC::SetBackground(const wxBrush
& brush
)
1419 #ifdef __WXMICROWIN__
1420 if (!GetHDC()) return;
1423 m_backgroundBrush
= brush
;
1425 if (!m_backgroundBrush
.Ok())
1430 bool customColours
= TRUE
;
1431 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1432 // change background colours from the control-panel specified colours.
1433 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1434 customColours
= FALSE
;
1438 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1440 m_canvas
->SetTransparent(TRUE
);
1444 // New behaviour, 10/2/99: setting the background brush of a DC
1445 // doesn't affect the window background colour. However,
1446 // I'm leaving in the transparency setting because it's needed by
1447 // various controls (e.g. wxStaticText) to determine whether to draw
1448 // transparently or not. TODO: maybe this should be a new function
1449 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1451 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1452 m_canvas
->SetTransparent(FALSE
);
1456 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1458 (void)SetBkColor(GetHdc(), new_color
);
1462 void wxDC::SetBackgroundMode(int mode
)
1464 #ifdef __WXMICROWIN__
1465 if (!GetHDC()) return;
1468 m_backgroundMode
= mode
;
1470 // SetBackgroundColour now only refers to text background
1471 // and m_backgroundMode is used there
1474 void wxDC::SetLogicalFunction(int function
)
1476 #ifdef __WXMICROWIN__
1477 if (!GetHDC()) return;
1480 m_logicalFunction
= function
;
1485 void wxDC::SetRop(WXHDC dc
)
1487 if ( !dc
|| m_logicalFunction
< 0 )
1492 switch (m_logicalFunction
)
1494 case wxCLEAR
: rop
= R2_BLACK
; break;
1495 case wxXOR
: rop
= R2_XORPEN
; break;
1496 case wxINVERT
: rop
= R2_NOT
; break;
1497 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1498 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1499 case wxCOPY
: rop
= R2_COPYPEN
; break;
1500 case wxAND
: rop
= R2_MASKPEN
; break;
1501 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1502 case wxNO_OP
: rop
= R2_NOP
; break;
1503 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1504 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1505 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1506 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1507 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1508 case wxOR
: rop
= R2_MERGEPEN
; break;
1509 case wxSET
: rop
= R2_WHITE
; break;
1512 wxFAIL_MSG( wxT("unsupported logical function") );
1516 SetROP2(GetHdc(), rop
);
1519 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1521 // We might be previewing, so return TRUE to let it continue.
1529 void wxDC::StartPage()
1533 void wxDC::EndPage()
1537 // ---------------------------------------------------------------------------
1539 // ---------------------------------------------------------------------------
1541 wxCoord
wxDC::GetCharHeight() const
1543 #ifdef __WXMICROWIN__
1544 if (!GetHDC()) return 0;
1547 TEXTMETRIC lpTextMetric
;
1549 GetTextMetrics(GetHdc(), &lpTextMetric
);
1551 return lpTextMetric
.tmHeight
;
1554 wxCoord
wxDC::GetCharWidth() const
1556 #ifdef __WXMICROWIN__
1557 if (!GetHDC()) return 0;
1560 TEXTMETRIC lpTextMetric
;
1562 GetTextMetrics(GetHdc(), &lpTextMetric
);
1564 return lpTextMetric
.tmAveCharWidth
;
1567 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1568 wxCoord
*descent
, wxCoord
*externalLeading
,
1571 #ifdef __WXMICROWIN__
1576 if (descent
) *descent
= 0;
1577 if (externalLeading
) *externalLeading
= 0;
1580 #endif // __WXMICROWIN__
1585 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1587 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1589 else // don't change the font
1597 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1598 GetTextMetrics(GetHdc(), &tm
);
1605 *descent
= tm
.tmDescent
;
1606 if (externalLeading
)
1607 *externalLeading
= tm
.tmExternalLeading
;
1611 ::SelectObject(GetHdc(), hfontOld
);
1615 void wxDC::SetMapMode(int mode
)
1617 #ifdef __WXMICROWIN__
1618 if (!GetHDC()) return;
1621 m_mappingMode
= mode
;
1623 if ( mode
== wxMM_TEXT
)
1626 m_logicalScaleY
= 1.0;
1628 else // need to do some calculations
1630 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1631 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1632 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1633 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1635 if ( (mm_width
== 0) || (mm_height
== 0) )
1637 // we can't calculate mm2pixels[XY] then!
1641 double mm2pixelsX
= pixel_width
/ mm_width
,
1642 mm2pixelsY
= pixel_height
/ mm_height
;
1647 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1648 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1652 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1653 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1657 m_logicalScaleX
= mm2pixelsX
;
1658 m_logicalScaleY
= mm2pixelsY
;
1662 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1663 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1667 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1671 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1672 // cases we could do with MM_TEXT and in the remaining 0.9% with
1673 // MM_ISOTROPIC (TODO!)
1674 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1676 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1677 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1679 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1680 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1682 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1683 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1686 void wxDC::SetUserScale(double x
, double y
)
1688 #ifdef __WXMICROWIN__
1689 if (!GetHDC()) return;
1692 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1698 SetMapMode(m_mappingMode
);
1701 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1703 #ifdef __WXMICROWIN__
1704 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
);
1719 void wxDC::SetSystemScale(double x
, double y
)
1721 #ifdef __WXMICROWIN__
1722 if (!GetHDC()) return;
1725 if ( x
== m_scaleX
&& y
== m_scaleY
)
1731 SetMapMode(m_mappingMode
);
1734 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1736 #ifdef __WXMICROWIN__
1737 if (!GetHDC()) return;
1740 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1743 m_logicalOriginX
= x
;
1744 m_logicalOriginY
= y
;
1746 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1749 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1751 #ifdef __WXMICROWIN__
1752 if (!GetHDC()) return;
1755 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1758 m_deviceOriginX
= x
;
1759 m_deviceOriginY
= y
;
1761 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1764 // ---------------------------------------------------------------------------
1765 // coordinates transformations
1766 // ---------------------------------------------------------------------------
1768 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1770 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1773 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1775 // axis orientation is not taken into account for conversion of a distance
1776 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1779 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1781 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1784 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1786 // axis orientation is not taken into account for conversion of a distance
1787 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1790 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1792 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1795 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1797 // axis orientation is not taken into account for conversion of a distance
1798 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1801 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1803 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1806 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1808 // axis orientation is not taken into account for conversion of a distance
1809 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1812 // ---------------------------------------------------------------------------
1814 // ---------------------------------------------------------------------------
1816 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1817 wxCoord width
, wxCoord height
,
1818 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1819 int rop
, bool useMask
,
1820 wxCoord xsrcMask
, wxCoord ysrcMask
)
1822 #ifdef __WXMICROWIN__
1823 if (!GetHDC()) return FALSE
;
1826 wxMask
*mask
= NULL
;
1829 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1830 mask
= bmp
.GetMask();
1832 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1834 // don't give assert here because this would break existing
1835 // programs - just silently ignore useMask parameter
1840 if (xsrcMask
== -1 && ysrcMask
== -1)
1842 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1845 COLORREF old_textground
= ::GetTextColor(GetHdc());
1846 COLORREF old_background
= ::GetBkColor(GetHdc());
1847 if (m_textForegroundColour
.Ok())
1849 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1851 if (m_textBackgroundColour
.Ok())
1853 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1856 DWORD dwRop
= SRCCOPY
;
1859 case wxXOR
: dwRop
= SRCINVERT
; break;
1860 case wxINVERT
: dwRop
= DSTINVERT
; break;
1861 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1862 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1863 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1864 case wxSET
: dwRop
= WHITENESS
; break;
1865 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1866 case wxAND
: dwRop
= SRCAND
; break;
1867 case wxOR
: dwRop
= SRCPAINT
; break;
1868 case wxEQUIV
: dwRop
= 0x00990066; break;
1869 case wxNAND
: dwRop
= 0x007700E6; break;
1870 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1871 case wxCOPY
: dwRop
= SRCCOPY
; break;
1872 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1873 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1874 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1876 wxFAIL_MSG( wxT("unsupported logical function") );
1880 bool success
= FALSE
;
1885 // we want the part of the image corresponding to the mask to be
1886 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1887 // meaning of fg and bg is inverted which corresponds to wxWin notion
1888 // of the mask which is also contrary to the Windows one)
1890 // On some systems, MaskBlt succeeds yet is much much slower
1891 // than the wxWindows fall-back implementation. So we need
1892 // to be able to switch this on and off at runtime.
1893 #if wxUSE_SYSTEM_OPTIONS
1894 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1900 xdest
, ydest
, width
, height
,
1903 (HBITMAP
)mask
->GetMaskBitmap(),
1905 MAKEROP4(dwRop
, DSTCOPY
)
1912 // Blit bitmap with mask
1915 HBITMAP buffer_bmap
;
1917 #if wxUSE_DC_CACHEING
1918 // create a temp buffer bitmap and DCs to access it and the mask
1919 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1920 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1922 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1923 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1925 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1928 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1929 #else // !wxUSE_DC_CACHEING
1930 // create a temp buffer bitmap and DCs to access it and the mask
1931 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1932 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1933 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1934 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1935 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1936 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1938 // copy dest to buffer
1939 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1940 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1942 wxLogLastError(wxT("BitBlt"));
1945 // copy src to buffer using selected raster op
1946 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1947 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1949 wxLogLastError(wxT("BitBlt"));
1952 // set masked area in buffer to BLACK (pixel value 0)
1953 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1954 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1955 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1956 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1958 wxLogLastError(wxT("BitBlt"));
1961 // set unmasked area in dest to BLACK
1962 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1963 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1964 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1965 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1967 wxLogLastError(wxT("BitBlt"));
1969 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1970 ::SetTextColor(GetHdc(), prevCol
);
1972 // OR buffer to dest
1973 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1974 (int)width
, (int)height
,
1975 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1978 wxLogLastError(wxT("BitBlt"));
1981 // tidy up temporary DCs and bitmap
1982 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1983 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1985 #if !wxUSE_DC_CACHEING
1987 ::DeleteDC(dc_mask
);
1988 ::DeleteDC(dc_buffer
);
1989 ::DeleteObject(buffer_bmap
);
1994 else // no mask, just BitBlt() it
1996 // use StretchBlt() if available
1997 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS
) & RC_STRETCHBLT
)
1999 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2001 success
= ::StretchBlt
2004 xdest
, ydest
, width
, height
,
2006 xsrc
, ysrc
, width
, height
,
2016 (int)width
, (int)height
,
2025 wxLogLastError(wxT("BitBlt/StretchBlt"));
2029 ::SetTextColor(GetHdc(), old_textground
);
2030 ::SetBkColor(GetHdc(), old_background
);
2035 void wxDC::DoGetSize(int *w
, int *h
) const
2037 #ifdef __WXMICROWIN__
2038 if (!GetHDC()) return;
2041 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2042 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2045 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2047 #ifdef __WXMICROWIN__
2048 if (!GetHDC()) return;
2051 // if we implement it in terms of DoGetSize() instead of directly using the
2052 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2053 // will also work for wxWindowDC and wxClientDC even though their size is
2054 // not the same as the total size of the screen
2055 int wPixels
, hPixels
;
2056 DoGetSize(&wPixels
, &hPixels
);
2060 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2062 wxCHECK_RET( wTotal
, _T("0 width device?") );
2064 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2069 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2071 wxCHECK_RET( hTotal
, _T("0 height device?") );
2073 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2077 wxSize
wxDC::GetPPI() const
2079 #ifdef __WXMICROWIN__
2080 if (!GetHDC()) return wxSize();
2083 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2084 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2086 return wxSize(x
, y
);
2089 // For use by wxWindows only, unless custom units are required.
2090 void wxDC::SetLogicalScale(double x
, double y
)
2092 #ifdef __WXMICROWIN__
2093 if (!GetHDC()) return;
2096 m_logicalScaleX
= x
;
2097 m_logicalScaleY
= y
;
2100 #if wxUSE_DC_CACHEING
2103 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2104 * improve it in due course, either using arrays, or simply storing pointers to one
2105 * entry for the bitmap, and two for the DCs. -- JACS
2108 wxList
wxDC::sm_bitmapCache
;
2109 wxList
wxDC::sm_dcCache
;
2111 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2120 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2129 wxDCCacheEntry::~wxDCCacheEntry()
2132 ::DeleteObject((HBITMAP
) m_bitmap
);
2134 ::DeleteDC((HDC
) m_dc
);
2137 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2139 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2140 wxNode
* node
= sm_bitmapCache
.First();
2143 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2145 if (entry
->m_depth
== depth
)
2147 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2149 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2150 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2151 if ( !entry
->m_bitmap
)
2153 wxLogLastError(wxT("CreateCompatibleBitmap"));
2155 entry
->m_width
= w
; entry
->m_height
= h
;
2161 node
= node
->Next();
2163 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2166 wxLogLastError(wxT("CreateCompatibleBitmap"));
2168 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2169 AddToBitmapCache(entry
);
2173 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2175 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2176 wxNode
* node
= sm_dcCache
.First();
2179 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2181 // Don't return the same one as we already have
2182 if (!notThis
|| (notThis
!= entry
))
2184 if (entry
->m_depth
== depth
)
2190 node
= node
->Next();
2192 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2195 wxLogLastError(wxT("CreateCompatibleDC"));
2197 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2198 AddToDCCache(entry
);
2202 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2204 sm_bitmapCache
.Append(entry
);
2207 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2209 sm_dcCache
.Append(entry
);
2212 void wxDC::ClearCache()
2214 sm_dcCache
.DeleteContents(TRUE
);
2216 sm_dcCache
.DeleteContents(FALSE
);
2217 sm_bitmapCache
.DeleteContents(TRUE
);
2218 sm_bitmapCache
.Clear();
2219 sm_bitmapCache
.DeleteContents(FALSE
);
2222 // Clean up cache at app exit
2223 class wxDCModule
: public wxModule
2226 virtual bool OnInit() { return TRUE
; }
2227 virtual void OnExit() { wxDC::ClearCache(); }
2230 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2233 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2236 // wxUSE_DC_CACHEING