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/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 // don't give errors about the DLL being unavailable, we're
964 // prepared to handle this
967 wxDynamicLibrary
dll(_T("msimg32.dll"));
968 if ( dll
.IsLoaded() )
970 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
973 // we must keep the DLL loaded if we want to be able to
974 // call AlphaBlend() so just never unload it at all, not a
984 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
987 #define AC_SRC_ALPHA 1
991 bf
.BlendOp
= AC_SRC_OVER
;
993 bf
.SourceConstantAlpha
= 0xff;
994 bf
.AlphaFormat
= AC_SRC_ALPHA
;
996 if ( !pfnAlphaBlend(GetHdc(), x
, y
, width
, height
,
997 hdcMem
, 0, 0, width
, height
,
1000 wxLogLastError(_T("AlphaBlend"));
1005 //else: AlphaBlend() not available
1007 #endif // defined(AC_SRC_OVER)
1011 wxMask
*mask
= bmp
.GetMask();
1013 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1017 // don't give assert here because this would break existing
1018 // programs - just silently ignore useMask parameter
1025 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1027 // On some systems, MaskBlt succeeds yet is much much slower
1028 // than the wxWindows fall-back implementation. So we need
1029 // to be able to switch this on and off at runtime.
1031 #if wxUSE_SYSTEM_OPTIONS
1032 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1036 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1037 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1039 wxPalette
*pal
= bmp
.GetPalette();
1040 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1042 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1043 ::RealizePalette(hdcMem
);
1045 #endif // wxUSE_PALETTE
1047 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1050 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1054 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1055 #endif // wxUSE_PALETTE
1057 ::SelectObject(hdcMem
, hOldBitmap
);
1064 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1067 memDC
.SelectObject(bmp
);
1069 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1071 memDC
.SelectObject(wxNullBitmap
);
1074 else // no mask, just use BitBlt()
1077 HDC memdc
= ::CreateCompatibleDC( cdc
);
1078 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1080 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1082 COLORREF old_textground
= ::GetTextColor(GetHdc());
1083 COLORREF old_background
= ::GetBkColor(GetHdc());
1084 if (m_textForegroundColour
.Ok())
1086 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1088 if (m_textBackgroundColour
.Ok())
1090 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1094 wxPalette
*pal
= bmp
.GetPalette();
1095 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1097 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1098 ::RealizePalette(memdc
);
1100 #endif // wxUSE_PALETTE
1102 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1103 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1107 ::SelectPalette(memdc
, oldPal
, FALSE
);
1108 #endif // wxUSE_PALETTE
1110 ::SelectObject( memdc
, hOldBitmap
);
1111 ::DeleteDC( memdc
);
1113 ::SetTextColor(GetHdc(), old_textground
);
1114 ::SetBkColor(GetHdc(), old_background
);
1118 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1120 #ifdef __WXMICROWIN__
1121 if (!GetHDC()) return;
1124 DrawAnyText(text
, x
, y
);
1126 // update the bounding box
1127 CalcBoundingBox(x
, y
);
1130 GetTextExtent(text
, &w
, &h
);
1131 CalcBoundingBox(x
+ w
, y
+ h
);
1134 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1136 #ifdef __WXMICROWIN__
1137 if (!GetHDC()) return;
1140 // prepare for drawing the text
1141 if ( m_textForegroundColour
.Ok() )
1142 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1144 DWORD old_background
= 0;
1145 if ( m_textBackgroundColour
.Ok() )
1147 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1150 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1153 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1154 text
.c_str(), text
.length()) == 0 )
1156 wxLogLastError(wxT("TextOut"));
1159 // restore the old parameters (text foreground colour may be left because
1160 // it never is set to anything else, but background should remain
1161 // transparent even if we just drew an opaque string)
1162 if ( m_textBackgroundColour
.Ok() )
1163 (void)SetBkColor(GetHdc(), old_background
);
1165 SetBkMode(GetHdc(), TRANSPARENT
);
1168 void wxDC::DoDrawRotatedText(const wxString
& text
,
1169 wxCoord x
, wxCoord y
,
1172 #ifdef __WXMICROWIN__
1173 if (!GetHDC()) return;
1176 // we test that we have some font because otherwise we should still use the
1177 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1178 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1179 // font for drawing rotated fonts unfortunately)
1180 if ( (angle
== 0.0) && m_font
.Ok() )
1182 DoDrawText(text
, x
, y
);
1184 #ifndef __WXMICROWIN__
1187 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1188 // because it's not TrueType and so can't have non zero
1189 // orientation/escapement under Win9x
1190 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1191 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1193 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1195 wxLogLastError(wxT("GetObject(hfont)"));
1198 // GDI wants the angle in tenth of degree
1199 long angle10
= (long)(angle
* 10);
1200 lf
.lfEscapement
= angle10
;
1201 lf
. lfOrientation
= angle10
;
1203 hfont
= ::CreateFontIndirect(&lf
);
1206 wxLogLastError(wxT("CreateFont"));
1210 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1212 DrawAnyText(text
, x
, y
);
1214 (void)::SelectObject(GetHdc(), hfontOld
);
1215 (void)::DeleteObject(hfont
);
1218 // call the bounding box by adding all four vertices of the rectangle
1219 // containing the text to it (simpler and probably not slower than
1220 // determining which of them is really topmost/leftmost/...)
1222 GetTextExtent(text
, &w
, &h
);
1224 double rad
= DegToRad(angle
);
1226 // "upper left" and "upper right"
1227 CalcBoundingBox(x
, y
);
1228 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1230 // "bottom left" and "bottom right"
1231 x
+= (wxCoord
)(h
*sin(rad
));
1232 y
+= (wxCoord
)(h
*cos(rad
));
1233 CalcBoundingBox(x
, y
);
1234 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1239 // ---------------------------------------------------------------------------
1241 // ---------------------------------------------------------------------------
1245 void wxDC::DoSelectPalette(bool realize
)
1247 #ifdef __WXMICROWIN__
1248 if (!GetHDC()) return;
1251 // Set the old object temporarily, in case the assignment deletes an object
1252 // that's not yet selected out.
1255 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1259 if ( m_palette
.Ok() )
1261 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1262 GetHpaletteOf(m_palette
),
1265 m_oldPalette
= (WXHPALETTE
) oldPal
;
1268 ::RealizePalette(GetHdc());
1272 void wxDC::SetPalette(const wxPalette
& palette
)
1276 m_palette
= palette
;
1277 DoSelectPalette(TRUE
);
1281 void wxDC::InitializePalette()
1283 if ( wxDisplayDepth() <= 8 )
1285 // look for any window or parent that has a custom palette. If any has
1286 // one then we need to use it in drawing operations
1287 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1289 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1290 if ( m_hasCustomPalette
)
1292 m_palette
= win
->GetPalette();
1294 // turn on MSW translation for this palette
1300 #endif // wxUSE_PALETTE
1302 void wxDC::SetFont(const wxFont
& the_font
)
1304 #ifdef __WXMICROWIN__
1305 if (!GetHDC()) return;
1308 // Set the old object temporarily, in case the assignment deletes an object
1309 // that's not yet selected out.
1312 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1321 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1325 if (m_font
.Ok() && m_font
.GetResourceHandle())
1327 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1328 if (f
== (HFONT
) NULL
)
1330 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1333 m_oldFont
= (WXHFONT
) f
;
1337 void wxDC::SetPen(const wxPen
& pen
)
1339 #ifdef __WXMICROWIN__
1340 if (!GetHDC()) return;
1343 // Set the old object temporarily, in case the assignment deletes an object
1344 // that's not yet selected out.
1347 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1356 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1362 if (m_pen
.GetResourceHandle())
1364 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1366 m_oldPen
= (WXHPEN
) p
;
1371 void wxDC::SetBrush(const wxBrush
& brush
)
1373 #ifdef __WXMICROWIN__
1374 if (!GetHDC()) return;
1377 // Set the old object temporarily, in case the assignment deletes an object
1378 // that's not yet selected out.
1381 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1390 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1396 // to make sure the brush is alligned with the logical coordinates
1397 wxBitmap
*stipple
= m_brush
.GetStipple();
1398 if ( stipple
&& stipple
->Ok() )
1401 ::SetBrushOrgEx(GetHdc(),
1402 m_deviceOriginX
% stipple
->GetWidth(),
1403 m_deviceOriginY
% stipple
->GetHeight(),
1404 NULL
); // don't need previous brush origin
1406 ::SetBrushOrg(GetHdc(),
1407 m_deviceOriginX
% stipple
->GetWidth(),
1408 m_deviceOriginY
% stipple
->GetHeight());
1412 if ( m_brush
.GetResourceHandle() )
1415 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1417 m_oldBrush
= (WXHBRUSH
) b
;
1422 void wxDC::SetBackground(const wxBrush
& brush
)
1424 #ifdef __WXMICROWIN__
1425 if (!GetHDC()) return;
1428 m_backgroundBrush
= brush
;
1430 if (!m_backgroundBrush
.Ok())
1435 bool customColours
= TRUE
;
1436 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1437 // change background colours from the control-panel specified colours.
1438 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1439 customColours
= FALSE
;
1443 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1445 m_canvas
->SetTransparent(TRUE
);
1449 // New behaviour, 10/2/99: setting the background brush of a DC
1450 // doesn't affect the window background colour. However,
1451 // I'm leaving in the transparency setting because it's needed by
1452 // various controls (e.g. wxStaticText) to determine whether to draw
1453 // transparently or not. TODO: maybe this should be a new function
1454 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1456 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1457 m_canvas
->SetTransparent(FALSE
);
1461 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1463 (void)SetBkColor(GetHdc(), new_color
);
1467 void wxDC::SetBackgroundMode(int mode
)
1469 #ifdef __WXMICROWIN__
1470 if (!GetHDC()) return;
1473 m_backgroundMode
= mode
;
1475 // SetBackgroundColour now only refers to text background
1476 // and m_backgroundMode is used there
1479 void wxDC::SetLogicalFunction(int function
)
1481 #ifdef __WXMICROWIN__
1482 if (!GetHDC()) return;
1485 m_logicalFunction
= function
;
1490 void wxDC::SetRop(WXHDC dc
)
1492 if ( !dc
|| m_logicalFunction
< 0 )
1497 switch (m_logicalFunction
)
1499 case wxCLEAR
: rop
= R2_BLACK
; break;
1500 case wxXOR
: rop
= R2_XORPEN
; break;
1501 case wxINVERT
: rop
= R2_NOT
; break;
1502 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1503 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1504 case wxCOPY
: rop
= R2_COPYPEN
; break;
1505 case wxAND
: rop
= R2_MASKPEN
; break;
1506 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1507 case wxNO_OP
: rop
= R2_NOP
; break;
1508 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1509 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1510 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1511 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1512 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1513 case wxOR
: rop
= R2_MERGEPEN
; break;
1514 case wxSET
: rop
= R2_WHITE
; break;
1517 wxFAIL_MSG( wxT("unsupported logical function") );
1521 SetROP2(GetHdc(), rop
);
1524 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1526 // We might be previewing, so return TRUE to let it continue.
1534 void wxDC::StartPage()
1538 void wxDC::EndPage()
1542 // ---------------------------------------------------------------------------
1544 // ---------------------------------------------------------------------------
1546 wxCoord
wxDC::GetCharHeight() const
1548 #ifdef __WXMICROWIN__
1549 if (!GetHDC()) return 0;
1552 TEXTMETRIC lpTextMetric
;
1554 GetTextMetrics(GetHdc(), &lpTextMetric
);
1556 return lpTextMetric
.tmHeight
;
1559 wxCoord
wxDC::GetCharWidth() const
1561 #ifdef __WXMICROWIN__
1562 if (!GetHDC()) return 0;
1565 TEXTMETRIC lpTextMetric
;
1567 GetTextMetrics(GetHdc(), &lpTextMetric
);
1569 return lpTextMetric
.tmAveCharWidth
;
1572 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1573 wxCoord
*descent
, wxCoord
*externalLeading
,
1576 #ifdef __WXMICROWIN__
1581 if (descent
) *descent
= 0;
1582 if (externalLeading
) *externalLeading
= 0;
1585 #endif // __WXMICROWIN__
1590 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1592 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1594 else // don't change the font
1602 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1603 GetTextMetrics(GetHdc(), &tm
);
1610 *descent
= tm
.tmDescent
;
1611 if (externalLeading
)
1612 *externalLeading
= tm
.tmExternalLeading
;
1616 ::SelectObject(GetHdc(), hfontOld
);
1620 void wxDC::SetMapMode(int mode
)
1622 #ifdef __WXMICROWIN__
1623 if (!GetHDC()) return;
1626 m_mappingMode
= mode
;
1628 if ( mode
== wxMM_TEXT
)
1631 m_logicalScaleY
= 1.0;
1633 else // need to do some calculations
1635 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1636 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1637 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1638 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1640 if ( (mm_width
== 0) || (mm_height
== 0) )
1642 // we can't calculate mm2pixels[XY] then!
1646 double mm2pixelsX
= pixel_width
/ mm_width
,
1647 mm2pixelsY
= pixel_height
/ mm_height
;
1652 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1653 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1657 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1658 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1662 m_logicalScaleX
= mm2pixelsX
;
1663 m_logicalScaleY
= mm2pixelsY
;
1667 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1668 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1672 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1676 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1677 // cases we could do with MM_TEXT and in the remaining 0.9% with
1678 // MM_ISOTROPIC (TODO!)
1679 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1681 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1682 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1684 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1685 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1687 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1688 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1691 void wxDC::SetUserScale(double x
, double y
)
1693 #ifdef __WXMICROWIN__
1694 if (!GetHDC()) return;
1697 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1703 SetMapMode(m_mappingMode
);
1706 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1708 #ifdef __WXMICROWIN__
1709 if (!GetHDC()) return;
1712 int signX
= xLeftRight
? 1 : -1,
1713 signY
= yBottomUp
? -1 : 1;
1715 if ( signX
!= m_signX
|| signY
!= m_signY
)
1720 SetMapMode(m_mappingMode
);
1724 void wxDC::SetSystemScale(double x
, double y
)
1726 #ifdef __WXMICROWIN__
1727 if (!GetHDC()) return;
1730 if ( x
== m_scaleX
&& y
== m_scaleY
)
1736 SetMapMode(m_mappingMode
);
1739 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1741 #ifdef __WXMICROWIN__
1742 if (!GetHDC()) return;
1745 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1748 m_logicalOriginX
= x
;
1749 m_logicalOriginY
= y
;
1751 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1754 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1756 #ifdef __WXMICROWIN__
1757 if (!GetHDC()) return;
1760 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1763 m_deviceOriginX
= x
;
1764 m_deviceOriginY
= y
;
1766 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1769 // ---------------------------------------------------------------------------
1770 // coordinates transformations
1771 // ---------------------------------------------------------------------------
1773 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1775 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1778 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1780 // axis orientation is not taken into account for conversion of a distance
1781 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1784 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1786 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1789 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1791 // axis orientation is not taken into account for conversion of a distance
1792 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1795 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1797 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1800 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1802 // axis orientation is not taken into account for conversion of a distance
1803 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1806 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1808 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1811 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1813 // axis orientation is not taken into account for conversion of a distance
1814 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1817 // ---------------------------------------------------------------------------
1819 // ---------------------------------------------------------------------------
1821 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1822 wxCoord width
, wxCoord height
,
1823 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1824 int rop
, bool useMask
,
1825 wxCoord xsrcMask
, wxCoord ysrcMask
)
1827 #ifdef __WXMICROWIN__
1828 if (!GetHDC()) return FALSE
;
1831 wxMask
*mask
= NULL
;
1834 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1835 mask
= bmp
.GetMask();
1837 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1839 // don't give assert here because this would break existing
1840 // programs - just silently ignore useMask parameter
1845 if (xsrcMask
== -1 && ysrcMask
== -1)
1847 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1850 COLORREF old_textground
= ::GetTextColor(GetHdc());
1851 COLORREF old_background
= ::GetBkColor(GetHdc());
1852 if (m_textForegroundColour
.Ok())
1854 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1856 if (m_textBackgroundColour
.Ok())
1858 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1861 DWORD dwRop
= SRCCOPY
;
1864 case wxXOR
: dwRop
= SRCINVERT
; break;
1865 case wxINVERT
: dwRop
= DSTINVERT
; break;
1866 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1867 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1868 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1869 case wxSET
: dwRop
= WHITENESS
; break;
1870 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1871 case wxAND
: dwRop
= SRCAND
; break;
1872 case wxOR
: dwRop
= SRCPAINT
; break;
1873 case wxEQUIV
: dwRop
= 0x00990066; break;
1874 case wxNAND
: dwRop
= 0x007700E6; break;
1875 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1876 case wxCOPY
: dwRop
= SRCCOPY
; break;
1877 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1878 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1879 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1881 wxFAIL_MSG( wxT("unsupported logical function") );
1885 bool success
= FALSE
;
1890 // we want the part of the image corresponding to the mask to be
1891 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1892 // meaning of fg and bg is inverted which corresponds to wxWin notion
1893 // of the mask which is also contrary to the Windows one)
1895 // On some systems, MaskBlt succeeds yet is much much slower
1896 // than the wxWindows fall-back implementation. So we need
1897 // to be able to switch this on and off at runtime.
1898 #if wxUSE_SYSTEM_OPTIONS
1899 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1905 xdest
, ydest
, width
, height
,
1908 (HBITMAP
)mask
->GetMaskBitmap(),
1910 MAKEROP4(dwRop
, DSTCOPY
)
1917 // Blit bitmap with mask
1920 HBITMAP buffer_bmap
;
1922 #if wxUSE_DC_CACHEING
1923 // create a temp buffer bitmap and DCs to access it and the mask
1924 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1925 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1927 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1928 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1930 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1933 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1934 #else // !wxUSE_DC_CACHEING
1935 // create a temp buffer bitmap and DCs to access it and the mask
1936 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1937 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1938 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1939 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1940 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1941 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1943 // copy dest to buffer
1944 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1945 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1947 wxLogLastError(wxT("BitBlt"));
1950 // copy src to buffer using selected raster op
1951 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1952 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1954 wxLogLastError(wxT("BitBlt"));
1957 // set masked area in buffer to BLACK (pixel value 0)
1958 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1959 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1960 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1961 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1963 wxLogLastError(wxT("BitBlt"));
1966 // set unmasked area in dest to BLACK
1967 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1968 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1969 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1970 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1972 wxLogLastError(wxT("BitBlt"));
1974 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1975 ::SetTextColor(GetHdc(), prevCol
);
1977 // OR buffer to dest
1978 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1979 (int)width
, (int)height
,
1980 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1983 wxLogLastError(wxT("BitBlt"));
1986 // tidy up temporary DCs and bitmap
1987 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1988 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1990 #if !wxUSE_DC_CACHEING
1992 ::DeleteDC(dc_mask
);
1993 ::DeleteDC(dc_buffer
);
1994 ::DeleteObject(buffer_bmap
);
1999 else // no mask, just BitBlt() it
2001 // use StretchBlt() if available
2002 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS
) & RC_STRETCHBLT
)
2004 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2006 success
= ::StretchBlt
2009 xdest
, ydest
, width
, height
,
2011 xsrc
, ysrc
, width
, height
,
2021 (int)width
, (int)height
,
2030 wxLogLastError(wxT("BitBlt/StretchBlt"));
2034 ::SetTextColor(GetHdc(), old_textground
);
2035 ::SetBkColor(GetHdc(), old_background
);
2040 void wxDC::DoGetSize(int *w
, int *h
) const
2042 #ifdef __WXMICROWIN__
2043 if (!GetHDC()) return;
2046 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2047 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2050 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2052 #ifdef __WXMICROWIN__
2053 if (!GetHDC()) return;
2056 // if we implement it in terms of DoGetSize() instead of directly using the
2057 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2058 // will also work for wxWindowDC and wxClientDC even though their size is
2059 // not the same as the total size of the screen
2060 int wPixels
, hPixels
;
2061 DoGetSize(&wPixels
, &hPixels
);
2065 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2067 wxCHECK_RET( wTotal
, _T("0 width device?") );
2069 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2074 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2076 wxCHECK_RET( hTotal
, _T("0 height device?") );
2078 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2082 wxSize
wxDC::GetPPI() const
2084 #ifdef __WXMICROWIN__
2085 if (!GetHDC()) return wxSize();
2088 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2089 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2091 return wxSize(x
, y
);
2094 // For use by wxWindows only, unless custom units are required.
2095 void wxDC::SetLogicalScale(double x
, double y
)
2097 #ifdef __WXMICROWIN__
2098 if (!GetHDC()) return;
2101 m_logicalScaleX
= x
;
2102 m_logicalScaleY
= y
;
2105 #if wxUSE_DC_CACHEING
2108 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2109 * improve it in due course, either using arrays, or simply storing pointers to one
2110 * entry for the bitmap, and two for the DCs. -- JACS
2113 wxList
wxDC::sm_bitmapCache
;
2114 wxList
wxDC::sm_dcCache
;
2116 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2125 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2134 wxDCCacheEntry::~wxDCCacheEntry()
2137 ::DeleteObject((HBITMAP
) m_bitmap
);
2139 ::DeleteDC((HDC
) m_dc
);
2142 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2144 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2145 wxNode
* node
= sm_bitmapCache
.First();
2148 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2150 if (entry
->m_depth
== depth
)
2152 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2154 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2155 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2156 if ( !entry
->m_bitmap
)
2158 wxLogLastError(wxT("CreateCompatibleBitmap"));
2160 entry
->m_width
= w
; entry
->m_height
= h
;
2166 node
= node
->Next();
2168 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2171 wxLogLastError(wxT("CreateCompatibleBitmap"));
2173 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2174 AddToBitmapCache(entry
);
2178 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2180 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2181 wxNode
* node
= sm_dcCache
.First();
2184 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2186 // Don't return the same one as we already have
2187 if (!notThis
|| (notThis
!= entry
))
2189 if (entry
->m_depth
== depth
)
2195 node
= node
->Next();
2197 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2200 wxLogLastError(wxT("CreateCompatibleDC"));
2202 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2203 AddToDCCache(entry
);
2207 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2209 sm_bitmapCache
.Append(entry
);
2212 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2214 sm_dcCache
.Append(entry
);
2217 void wxDC::ClearCache()
2219 sm_dcCache
.DeleteContents(TRUE
);
2221 sm_dcCache
.DeleteContents(FALSE
);
2222 sm_bitmapCache
.DeleteContents(TRUE
);
2223 sm_bitmapCache
.Clear();
2224 sm_bitmapCache
.DeleteContents(FALSE
);
2227 // Clean up cache at app exit
2228 class wxDCModule
: public wxModule
2231 virtual bool OnInit() { return TRUE
; }
2232 virtual void OnExit() { wxDC::ClearCache(); }
2235 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2238 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2241 // wxUSE_DC_CACHEING