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"
50 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
52 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
62 // ---------------------------------------------------------------------------
64 // ---------------------------------------------------------------------------
66 static const int VIEWPORT_EXTENT
= 1000;
68 static const int MM_POINTS
= 9;
69 static const int MM_METRIC
= 10;
71 // usually this is defined in math.h
73 static const double M_PI
= 3.14159265358979323846;
76 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
77 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
78 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
80 // ----------------------------------------------------------------------------
81 // macros for logical <-> device coords conversion
82 // ----------------------------------------------------------------------------
85 We currently let Windows do all the translations itself so these macros are
86 not really needed (any more) but keep them to enhance readability of the
87 code by allowing to see where are the logical and where are the device
92 #define XLOG2DEV(x) (x)
93 #define YLOG2DEV(y) (y)
96 #define XDEV2LOG(x) (x)
97 #define YDEV2LOG(y) (y)
99 // ---------------------------------------------------------------------------
101 // ---------------------------------------------------------------------------
103 // convert degrees to radians
104 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
106 // ----------------------------------------------------------------------------
108 // ----------------------------------------------------------------------------
110 // instead of duplicating the same code which sets and then restores text
111 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
112 // encapsulate this in a small helper class
114 // wxColourChanger: changes the text colours in the ctor if required and
115 // restores them in the dtor
116 class wxColourChanger
119 wxColourChanger(wxDC
& dc
);
125 COLORREF m_colFgOld
, m_colBgOld
;
130 // ===========================================================================
132 // ===========================================================================
134 // ----------------------------------------------------------------------------
136 // ----------------------------------------------------------------------------
138 wxColourChanger
::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
140 if ( dc
.GetBrush().GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
142 HDC hdc
= GetHdcOf(dc
);
143 m_colFgOld
= ::GetTextColor(hdc
);
144 m_colBgOld
= ::GetBkColor(hdc
);
146 // note that Windows convention is opposite to wxWindows one, this is
147 // why text colour becomes the background one and vice versa
148 const wxColour
& colFg
= dc
.GetTextForeground();
151 ::SetBkColor(hdc
, colFg
.GetPixel());
154 const wxColour
& colBg
= dc
.GetTextBackground();
157 ::SetTextColor(hdc
, colBg
.GetPixel());
161 dc
.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
164 // flag which telsl us to undo changes in the dtor
169 // nothing done, nothing to undo
174 wxColourChanger
::~wxColourChanger()
178 // restore the colours we changed
179 HDC hdc
= GetHdcOf(m_dc
);
181 ::SetBkMode(hdc
, TRANSPARENT
);
182 ::SetTextColor(hdc
, m_colFgOld
);
183 ::SetBkColor(hdc
, m_colBgOld
);
187 // ---------------------------------------------------------------------------
189 // ---------------------------------------------------------------------------
191 // Default constructor
202 #endif // wxUSE_PALETTE
212 SelectOldObjects(m_hDC
);
214 // if we own the HDC, we delete it, otherwise we just release it
218 ::DeleteDC(GetHdc());
220 else // we don't own our HDC
224 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
228 // Must have been a wxScreenDC
229 ::ReleaseDC((HWND
) NULL
, GetHdc());
235 // This will select current objects out of the DC,
236 // which is what you have to do before deleting the
238 void wxDC
::SelectOldObjects(WXHDC dc
)
244 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
245 if (m_selectedBitmap
.Ok())
247 m_selectedBitmap
.SetSelectedInto(NULL
);
253 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
258 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
263 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
270 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
273 #endif // wxUSE_PALETTE
276 m_brush
= wxNullBrush
;
279 m_palette
= wxNullPalette
;
280 #endif // wxUSE_PALETTE
282 m_backgroundBrush
= wxNullBrush
;
283 m_selectedBitmap
= wxNullBitmap
;
286 // ---------------------------------------------------------------------------
288 // ---------------------------------------------------------------------------
290 void wxDC
::UpdateClipBox()
292 #ifdef __WXMICROWIN__
293 if (!GetHDC()) return;
297 ::GetClipBox(GetHdc(), &rect
);
299 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
300 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
301 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
302 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
305 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
306 void wxDC
::SetClippingHrgn(WXHRGN hrgn
)
308 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
310 #ifdef __WXMICROWIN__
311 if (!GetHdc()) return;
312 #endif // __WXMICROWIN__
314 // note that we combine the new clipping region with the existing one: this
315 // is compatible with what the other ports do and is the documented
316 // behaviour now (starting with 2.3.3)
319 if ( !::GetClipBox(GetHdc(), &rectClip
) )
322 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
323 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
324 rectClip
.right
, rectClip
.bottom
);
326 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
328 ::SelectClipRgn(GetHdc(), hrgnDest
);
331 ::DeleteObject(hrgnClipOld
);
332 ::DeleteObject(hrgnDest
);
334 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
336 wxLogLastError(_T("ExtSelectClipRgn"));
347 void wxDC
::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
349 // the region coords are always the device ones, so do the translation
352 // FIXME: possible +/-1 error here, to check!
353 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
355 LogicalToDeviceX(x
+ w
),
356 LogicalToDeviceY(y
+ h
));
359 wxLogLastError(_T("CreateRectRgn"));
363 SetClippingHrgn((WXHRGN
)hrgn
);
365 ::DeleteObject(hrgn
);
369 void wxDC
::DoSetClippingRegionAsRegion(const wxRegion
& region
)
371 SetClippingHrgn(region
.GetHRGN());
374 void wxDC
::DestroyClippingRegion()
376 #ifdef __WXMICROWIN__
377 if (!GetHDC()) return;
380 if (m_clipping
&& m_hDC
)
382 // TODO: this should restore the previous clipping region,
383 // so that OnPaint processing works correctly, and the update
384 // clipping region doesn't get destroyed after the first
385 // DestroyClippingRegion.
386 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
387 ::SelectClipRgn(GetHdc(), rgn
);
394 // ---------------------------------------------------------------------------
395 // query capabilities
396 // ---------------------------------------------------------------------------
398 bool wxDC
::CanDrawBitmap() const
403 bool wxDC
::CanGetTextExtent() const
405 #ifdef __WXMICROWIN__
406 // TODO Extend MicroWindows' GetDeviceCaps function
409 // What sort of display is it?
410 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
412 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
416 int wxDC
::GetDepth() const
418 #ifdef __WXMICROWIN__
419 if (!GetHDC()) return 16;
422 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
425 // ---------------------------------------------------------------------------
427 // ---------------------------------------------------------------------------
431 #ifdef __WXMICROWIN__
432 if (!GetHDC()) return;
438 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
442 // No, I think we should simply ignore this if printing on e.g.
444 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
445 if (!m_selectedBitmap
.Ok())
448 rect
.left
= 0; rect
.top
= 0;
449 rect
.right
= m_selectedBitmap
.GetWidth();
450 rect
.bottom
= m_selectedBitmap
.GetHeight();
453 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
455 DWORD colour
= ::GetBkColor(GetHdc());
456 HBRUSH brush
= ::CreateSolidBrush(colour
);
457 ::FillRect(GetHdc(), &rect
, brush
);
458 ::DeleteObject(brush
);
460 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
461 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
463 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
464 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
465 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
466 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
467 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
470 void wxDC
::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
472 #ifdef __WXMICROWIN__
473 if (!GetHDC()) return;
476 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
478 style
== wxFLOOD_SURFACE ? FLOODFILLSURFACE
481 // quoting from the MSDN docs:
483 // Following are some of the reasons this function might fail:
485 // * The filling could not be completed.
486 // * The specified point has the boundary color specified by the
487 // crColor parameter (if FLOODFILLBORDER was requested).
488 // * The specified point does not have the color specified by
489 // crColor (if FLOODFILLSURFACE was requested)
490 // * The point is outside the clipping region that is, it is not
491 // visible on the device.
493 wxLogLastError(wxT("ExtFloodFill"));
496 CalcBoundingBox(x
, y
);
499 bool wxDC
::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
501 #ifdef __WXMICROWIN__
502 if (!GetHDC()) return FALSE
;
505 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
507 // get the color of the pixel
508 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
510 wxRGBToColour(*col
, pixelcolor
);
515 void wxDC
::DoCrossHair(wxCoord x
, wxCoord y
)
517 #ifdef __WXMICROWIN__
518 if (!GetHDC()) return;
521 wxCoord x1
= x
-VIEWPORT_EXTENT
;
522 wxCoord y1
= y
-VIEWPORT_EXTENT
;
523 wxCoord x2
= x
+VIEWPORT_EXTENT
;
524 wxCoord y2
= y
+VIEWPORT_EXTENT
;
526 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
527 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
529 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
530 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
532 CalcBoundingBox(x1
, y1
);
533 CalcBoundingBox(x2
, y2
);
536 void wxDC
::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
538 #ifdef __WXMICROWIN__
539 if (!GetHDC()) return;
542 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
543 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
545 CalcBoundingBox(x1
, y1
);
546 CalcBoundingBox(x2
, y2
);
549 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
550 // and ending at (x2, y2)
551 void wxDC
::DoDrawArc(wxCoord x1
, wxCoord y1
,
552 wxCoord x2
, wxCoord y2
,
553 wxCoord xc
, wxCoord yc
)
555 #ifdef __WXMICROWIN__
556 if (!GetHDC()) return;
559 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
563 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
564 wxCoord r
= (wxCoord
)radius
;
566 // treat the special case of full circle separately
567 if ( x1
== x2
&& y1
== y2
)
569 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
573 wxCoord xx1
= XLOG2DEV(x1
);
574 wxCoord yy1
= YLOG2DEV(y1
);
575 wxCoord xx2
= XLOG2DEV(x2
);
576 wxCoord yy2
= YLOG2DEV(y2
);
577 wxCoord xxc
= XLOG2DEV(xc
);
578 wxCoord yyc
= YLOG2DEV(yc
);
579 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
581 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
582 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
583 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
584 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
586 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
588 // Have to add 1 to bottom-right corner of rectangle
589 // to make semi-circles look right (crooked line otherwise).
590 // Unfortunately this is not a reliable method, depends
591 // on the size of shape.
592 // TODO: figure out why this happens!
593 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
597 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
600 CalcBoundingBox(xc
- r
, yc
- r
);
601 CalcBoundingBox(xc
+ r
, yc
+ r
);
604 void wxDC
::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
605 wxCoord width
, wxCoord height
)
607 #ifdef __WXMICROWIN__
608 if (!GetHDC()) return;
611 wxCoord x2
= x1
+ width
,
614 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__)
621 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
623 // In WIN16, draw a cross
624 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
625 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
626 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
627 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
628 ::SetROP2(GetHdc(), R2_COPYPEN
);
629 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
630 MoveToEx(GetHdc(), x1
, y1
, NULL
);
631 LineTo(GetHdc(), x2
, y2
);
632 MoveToEx(GetHdc(), x2
, y1
, NULL
);
633 LineTo(GetHdc(), x1
, y2
);
634 ::SelectObject(GetHdc(), hPenOld
);
635 ::SelectObject(GetHdc(), hBrushOld
);
636 ::DeleteObject(blackPen
);
639 CalcBoundingBox(x1
, y1
);
640 CalcBoundingBox(x2
, y2
);
643 void wxDC
::DoDrawPoint(wxCoord x
, wxCoord y
)
645 #ifdef __WXMICROWIN__
646 if (!GetHDC()) return;
649 COLORREF color
= 0x00ffffff;
652 color
= m_pen
.GetColour().GetPixel();
655 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
657 CalcBoundingBox(x
, y
);
660 void wxDC
::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
662 #ifdef __WXMICROWIN__
663 if (!GetHDC()) return;
666 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
668 // Do things less efficiently if we have offsets
669 if (xoffset
!= 0 || yoffset
!= 0)
671 POINT
*cpoints
= new POINT
[n
];
673 for (i
= 0; i
< n
; i
++)
675 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
676 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
678 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
680 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE?ALTERNATE
:WINDING
);
681 (void)Polygon(GetHdc(), cpoints
, n
);
682 SetPolyFillMode(GetHdc(),prev
);
688 for (i
= 0; i
< n
; i
++)
689 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
691 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE?ALTERNATE
:WINDING
);
692 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
693 SetPolyFillMode(GetHdc(),prev
);
697 void wxDC
::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
699 #ifdef __WXMICROWIN__
700 if (!GetHDC()) return;
703 // Do things less efficiently if we have offsets
704 if (xoffset
!= 0 || yoffset
!= 0)
706 POINT
*cpoints
= new POINT
[n
];
708 for (i
= 0; i
< n
; i
++)
710 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
711 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
713 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
715 (void)Polyline(GetHdc(), cpoints
, n
);
721 for (i
= 0; i
< n
; i
++)
722 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
724 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
728 void wxDC
::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
730 #ifdef __WXMICROWIN__
731 if (!GetHDC()) return;
734 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
736 wxCoord x2
= x
+ width
;
737 wxCoord y2
= y
+ height
;
739 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
742 rect
.left
= XLOG2DEV(x
);
743 rect
.top
= YLOG2DEV(y
);
744 rect
.right
= XLOG2DEV(x2
);
745 rect
.bottom
= YLOG2DEV(y2
);
746 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
750 // Windows draws the filled rectangles without outline (i.e. drawn with a
751 // transparent pen) one pixel smaller in both directions and we want them
752 // to have the same size regardless of which pen is used - adjust
754 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
755 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
761 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
765 CalcBoundingBox(x
, y
);
766 CalcBoundingBox(x2
, y2
);
769 void wxDC
::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
771 #ifdef __WXMICROWIN__
772 if (!GetHDC()) return;
775 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
777 // Now, a negative radius value is interpreted to mean
778 // 'the proportion of the smallest X or Y dimension'
782 double smallest
= 0.0;
787 radius
= (- radius
* smallest
);
790 wxCoord x2
= (x
+width
);
791 wxCoord y2
= (y
+height
);
793 // Windows draws the filled rectangles without outline (i.e. drawn with a
794 // transparent pen) one pixel smaller in both directions and we want them
795 // to have the same size regardless of which pen is used - adjust
796 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
802 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
803 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
805 CalcBoundingBox(x
, y
);
806 CalcBoundingBox(x2
, y2
);
809 void wxDC
::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
811 #ifdef __WXMICROWIN__
812 if (!GetHDC()) return;
815 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
817 wxCoord x2
= (x
+width
);
818 wxCoord y2
= (y
+height
);
820 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
822 CalcBoundingBox(x
, y
);
823 CalcBoundingBox(x2
, y2
);
826 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
827 void wxDC
::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
829 #ifdef __WXMICROWIN__
830 if (!GetHDC()) return;
833 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
838 int rx1
= XLOG2DEV(x
+w
/2);
839 int ry1
= YLOG2DEV(y
+h
/2);
846 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
847 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
848 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
849 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
851 // draw pie with NULL_PEN first and then outline otherwise a line is
852 // drawn from the start and end points to the centre
853 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
856 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
861 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
862 rx1
, ry1
-1, rx2
, ry2
-1);
865 ::SelectObject(GetHdc(), hpenOld
);
867 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
870 CalcBoundingBox(x
, y
);
871 CalcBoundingBox(x2
, y2
);
874 void wxDC
::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
876 #ifdef __WXMICROWIN__
877 if (!GetHDC()) return;
880 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
883 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
885 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
888 CalcBoundingBox(x
, y
);
889 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
892 void wxDC
::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
894 #ifdef __WXMICROWIN__
895 if (!GetHDC()) return;
898 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
900 int width
= bmp
.GetWidth(),
901 height
= bmp
.GetHeight();
903 HBITMAP hbmpMask
= 0;
907 #endif // wxUSE_PALETTE
911 wxMask
*mask
= bmp
.GetMask();
913 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
917 // don't give assert here because this would break existing
918 // programs - just silently ignore useMask parameter
925 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
927 // On some systems, MaskBlt succeeds yet is much much slower
928 // than the wxWindows fall-back implementation. So we need
929 // to be able to switch this on and off at runtime.
931 #if wxUSE_SYSTEM_OPTIONS
932 if (wxSystemOptions
::GetOptionInt(wxT("no-maskblt")) == 0)
936 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
937 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
939 wxPalette
*pal
= bmp
.GetPalette();
940 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
942 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(pal
), FALSE
);
943 ::RealizePalette(hdcMem
);
945 #endif // wxUSE_PALETTE
947 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
950 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
954 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
955 #endif // wxUSE_PALETTE
957 ::SelectObject(hdcMem
, hOldBitmap
);
964 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
967 memDC
.SelectObject(bmp
);
969 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
971 memDC
.SelectObject(wxNullBitmap
);
974 else // no mask, just use BitBlt()
977 HDC memdc
= ::CreateCompatibleDC( cdc
);
978 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
980 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
982 COLORREF old_textground
= ::GetTextColor(GetHdc());
983 COLORREF old_background
= ::GetBkColor(GetHdc());
984 if (m_textForegroundColour
.Ok())
986 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
988 if (m_textBackgroundColour
.Ok())
990 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
994 wxPalette
*pal
= bmp
.GetPalette();
995 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
997 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(pal
), FALSE
);
998 ::RealizePalette(memdc
);
1000 #endif // wxUSE_PALETTE
1002 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1003 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1007 ::SelectPalette(memdc
, oldPal
, FALSE
);
1008 #endif // wxUSE_PALETTE
1010 ::SelectObject( memdc
, hOldBitmap
);
1011 ::DeleteDC( memdc
);
1013 ::SetTextColor(GetHdc(), old_textground
);
1014 ::SetBkColor(GetHdc(), old_background
);
1018 void wxDC
::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1020 #ifdef __WXMICROWIN__
1021 if (!GetHDC()) return;
1024 DrawAnyText(text
, x
, y
);
1026 // update the bounding box
1027 CalcBoundingBox(x
, y
);
1030 GetTextExtent(text
, &w
, &h
);
1031 CalcBoundingBox(x
+ w
, y
+ h
);
1034 void wxDC
::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1036 #ifdef __WXMICROWIN__
1037 if (!GetHDC()) return;
1040 // prepare for drawing the text
1041 if ( m_textForegroundColour
.Ok() )
1042 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1044 DWORD old_background
= 0;
1045 if ( m_textBackgroundColour
.Ok() )
1047 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1050 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT ? TRANSPARENT
1053 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1054 text
.c_str(), text
.length()) == 0 )
1056 wxLogLastError(wxT("TextOut"));
1059 // restore the old parameters (text foreground colour may be left because
1060 // it never is set to anything else, but background should remain
1061 // transparent even if we just drew an opaque string)
1062 if ( m_textBackgroundColour
.Ok() )
1063 (void)SetBkColor(GetHdc(), old_background
);
1065 SetBkMode(GetHdc(), TRANSPARENT
);
1068 void wxDC
::DoDrawRotatedText(const wxString
& text
,
1069 wxCoord x
, wxCoord y
,
1072 #ifdef __WXMICROWIN__
1073 if (!GetHDC()) return;
1076 // we test that we have some font because otherwise we should still use the
1077 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1078 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1079 // font for drawing rotated fonts unfortunately)
1080 if ( (angle
== 0.0) && m_font
.Ok() )
1082 DoDrawText(text
, x
, y
);
1084 #ifndef __WXMICROWIN__
1087 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1088 // because it's not TrueType and so can't have non zero
1089 // orientation/escapement under Win9x
1090 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1091 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1093 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1095 wxLogLastError(wxT("GetObject(hfont)"));
1098 // GDI wants the angle in tenth of degree
1099 long angle10
= (long)(angle
* 10);
1100 lf
.lfEscapement
= angle10
;
1101 lf
. lfOrientation
= angle10
;
1103 hfont
= ::CreateFontIndirect(&lf
);
1106 wxLogLastError(wxT("CreateFont"));
1110 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1112 DrawAnyText(text
, x
, y
);
1114 (void)::SelectObject(GetHdc(), hfontOld
);
1115 (void)::DeleteObject(hfont
);
1118 // call the bounding box by adding all four vertices of the rectangle
1119 // containing the text to it (simpler and probably not slower than
1120 // determining which of them is really topmost/leftmost/...)
1122 GetTextExtent(text
, &w
, &h
);
1124 double rad
= DegToRad(angle
);
1126 // "upper left" and "upper right"
1127 CalcBoundingBox(x
, y
);
1128 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
1130 // "bottom left" and "bottom right"
1131 x
+= (wxCoord
)(h
*sin(rad
));
1132 y
+= (wxCoord
)(h
*cos(rad
));
1133 CalcBoundingBox(x
, y
);
1134 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
1139 // ---------------------------------------------------------------------------
1141 // ---------------------------------------------------------------------------
1145 void wxDC
::SetPalette(const wxPalette
& palette
)
1147 #ifdef __WXMICROWIN__
1148 if (!GetHDC()) return;
1151 // Set the old object temporarily, in case the assignment deletes an object
1152 // that's not yet selected out.
1155 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1159 m_palette
= palette
;
1161 if (!m_palette
.Ok())
1163 // Setting a NULL colourmap is a way of restoring
1164 // the original colourmap
1167 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1174 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
1176 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
1178 m_oldPalette
= (WXHPALETTE
) oldPal
;
1180 ::RealizePalette(GetHdc());
1184 #endif // wxUSE_PALETTE
1186 void wxDC
::SetFont(const wxFont
& the_font
)
1188 #ifdef __WXMICROWIN__
1189 if (!GetHDC()) return;
1192 // Set the old object temporarily, in case the assignment deletes an object
1193 // that's not yet selected out.
1196 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1205 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1209 if (m_font
.Ok() && m_font
.GetResourceHandle())
1211 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1212 if (f
== (HFONT
) NULL
)
1214 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1217 m_oldFont
= (WXHFONT
) f
;
1221 void wxDC
::SetPen(const wxPen
& pen
)
1223 #ifdef __WXMICROWIN__
1224 if (!GetHDC()) return;
1227 // Set the old object temporarily, in case the assignment deletes an object
1228 // that's not yet selected out.
1231 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1240 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1246 if (m_pen
.GetResourceHandle())
1248 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1250 m_oldPen
= (WXHPEN
) p
;
1255 void wxDC
::SetBrush(const wxBrush
& brush
)
1257 #ifdef __WXMICROWIN__
1258 if (!GetHDC()) return;
1261 // Set the old object temporarily, in case the assignment deletes an object
1262 // that's not yet selected out.
1265 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1274 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1280 // to make sure the brush is alligned with the logical coordinates
1281 wxBitmap
*stipple
= m_brush
.GetStipple();
1282 if ( stipple
&& stipple
->Ok() )
1285 ::SetBrushOrgEx(GetHdc(),
1286 m_deviceOriginX
% stipple
->GetWidth(),
1287 m_deviceOriginY
% stipple
->GetHeight(),
1288 NULL
); // don't need previous brush origin
1290 ::SetBrushOrg(GetHdc(),
1291 m_deviceOriginX
% stipple
->GetWidth(),
1292 m_deviceOriginY
% stipple
->GetHeight());
1296 if ( m_brush
.GetResourceHandle() )
1299 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1301 m_oldBrush
= (WXHBRUSH
) b
;
1306 void wxDC
::SetBackground(const wxBrush
& brush
)
1308 #ifdef __WXMICROWIN__
1309 if (!GetHDC()) return;
1312 m_backgroundBrush
= brush
;
1314 if (!m_backgroundBrush
.Ok())
1319 bool customColours
= TRUE
;
1320 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1321 // change background colours from the control-panel specified colours.
1322 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1323 customColours
= FALSE
;
1327 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1329 m_canvas
->SetTransparent(TRUE
);
1333 // New behaviour, 10/2/99: setting the background brush of a DC
1334 // doesn't affect the window background colour. However,
1335 // I'm leaving in the transparency setting because it's needed by
1336 // various controls (e.g. wxStaticText) to determine whether to draw
1337 // transparently or not. TODO: maybe this should be a new function
1338 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1340 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1341 m_canvas
->SetTransparent(FALSE
);
1345 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1347 (void)SetBkColor(GetHdc(), new_color
);
1351 void wxDC
::SetBackgroundMode(int mode
)
1353 #ifdef __WXMICROWIN__
1354 if (!GetHDC()) return;
1357 m_backgroundMode
= mode
;
1359 // SetBackgroundColour now only refers to text background
1360 // and m_backgroundMode is used there
1363 void wxDC
::SetLogicalFunction(int function
)
1365 #ifdef __WXMICROWIN__
1366 if (!GetHDC()) return;
1369 m_logicalFunction
= function
;
1374 void wxDC
::SetRop(WXHDC dc
)
1376 if ( !dc
|| m_logicalFunction
< 0 )
1381 switch (m_logicalFunction
)
1383 case wxCLEAR
: rop
= R2_BLACK
; break;
1384 case wxXOR
: rop
= R2_XORPEN
; break;
1385 case wxINVERT
: rop
= R2_NOT
; break;
1386 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1387 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1388 case wxCOPY
: rop
= R2_COPYPEN
; break;
1389 case wxAND
: rop
= R2_MASKPEN
; break;
1390 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1391 case wxNO_OP
: rop
= R2_NOP
; break;
1392 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1393 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1394 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1395 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1396 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1397 case wxOR
: rop
= R2_MERGEPEN
; break;
1398 case wxSET
: rop
= R2_WHITE
; break;
1401 wxFAIL_MSG( wxT("unsupported logical function") );
1405 SetROP2(GetHdc(), rop
);
1408 bool wxDC
::StartDoc(const wxString
& WXUNUSED(message
))
1410 // We might be previewing, so return TRUE to let it continue.
1418 void wxDC
::StartPage()
1422 void wxDC
::EndPage()
1426 // ---------------------------------------------------------------------------
1428 // ---------------------------------------------------------------------------
1430 wxCoord wxDC
::GetCharHeight() const
1432 #ifdef __WXMICROWIN__
1433 if (!GetHDC()) return 0;
1436 TEXTMETRIC lpTextMetric
;
1438 GetTextMetrics(GetHdc(), &lpTextMetric
);
1440 return lpTextMetric
.tmHeight
;
1443 wxCoord wxDC
::GetCharWidth() const
1445 #ifdef __WXMICROWIN__
1446 if (!GetHDC()) return 0;
1449 TEXTMETRIC lpTextMetric
;
1451 GetTextMetrics(GetHdc(), &lpTextMetric
);
1453 return lpTextMetric
.tmAveCharWidth
;
1456 void wxDC
::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1457 wxCoord
*descent
, wxCoord
*externalLeading
,
1460 #ifdef __WXMICROWIN__
1465 if (descent
) *descent
= 0;
1466 if (externalLeading
) *externalLeading
= 0;
1469 #endif // __WXMICROWIN__
1474 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1476 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1478 else // don't change the font
1486 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1487 GetTextMetrics(GetHdc(), &tm
);
1494 *descent
= tm
.tmDescent
;
1495 if (externalLeading
)
1496 *externalLeading
= tm
.tmExternalLeading
;
1500 ::SelectObject(GetHdc(), hfontOld
);
1504 void wxDC
::SetMapMode(int mode
)
1506 #ifdef __WXMICROWIN__
1507 if (!GetHDC()) return;
1510 m_mappingMode
= mode
;
1512 if ( mode
== wxMM_TEXT
)
1515 m_logicalScaleY
= 1.0;
1517 else // need to do some calculations
1519 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1520 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1521 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1522 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1524 if ( (mm_width
== 0) || (mm_height
== 0) )
1526 // we can't calculate mm2pixels[XY] then!
1530 double mm2pixelsX
= pixel_width
/ mm_width
,
1531 mm2pixelsY
= pixel_height
/ mm_height
;
1536 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1537 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1541 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1542 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1546 m_logicalScaleX
= mm2pixelsX
;
1547 m_logicalScaleY
= mm2pixelsY
;
1551 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1552 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1556 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1560 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1561 // cases we could do with MM_TEXT and in the remaining 0.9% with
1562 // MM_ISOTROPIC (TODO!)
1563 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1565 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1566 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1568 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1569 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1571 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1572 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1575 void wxDC
::SetUserScale(double x
, double y
)
1577 #ifdef __WXMICROWIN__
1578 if (!GetHDC()) return;
1581 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1587 SetMapMode(m_mappingMode
);
1590 void wxDC
::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1592 #ifdef __WXMICROWIN__
1593 if (!GetHDC()) return;
1596 int signX
= xLeftRight ?
1 : -1,
1597 signY
= yBottomUp ?
-1 : 1;
1599 if ( signX
!= m_signX
|| signY
!= m_signY
)
1604 SetMapMode(m_mappingMode
);
1608 void wxDC
::SetSystemScale(double x
, double y
)
1610 #ifdef __WXMICROWIN__
1611 if (!GetHDC()) return;
1614 if ( x
== m_scaleX
&& y
== m_scaleY
)
1620 SetMapMode(m_mappingMode
);
1623 void wxDC
::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1625 #ifdef __WXMICROWIN__
1626 if (!GetHDC()) return;
1629 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1632 m_logicalOriginX
= x
;
1633 m_logicalOriginY
= y
;
1635 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1638 void wxDC
::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1640 #ifdef __WXMICROWIN__
1641 if (!GetHDC()) return;
1644 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1647 m_deviceOriginX
= x
;
1648 m_deviceOriginY
= y
;
1650 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1653 // ---------------------------------------------------------------------------
1654 // coordinates transformations
1655 // ---------------------------------------------------------------------------
1657 wxCoord wxDCBase
::DeviceToLogicalX(wxCoord x
) const
1659 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1662 wxCoord wxDCBase
::DeviceToLogicalXRel(wxCoord x
) const
1664 // axis orientation is not taken into account for conversion of a distance
1665 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1668 wxCoord wxDCBase
::DeviceToLogicalY(wxCoord y
) const
1670 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1673 wxCoord wxDCBase
::DeviceToLogicalYRel(wxCoord y
) const
1675 // axis orientation is not taken into account for conversion of a distance
1676 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1679 wxCoord wxDCBase
::LogicalToDeviceX(wxCoord x
) const
1681 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1684 wxCoord wxDCBase
::LogicalToDeviceXRel(wxCoord x
) const
1686 // axis orientation is not taken into account for conversion of a distance
1687 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1690 wxCoord wxDCBase
::LogicalToDeviceY(wxCoord y
) const
1692 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1695 wxCoord wxDCBase
::LogicalToDeviceYRel(wxCoord y
) const
1697 // axis orientation is not taken into account for conversion of a distance
1698 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1701 // ---------------------------------------------------------------------------
1703 // ---------------------------------------------------------------------------
1705 bool wxDC
::DoBlit(wxCoord xdest
, wxCoord ydest
,
1706 wxCoord width
, wxCoord height
,
1707 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1708 int rop
, bool useMask
,
1709 wxCoord xsrcMask
, wxCoord ysrcMask
)
1711 #ifdef __WXMICROWIN__
1712 if (!GetHDC()) return FALSE
;
1715 wxMask
*mask
= NULL
;
1718 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1719 mask
= bmp
.GetMask();
1721 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1723 // don't give assert here because this would break existing
1724 // programs - just silently ignore useMask parameter
1729 if (xsrcMask
== -1 && ysrcMask
== -1)
1731 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1734 COLORREF old_textground
= ::GetTextColor(GetHdc());
1735 COLORREF old_background
= ::GetBkColor(GetHdc());
1736 if (m_textForegroundColour
.Ok())
1738 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1740 if (m_textBackgroundColour
.Ok())
1742 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1745 DWORD dwRop
= SRCCOPY
;
1748 case wxXOR
: dwRop
= SRCINVERT
; break;
1749 case wxINVERT
: dwRop
= DSTINVERT
; break;
1750 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1751 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1752 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1753 case wxSET
: dwRop
= WHITENESS
; break;
1754 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1755 case wxAND
: dwRop
= SRCAND
; break;
1756 case wxOR
: dwRop
= SRCPAINT
; break;
1757 case wxEQUIV
: dwRop
= 0x00990066; break;
1758 case wxNAND
: dwRop
= 0x007700E6; break;
1759 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1760 case wxCOPY
: dwRop
= SRCCOPY
; break;
1761 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1762 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1763 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1765 wxFAIL_MSG( wxT("unsupported logical function") );
1769 bool success
= FALSE
;
1774 // we want the part of the image corresponding to the mask to be
1775 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1776 // meaning of fg and bg is inverted which corresponds to wxWin notion
1777 // of the mask which is also contrary to the Windows one)
1779 // On some systems, MaskBlt succeeds yet is much much slower
1780 // than the wxWindows fall-back implementation. So we need
1781 // to be able to switch this on and off at runtime.
1782 #if wxUSE_SYSTEM_OPTIONS
1783 if (wxSystemOptions
::GetOptionInt(wxT("no-maskblt")) == 0)
1786 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1787 GetHdcOf(*source
), xsrc
, ysrc
,
1788 (HBITMAP
)mask
->GetMaskBitmap(), xsrcMask
, ysrcMask
,
1789 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1795 // Blit bitmap with mask
1798 HBITMAP buffer_bmap
;
1800 #if wxUSE_DC_CACHEING
1801 // create a temp buffer bitmap and DCs to access it and the mask
1802 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1803 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1805 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1806 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1808 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1811 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1812 #else // !wxUSE_DC_CACHEING
1813 // create a temp buffer bitmap and DCs to access it and the mask
1814 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1815 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1816 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1817 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1818 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1819 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1821 // copy dest to buffer
1822 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1823 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1825 wxLogLastError(wxT("BitBlt"));
1828 // copy src to buffer using selected raster op
1829 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1830 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1832 wxLogLastError(wxT("BitBlt"));
1835 // set masked area in buffer to BLACK (pixel value 0)
1836 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1837 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1838 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1839 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1841 wxLogLastError(wxT("BitBlt"));
1844 // set unmasked area in dest to BLACK
1845 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1846 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1847 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1848 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1850 wxLogLastError(wxT("BitBlt"));
1852 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1853 ::SetTextColor(GetHdc(), prevCol
);
1855 // OR buffer to dest
1856 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1857 (int)width
, (int)height
,
1858 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1861 wxLogLastError(wxT("BitBlt"));
1864 // tidy up temporary DCs and bitmap
1865 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1866 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1868 #if !wxUSE_DC_CACHEING
1870 ::DeleteDC(dc_mask
);
1871 ::DeleteDC(dc_buffer
);
1872 ::DeleteObject(buffer_bmap
);
1877 else // no mask, just BitBlt() it
1879 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1880 (int)width
, (int)height
,
1881 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1884 wxLogLastError(wxT("BitBlt"));
1887 ::SetTextColor(GetHdc(), old_textground
);
1888 ::SetBkColor(GetHdc(), old_background
);
1893 void wxDC
::DoGetSize(int *w
, int *h
) const
1895 #ifdef __WXMICROWIN__
1896 if (!GetHDC()) return;
1899 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1900 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1903 void wxDC
::DoGetSizeMM(int *w
, int *h
) const
1905 #ifdef __WXMICROWIN__
1906 if (!GetHDC()) return;
1909 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1910 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1913 wxSize wxDC
::GetPPI() const
1915 #ifdef __WXMICROWIN__
1916 if (!GetHDC()) return wxSize();
1919 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1920 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1922 return wxSize(x
, y
);
1925 // For use by wxWindows only, unless custom units are required.
1926 void wxDC
::SetLogicalScale(double x
, double y
)
1928 #ifdef __WXMICROWIN__
1929 if (!GetHDC()) return;
1932 m_logicalScaleX
= x
;
1933 m_logicalScaleY
= y
;
1936 #if WXWIN_COMPATIBILITY
1937 void wxDC
::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1938 float *descent
, float *externalLeading
,
1939 wxFont
*theFont
, bool use16bit
) const
1941 #ifdef __WXMICROWIN__
1942 if (!GetHDC()) return;
1945 wxCoord x1
, y1
, descent1
, externalLeading1
;
1946 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1949 *descent
= descent1
;
1950 if (externalLeading
)
1951 *externalLeading
= externalLeading1
;
1955 #if wxUSE_DC_CACHEING
1958 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
1959 * improve it in due course, either using arrays, or simply storing pointers to one
1960 * entry for the bitmap, and two for the DCs. -- JACS
1963 wxList wxDC
::sm_bitmapCache
;
1964 wxList wxDC
::sm_dcCache
;
1966 wxDCCacheEntry
::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
1975 wxDCCacheEntry
::wxDCCacheEntry(WXHDC hDC
, int depth
)
1984 wxDCCacheEntry
::~wxDCCacheEntry()
1987 ::DeleteObject((HBITMAP
) m_bitmap
);
1989 ::DeleteDC((HDC
) m_dc
);
1992 wxDCCacheEntry
* wxDC
::FindBitmapInCache(WXHDC dc
, int w
, int h
)
1994 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
1995 wxNode
* node
= sm_bitmapCache
.First();
1998 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2000 if (entry
->m_depth
== depth
)
2002 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2004 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2005 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2006 if ( !entry
->m_bitmap
)
2008 wxLogLastError(wxT("CreateCompatibleBitmap"));
2010 entry
->m_width
= w
; entry
->m_height
= h
;
2016 node
= node
->Next();
2018 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2021 wxLogLastError(wxT("CreateCompatibleBitmap"));
2023 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2024 AddToBitmapCache(entry
);
2028 wxDCCacheEntry
* wxDC
::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2030 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2031 wxNode
* node
= sm_dcCache
.First();
2034 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2036 // Don't return the same one as we already have
2037 if (!notThis
|| (notThis
!= entry
))
2039 if (entry
->m_depth
== depth
)
2045 node
= node
->Next();
2047 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2050 wxLogLastError(wxT("CreateCompatibleDC"));
2052 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2053 AddToDCCache(entry
);
2057 void wxDC
::AddToBitmapCache(wxDCCacheEntry
* entry
)
2059 sm_bitmapCache
.Append(entry
);
2062 void wxDC
::AddToDCCache(wxDCCacheEntry
* entry
)
2064 sm_dcCache
.Append(entry
);
2067 void wxDC
::ClearCache()
2069 sm_bitmapCache
.DeleteContents(TRUE
);
2070 sm_bitmapCache
.Clear();
2071 sm_bitmapCache
.DeleteContents(FALSE
);
2072 sm_dcCache
.DeleteContents(TRUE
);
2074 sm_dcCache
.DeleteContents(FALSE
);
2077 // Clean up cache at app exit
2078 class wxDCModule
: public wxModule
2081 virtual bool OnInit() { return TRUE
; }
2082 virtual void OnExit() { wxDC
::ClearCache(); }
2085 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2088 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2091 // wxUSE_DC_CACHEING