]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/dc.cpp
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 const wxBrush
& brush
= dc
.GetBrush();
141 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
143 HDC hdc
= GetHdcOf(dc
);
144 m_colFgOld
= ::GetTextColor(hdc
);
145 m_colBgOld
= ::GetBkColor(hdc
);
147 // note that Windows convention is opposite to wxWindows one, this is
148 // why text colour becomes the background one and vice versa
149 const wxColour
& colFg
= dc
.GetTextForeground();
152 ::SetBkColor(hdc
, colFg
.GetPixel());
155 const wxColour
& colBg
= dc
.GetTextBackground();
158 ::SetTextColor(hdc
, colBg
.GetPixel());
162 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
165 // flag which telsl us to undo changes in the dtor
170 // nothing done, nothing to undo
175 wxColourChanger::~wxColourChanger()
179 // restore the colours we changed
180 HDC hdc
= GetHdcOf(m_dc
);
182 ::SetBkMode(hdc
, TRANSPARENT
);
183 ::SetTextColor(hdc
, m_colFgOld
);
184 ::SetBkColor(hdc
, m_colBgOld
);
188 // ---------------------------------------------------------------------------
190 // ---------------------------------------------------------------------------
192 // Default constructor
203 #endif // wxUSE_PALETTE
213 SelectOldObjects(m_hDC
);
215 // if we own the HDC, we delete it, otherwise we just release it
219 ::DeleteDC(GetHdc());
221 else // we don't own our HDC
225 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
229 // Must have been a wxScreenDC
230 ::ReleaseDC((HWND
) NULL
, GetHdc());
236 // This will select current objects out of the DC,
237 // which is what you have to do before deleting the
239 void wxDC::SelectOldObjects(WXHDC dc
)
245 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
246 if (m_selectedBitmap
.Ok())
248 m_selectedBitmap
.SetSelectedInto(NULL
);
254 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
259 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
264 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
271 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
274 #endif // wxUSE_PALETTE
277 m_brush
= wxNullBrush
;
280 m_palette
= wxNullPalette
;
281 #endif // wxUSE_PALETTE
283 m_backgroundBrush
= wxNullBrush
;
284 m_selectedBitmap
= wxNullBitmap
;
287 // ---------------------------------------------------------------------------
289 // ---------------------------------------------------------------------------
291 void wxDC::UpdateClipBox()
293 #ifdef __WXMICROWIN__
294 if (!GetHDC()) return;
298 ::GetClipBox(GetHdc(), &rect
);
300 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
301 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
302 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
303 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
306 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
307 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
309 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
311 #ifdef __WXMICROWIN__
312 if (!GetHdc()) return;
313 #endif // __WXMICROWIN__
315 // note that we combine the new clipping region with the existing one: this
316 // is compatible with what the other ports do and is the documented
317 // behaviour now (starting with 2.3.3)
320 if ( !::GetClipBox(GetHdc(), &rectClip
) )
323 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
324 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
325 rectClip
.right
, rectClip
.bottom
);
327 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
329 ::SelectClipRgn(GetHdc(), hrgnDest
);
332 ::DeleteObject(hrgnClipOld
);
333 ::DeleteObject(hrgnDest
);
335 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
337 wxLogLastError(_T("ExtSelectClipRgn"));
348 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
350 // the region coords are always the device ones, so do the translation
353 // FIXME: possible +/-1 error here, to check!
354 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
356 LogicalToDeviceX(x
+ w
),
357 LogicalToDeviceY(y
+ h
));
360 wxLogLastError(_T("CreateRectRgn"));
364 SetClippingHrgn((WXHRGN
)hrgn
);
366 ::DeleteObject(hrgn
);
370 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
372 SetClippingHrgn(region
.GetHRGN());
375 void wxDC::DestroyClippingRegion()
377 #ifdef __WXMICROWIN__
378 if (!GetHDC()) return;
381 if (m_clipping
&& m_hDC
)
383 // TODO: this should restore the previous clipping region,
384 // so that OnPaint processing works correctly, and the update
385 // clipping region doesn't get destroyed after the first
386 // DestroyClippingRegion.
387 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
388 ::SelectClipRgn(GetHdc(), rgn
);
395 // ---------------------------------------------------------------------------
396 // query capabilities
397 // ---------------------------------------------------------------------------
399 bool wxDC::CanDrawBitmap() const
404 bool wxDC::CanGetTextExtent() const
406 #ifdef __WXMICROWIN__
407 // TODO Extend MicroWindows' GetDeviceCaps function
410 // What sort of display is it?
411 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
413 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
417 int wxDC::GetDepth() const
419 #ifdef __WXMICROWIN__
420 if (!GetHDC()) return 16;
423 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
426 // ---------------------------------------------------------------------------
428 // ---------------------------------------------------------------------------
432 #ifdef __WXMICROWIN__
433 if (!GetHDC()) return;
439 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
443 // No, I think we should simply ignore this if printing on e.g.
445 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
446 if (!m_selectedBitmap
.Ok())
449 rect
.left
= 0; rect
.top
= 0;
450 rect
.right
= m_selectedBitmap
.GetWidth();
451 rect
.bottom
= m_selectedBitmap
.GetHeight();
454 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
456 DWORD colour
= ::GetBkColor(GetHdc());
457 HBRUSH brush
= ::CreateSolidBrush(colour
);
458 ::FillRect(GetHdc(), &rect
, brush
);
459 ::DeleteObject(brush
);
461 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
462 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
464 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
465 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
466 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
467 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
468 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
471 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
473 #ifdef __WXMICROWIN__
474 if (!GetHDC()) return FALSE
;
477 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
479 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
480 : FLOODFILLBORDER
) ) ;
483 // quoting from the MSDN docs:
485 // Following are some of the reasons this function might fail:
487 // * The filling could not be completed.
488 // * The specified point has the boundary color specified by the
489 // crColor parameter (if FLOODFILLBORDER was requested).
490 // * The specified point does not have the color specified by
491 // crColor (if FLOODFILLSURFACE was requested)
492 // * The point is outside the clipping region that is, it is not
493 // visible on the device.
495 wxLogLastError(wxT("ExtFloodFill"));
498 CalcBoundingBox(x
, y
);
503 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
505 #ifdef __WXMICROWIN__
506 if (!GetHDC()) return FALSE
;
509 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
511 // get the color of the pixel
512 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
514 wxRGBToColour(*col
, pixelcolor
);
519 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
521 #ifdef __WXMICROWIN__
522 if (!GetHDC()) return;
525 wxCoord x1
= x
-VIEWPORT_EXTENT
;
526 wxCoord y1
= y
-VIEWPORT_EXTENT
;
527 wxCoord x2
= x
+VIEWPORT_EXTENT
;
528 wxCoord y2
= y
+VIEWPORT_EXTENT
;
530 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
531 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
533 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
534 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
536 CalcBoundingBox(x1
, y1
);
537 CalcBoundingBox(x2
, y2
);
540 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
542 #ifdef __WXMICROWIN__
543 if (!GetHDC()) return;
546 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
547 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
549 CalcBoundingBox(x1
, y1
);
550 CalcBoundingBox(x2
, y2
);
553 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
554 // and ending at (x2, y2)
555 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
556 wxCoord x2
, wxCoord y2
,
557 wxCoord xc
, wxCoord yc
)
559 #ifdef __WXMICROWIN__
560 if (!GetHDC()) return;
563 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
567 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
568 wxCoord r
= (wxCoord
)radius
;
570 // treat the special case of full circle separately
571 if ( x1
== x2
&& y1
== y2
)
573 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
577 wxCoord xx1
= XLOG2DEV(x1
);
578 wxCoord yy1
= YLOG2DEV(y1
);
579 wxCoord xx2
= XLOG2DEV(x2
);
580 wxCoord yy2
= YLOG2DEV(y2
);
581 wxCoord xxc
= XLOG2DEV(xc
);
582 wxCoord yyc
= YLOG2DEV(yc
);
583 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
585 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
586 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
587 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
588 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
590 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
592 // Have to add 1 to bottom-right corner of rectangle
593 // to make semi-circles look right (crooked line otherwise).
594 // Unfortunately this is not a reliable method, depends
595 // on the size of shape.
596 // TODO: figure out why this happens!
597 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
601 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
604 CalcBoundingBox(xc
- r
, yc
- r
);
605 CalcBoundingBox(xc
+ r
, yc
+ r
);
608 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
609 wxCoord width
, wxCoord height
)
611 #ifdef __WXMICROWIN__
612 if (!GetHDC()) return;
615 wxCoord x2
= x1
+ width
,
618 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__)
625 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
627 // In WIN16, draw a cross
628 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
629 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
630 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
631 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
632 ::SetROP2(GetHdc(), R2_COPYPEN
);
633 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
634 MoveToEx(GetHdc(), x1
, y1
, NULL
);
635 LineTo(GetHdc(), x2
, y2
);
636 MoveToEx(GetHdc(), x2
, y1
, NULL
);
637 LineTo(GetHdc(), x1
, y2
);
638 ::SelectObject(GetHdc(), hPenOld
);
639 ::SelectObject(GetHdc(), hBrushOld
);
640 ::DeleteObject(blackPen
);
643 CalcBoundingBox(x1
, y1
);
644 CalcBoundingBox(x2
, y2
);
647 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
649 #ifdef __WXMICROWIN__
650 if (!GetHDC()) return;
653 COLORREF color
= 0x00ffffff;
656 color
= m_pen
.GetColour().GetPixel();
659 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
661 CalcBoundingBox(x
, y
);
664 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
666 #ifdef __WXMICROWIN__
667 if (!GetHDC()) return;
670 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
672 // Do things less efficiently if we have offsets
673 if (xoffset
!= 0 || yoffset
!= 0)
675 POINT
*cpoints
= new POINT
[n
];
677 for (i
= 0; i
< n
; i
++)
679 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
680 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
682 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
684 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
685 (void)Polygon(GetHdc(), cpoints
, n
);
686 SetPolyFillMode(GetHdc(),prev
);
692 for (i
= 0; i
< n
; i
++)
693 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
695 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
696 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
697 SetPolyFillMode(GetHdc(),prev
);
701 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
703 #ifdef __WXMICROWIN__
704 if (!GetHDC()) return;
707 // Do things less efficiently if we have offsets
708 if (xoffset
!= 0 || yoffset
!= 0)
710 POINT
*cpoints
= new POINT
[n
];
712 for (i
= 0; i
< n
; i
++)
714 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
715 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
717 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
719 (void)Polyline(GetHdc(), cpoints
, n
);
725 for (i
= 0; i
< n
; i
++)
726 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
728 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
732 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
734 #ifdef __WXMICROWIN__
735 if (!GetHDC()) return;
738 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
740 wxCoord x2
= x
+ width
;
741 wxCoord y2
= y
+ height
;
743 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
746 rect
.left
= XLOG2DEV(x
);
747 rect
.top
= YLOG2DEV(y
);
748 rect
.right
= XLOG2DEV(x2
);
749 rect
.bottom
= YLOG2DEV(y2
);
750 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
754 // Windows draws the filled rectangles without outline (i.e. drawn with a
755 // transparent pen) one pixel smaller in both directions and we want them
756 // to have the same size regardless of which pen is used - adjust
758 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
759 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
765 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
769 CalcBoundingBox(x
, y
);
770 CalcBoundingBox(x2
, y2
);
773 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
775 #ifdef __WXMICROWIN__
776 if (!GetHDC()) return;
779 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
781 // Now, a negative radius value is interpreted to mean
782 // 'the proportion of the smallest X or Y dimension'
786 double smallest
= 0.0;
791 radius
= (- radius
* smallest
);
794 wxCoord x2
= (x
+width
);
795 wxCoord y2
= (y
+height
);
797 // Windows draws the filled rectangles without outline (i.e. drawn with a
798 // transparent pen) one pixel smaller in both directions and we want them
799 // to have the same size regardless of which pen is used - adjust
800 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
806 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
807 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
809 CalcBoundingBox(x
, y
);
810 CalcBoundingBox(x2
, y2
);
813 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
815 #ifdef __WXMICROWIN__
816 if (!GetHDC()) return;
819 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
821 wxCoord x2
= (x
+width
);
822 wxCoord y2
= (y
+height
);
824 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
826 CalcBoundingBox(x
, y
);
827 CalcBoundingBox(x2
, y2
);
830 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
831 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
833 #ifdef __WXMICROWIN__
834 if (!GetHDC()) return;
837 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
842 int rx1
= XLOG2DEV(x
+w
/2);
843 int ry1
= YLOG2DEV(y
+h
/2);
850 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
851 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
852 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
853 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
855 // draw pie with NULL_PEN first and then outline otherwise a line is
856 // drawn from the start and end points to the centre
857 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
860 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
865 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
866 rx1
, ry1
-1, rx2
, ry2
-1);
869 ::SelectObject(GetHdc(), hpenOld
);
871 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
874 CalcBoundingBox(x
, y
);
875 CalcBoundingBox(x2
, y2
);
878 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
880 #ifdef __WXMICROWIN__
881 if (!GetHDC()) return;
884 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
887 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
889 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
892 CalcBoundingBox(x
, y
);
893 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
896 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
898 #ifdef __WXMICROWIN__
899 if (!GetHDC()) return;
902 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
904 int width
= bmp
.GetWidth(),
905 height
= bmp
.GetHeight();
907 HBITMAP hbmpMask
= 0;
911 #endif // wxUSE_PALETTE
915 wxMask
*mask
= bmp
.GetMask();
917 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
921 // don't give assert here because this would break existing
922 // programs - just silently ignore useMask parameter
929 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
931 // On some systems, MaskBlt succeeds yet is much much slower
932 // than the wxWindows fall-back implementation. So we need
933 // to be able to switch this on and off at runtime.
935 #if wxUSE_SYSTEM_OPTIONS
936 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
940 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
941 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
943 wxPalette
*pal
= bmp
.GetPalette();
944 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
946 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
947 ::RealizePalette(hdcMem
);
949 #endif // wxUSE_PALETTE
951 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
954 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
958 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
959 #endif // wxUSE_PALETTE
961 ::SelectObject(hdcMem
, hOldBitmap
);
968 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
971 memDC
.SelectObject(bmp
);
973 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
975 memDC
.SelectObject(wxNullBitmap
);
978 else // no mask, just use BitBlt()
981 HDC memdc
= ::CreateCompatibleDC( cdc
);
982 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
984 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
986 COLORREF old_textground
= ::GetTextColor(GetHdc());
987 COLORREF old_background
= ::GetBkColor(GetHdc());
988 if (m_textForegroundColour
.Ok())
990 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
992 if (m_textBackgroundColour
.Ok())
994 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
998 wxPalette
*pal
= bmp
.GetPalette();
999 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1001 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1002 ::RealizePalette(memdc
);
1004 #endif // wxUSE_PALETTE
1006 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1007 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1011 ::SelectPalette(memdc
, oldPal
, FALSE
);
1012 #endif // wxUSE_PALETTE
1014 ::SelectObject( memdc
, hOldBitmap
);
1015 ::DeleteDC( memdc
);
1017 ::SetTextColor(GetHdc(), old_textground
);
1018 ::SetBkColor(GetHdc(), old_background
);
1022 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1024 #ifdef __WXMICROWIN__
1025 if (!GetHDC()) return;
1028 DrawAnyText(text
, x
, y
);
1030 // update the bounding box
1031 CalcBoundingBox(x
, y
);
1034 GetTextExtent(text
, &w
, &h
);
1035 CalcBoundingBox(x
+ w
, y
+ h
);
1038 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1040 #ifdef __WXMICROWIN__
1041 if (!GetHDC()) return;
1044 // prepare for drawing the text
1045 if ( m_textForegroundColour
.Ok() )
1046 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1048 DWORD old_background
= 0;
1049 if ( m_textBackgroundColour
.Ok() )
1051 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1054 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1057 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1058 text
.c_str(), text
.length()) == 0 )
1060 wxLogLastError(wxT("TextOut"));
1063 // restore the old parameters (text foreground colour may be left because
1064 // it never is set to anything else, but background should remain
1065 // transparent even if we just drew an opaque string)
1066 if ( m_textBackgroundColour
.Ok() )
1067 (void)SetBkColor(GetHdc(), old_background
);
1069 SetBkMode(GetHdc(), TRANSPARENT
);
1072 void wxDC::DoDrawRotatedText(const wxString
& text
,
1073 wxCoord x
, wxCoord y
,
1076 #ifdef __WXMICROWIN__
1077 if (!GetHDC()) return;
1080 // we test that we have some font because otherwise we should still use the
1081 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1082 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1083 // font for drawing rotated fonts unfortunately)
1084 if ( (angle
== 0.0) && m_font
.Ok() )
1086 DoDrawText(text
, x
, y
);
1088 #ifndef __WXMICROWIN__
1091 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1092 // because it's not TrueType and so can't have non zero
1093 // orientation/escapement under Win9x
1094 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1095 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1097 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1099 wxLogLastError(wxT("GetObject(hfont)"));
1102 // GDI wants the angle in tenth of degree
1103 long angle10
= (long)(angle
* 10);
1104 lf
.lfEscapement
= angle10
;
1105 lf
. lfOrientation
= angle10
;
1107 hfont
= ::CreateFontIndirect(&lf
);
1110 wxLogLastError(wxT("CreateFont"));
1114 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1116 DrawAnyText(text
, x
, y
);
1118 (void)::SelectObject(GetHdc(), hfontOld
);
1119 (void)::DeleteObject(hfont
);
1122 // call the bounding box by adding all four vertices of the rectangle
1123 // containing the text to it (simpler and probably not slower than
1124 // determining which of them is really topmost/leftmost/...)
1126 GetTextExtent(text
, &w
, &h
);
1128 double rad
= DegToRad(angle
);
1130 // "upper left" and "upper right"
1131 CalcBoundingBox(x
, y
);
1132 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1134 // "bottom left" and "bottom right"
1135 x
+= (wxCoord
)(h
*sin(rad
));
1136 y
+= (wxCoord
)(h
*cos(rad
));
1137 CalcBoundingBox(x
, y
);
1138 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1143 // ---------------------------------------------------------------------------
1145 // ---------------------------------------------------------------------------
1149 void wxDC::DoSelectPalette(bool realize
)
1151 #ifdef __WXMICROWIN__
1152 if (!GetHDC()) return;
1155 // Set the old object temporarily, in case the assignment deletes an object
1156 // that's not yet selected out.
1159 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1163 if ( m_palette
.Ok() )
1165 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1166 GetHpaletteOf(m_palette
),
1169 m_oldPalette
= (WXHPALETTE
) oldPal
;
1172 ::RealizePalette(GetHdc());
1176 void wxDC::SetPalette(const wxPalette
& palette
)
1180 m_palette
= palette
;
1181 DoSelectPalette(TRUE
);
1185 void wxDC::InitializePalette()
1187 if ( wxDisplayDepth() <= 8 )
1189 // look for any window or parent that has a custom palette. If any has
1190 // one then we need to use it in drawing operations
1191 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1193 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1194 if ( m_hasCustomPalette
)
1196 m_palette
= win
->GetPalette();
1198 // turn on MSW translation for this palette
1204 #endif // wxUSE_PALETTE
1206 void wxDC::SetFont(const wxFont
& the_font
)
1208 #ifdef __WXMICROWIN__
1209 if (!GetHDC()) return;
1212 // Set the old object temporarily, in case the assignment deletes an object
1213 // that's not yet selected out.
1216 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1225 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1229 if (m_font
.Ok() && m_font
.GetResourceHandle())
1231 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1232 if (f
== (HFONT
) NULL
)
1234 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1237 m_oldFont
= (WXHFONT
) f
;
1241 void wxDC::SetPen(const wxPen
& pen
)
1243 #ifdef __WXMICROWIN__
1244 if (!GetHDC()) return;
1247 // Set the old object temporarily, in case the assignment deletes an object
1248 // that's not yet selected out.
1251 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1260 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1266 if (m_pen
.GetResourceHandle())
1268 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1270 m_oldPen
= (WXHPEN
) p
;
1275 void wxDC::SetBrush(const wxBrush
& brush
)
1277 #ifdef __WXMICROWIN__
1278 if (!GetHDC()) return;
1281 // Set the old object temporarily, in case the assignment deletes an object
1282 // that's not yet selected out.
1285 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1294 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1300 // to make sure the brush is alligned with the logical coordinates
1301 wxBitmap
*stipple
= m_brush
.GetStipple();
1302 if ( stipple
&& stipple
->Ok() )
1305 ::SetBrushOrgEx(GetHdc(),
1306 m_deviceOriginX
% stipple
->GetWidth(),
1307 m_deviceOriginY
% stipple
->GetHeight(),
1308 NULL
); // don't need previous brush origin
1310 ::SetBrushOrg(GetHdc(),
1311 m_deviceOriginX
% stipple
->GetWidth(),
1312 m_deviceOriginY
% stipple
->GetHeight());
1316 if ( m_brush
.GetResourceHandle() )
1319 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1321 m_oldBrush
= (WXHBRUSH
) b
;
1326 void wxDC::SetBackground(const wxBrush
& brush
)
1328 #ifdef __WXMICROWIN__
1329 if (!GetHDC()) return;
1332 m_backgroundBrush
= brush
;
1334 if (!m_backgroundBrush
.Ok())
1339 bool customColours
= TRUE
;
1340 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1341 // change background colours from the control-panel specified colours.
1342 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1343 customColours
= FALSE
;
1347 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1349 m_canvas
->SetTransparent(TRUE
);
1353 // New behaviour, 10/2/99: setting the background brush of a DC
1354 // doesn't affect the window background colour. However,
1355 // I'm leaving in the transparency setting because it's needed by
1356 // various controls (e.g. wxStaticText) to determine whether to draw
1357 // transparently or not. TODO: maybe this should be a new function
1358 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1360 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1361 m_canvas
->SetTransparent(FALSE
);
1365 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1367 (void)SetBkColor(GetHdc(), new_color
);
1371 void wxDC::SetBackgroundMode(int mode
)
1373 #ifdef __WXMICROWIN__
1374 if (!GetHDC()) return;
1377 m_backgroundMode
= mode
;
1379 // SetBackgroundColour now only refers to text background
1380 // and m_backgroundMode is used there
1383 void wxDC::SetLogicalFunction(int function
)
1385 #ifdef __WXMICROWIN__
1386 if (!GetHDC()) return;
1389 m_logicalFunction
= function
;
1394 void wxDC::SetRop(WXHDC dc
)
1396 if ( !dc
|| m_logicalFunction
< 0 )
1401 switch (m_logicalFunction
)
1403 case wxCLEAR
: rop
= R2_BLACK
; break;
1404 case wxXOR
: rop
= R2_XORPEN
; break;
1405 case wxINVERT
: rop
= R2_NOT
; break;
1406 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1407 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1408 case wxCOPY
: rop
= R2_COPYPEN
; break;
1409 case wxAND
: rop
= R2_MASKPEN
; break;
1410 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1411 case wxNO_OP
: rop
= R2_NOP
; break;
1412 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1413 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1414 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1415 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1416 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1417 case wxOR
: rop
= R2_MERGEPEN
; break;
1418 case wxSET
: rop
= R2_WHITE
; break;
1421 wxFAIL_MSG( wxT("unsupported logical function") );
1425 SetROP2(GetHdc(), rop
);
1428 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1430 // We might be previewing, so return TRUE to let it continue.
1438 void wxDC::StartPage()
1442 void wxDC::EndPage()
1446 // ---------------------------------------------------------------------------
1448 // ---------------------------------------------------------------------------
1450 wxCoord
wxDC::GetCharHeight() const
1452 #ifdef __WXMICROWIN__
1453 if (!GetHDC()) return 0;
1456 TEXTMETRIC lpTextMetric
;
1458 GetTextMetrics(GetHdc(), &lpTextMetric
);
1460 return lpTextMetric
.tmHeight
;
1463 wxCoord
wxDC::GetCharWidth() const
1465 #ifdef __WXMICROWIN__
1466 if (!GetHDC()) return 0;
1469 TEXTMETRIC lpTextMetric
;
1471 GetTextMetrics(GetHdc(), &lpTextMetric
);
1473 return lpTextMetric
.tmAveCharWidth
;
1476 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1477 wxCoord
*descent
, wxCoord
*externalLeading
,
1480 #ifdef __WXMICROWIN__
1485 if (descent
) *descent
= 0;
1486 if (externalLeading
) *externalLeading
= 0;
1489 #endif // __WXMICROWIN__
1494 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1496 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1498 else // don't change the font
1506 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1507 GetTextMetrics(GetHdc(), &tm
);
1514 *descent
= tm
.tmDescent
;
1515 if (externalLeading
)
1516 *externalLeading
= tm
.tmExternalLeading
;
1520 ::SelectObject(GetHdc(), hfontOld
);
1524 void wxDC::SetMapMode(int mode
)
1526 #ifdef __WXMICROWIN__
1527 if (!GetHDC()) return;
1530 m_mappingMode
= mode
;
1532 if ( mode
== wxMM_TEXT
)
1535 m_logicalScaleY
= 1.0;
1537 else // need to do some calculations
1539 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1540 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1541 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1542 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1544 if ( (mm_width
== 0) || (mm_height
== 0) )
1546 // we can't calculate mm2pixels[XY] then!
1550 double mm2pixelsX
= pixel_width
/ mm_width
,
1551 mm2pixelsY
= pixel_height
/ mm_height
;
1556 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1557 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1561 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1562 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1566 m_logicalScaleX
= mm2pixelsX
;
1567 m_logicalScaleY
= mm2pixelsY
;
1571 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1572 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1576 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1580 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1581 // cases we could do with MM_TEXT and in the remaining 0.9% with
1582 // MM_ISOTROPIC (TODO!)
1583 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1585 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1586 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1588 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1589 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1591 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1592 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1595 void wxDC::SetUserScale(double x
, double y
)
1597 #ifdef __WXMICROWIN__
1598 if (!GetHDC()) return;
1601 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1607 SetMapMode(m_mappingMode
);
1610 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1612 #ifdef __WXMICROWIN__
1613 if (!GetHDC()) return;
1616 int signX
= xLeftRight
? 1 : -1,
1617 signY
= yBottomUp
? -1 : 1;
1619 if ( signX
!= m_signX
|| signY
!= m_signY
)
1624 SetMapMode(m_mappingMode
);
1628 void wxDC::SetSystemScale(double x
, double y
)
1630 #ifdef __WXMICROWIN__
1631 if (!GetHDC()) return;
1634 if ( x
== m_scaleX
&& y
== m_scaleY
)
1640 SetMapMode(m_mappingMode
);
1643 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1645 #ifdef __WXMICROWIN__
1646 if (!GetHDC()) return;
1649 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1652 m_logicalOriginX
= x
;
1653 m_logicalOriginY
= y
;
1655 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1658 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1660 #ifdef __WXMICROWIN__
1661 if (!GetHDC()) return;
1664 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1667 m_deviceOriginX
= x
;
1668 m_deviceOriginY
= y
;
1670 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1673 // ---------------------------------------------------------------------------
1674 // coordinates transformations
1675 // ---------------------------------------------------------------------------
1677 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1679 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1682 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1684 // axis orientation is not taken into account for conversion of a distance
1685 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1688 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1690 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1693 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1695 // axis orientation is not taken into account for conversion of a distance
1696 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1699 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1701 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1704 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1706 // axis orientation is not taken into account for conversion of a distance
1707 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1710 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1712 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1715 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1717 // axis orientation is not taken into account for conversion of a distance
1718 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1721 // ---------------------------------------------------------------------------
1723 // ---------------------------------------------------------------------------
1725 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1726 wxCoord width
, wxCoord height
,
1727 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1728 int rop
, bool useMask
,
1729 wxCoord xsrcMask
, wxCoord ysrcMask
)
1731 #ifdef __WXMICROWIN__
1732 if (!GetHDC()) return FALSE
;
1735 wxMask
*mask
= NULL
;
1738 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1739 mask
= bmp
.GetMask();
1741 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1743 // don't give assert here because this would break existing
1744 // programs - just silently ignore useMask parameter
1749 if (xsrcMask
== -1 && ysrcMask
== -1)
1751 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1754 COLORREF old_textground
= ::GetTextColor(GetHdc());
1755 COLORREF old_background
= ::GetBkColor(GetHdc());
1756 if (m_textForegroundColour
.Ok())
1758 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1760 if (m_textBackgroundColour
.Ok())
1762 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1765 DWORD dwRop
= SRCCOPY
;
1768 case wxXOR
: dwRop
= SRCINVERT
; break;
1769 case wxINVERT
: dwRop
= DSTINVERT
; break;
1770 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1771 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1772 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1773 case wxSET
: dwRop
= WHITENESS
; break;
1774 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1775 case wxAND
: dwRop
= SRCAND
; break;
1776 case wxOR
: dwRop
= SRCPAINT
; break;
1777 case wxEQUIV
: dwRop
= 0x00990066; break;
1778 case wxNAND
: dwRop
= 0x007700E6; break;
1779 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1780 case wxCOPY
: dwRop
= SRCCOPY
; break;
1781 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1782 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1783 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1785 wxFAIL_MSG( wxT("unsupported logical function") );
1789 bool success
= FALSE
;
1794 // we want the part of the image corresponding to the mask to be
1795 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1796 // meaning of fg and bg is inverted which corresponds to wxWin notion
1797 // of the mask which is also contrary to the Windows one)
1799 // On some systems, MaskBlt succeeds yet is much much slower
1800 // than the wxWindows fall-back implementation. So we need
1801 // to be able to switch this on and off at runtime.
1802 #if wxUSE_SYSTEM_OPTIONS
1803 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1806 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1807 GetHdcOf(*source
), xsrc
, ysrc
,
1808 (HBITMAP
)mask
->GetMaskBitmap(), xsrcMask
, ysrcMask
,
1809 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1815 // Blit bitmap with mask
1818 HBITMAP buffer_bmap
;
1820 #if wxUSE_DC_CACHEING
1821 // create a temp buffer bitmap and DCs to access it and the mask
1822 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1823 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1825 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1826 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1828 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1831 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1832 #else // !wxUSE_DC_CACHEING
1833 // create a temp buffer bitmap and DCs to access it and the mask
1834 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1835 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1836 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1837 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1838 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1839 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1841 // copy dest to buffer
1842 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1843 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1845 wxLogLastError(wxT("BitBlt"));
1848 // copy src to buffer using selected raster op
1849 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1850 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1852 wxLogLastError(wxT("BitBlt"));
1855 // set masked area in buffer to BLACK (pixel value 0)
1856 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1857 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1858 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1859 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1861 wxLogLastError(wxT("BitBlt"));
1864 // set unmasked area in dest to BLACK
1865 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1866 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1867 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1868 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1870 wxLogLastError(wxT("BitBlt"));
1872 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1873 ::SetTextColor(GetHdc(), prevCol
);
1875 // OR buffer to dest
1876 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1877 (int)width
, (int)height
,
1878 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1881 wxLogLastError(wxT("BitBlt"));
1884 // tidy up temporary DCs and bitmap
1885 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1886 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1888 #if !wxUSE_DC_CACHEING
1890 ::DeleteDC(dc_mask
);
1891 ::DeleteDC(dc_buffer
);
1892 ::DeleteObject(buffer_bmap
);
1897 else // no mask, just BitBlt() it
1899 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1900 (int)width
, (int)height
,
1901 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1904 wxLogLastError(wxT("BitBlt"));
1907 ::SetTextColor(GetHdc(), old_textground
);
1908 ::SetBkColor(GetHdc(), old_background
);
1913 void wxDC::DoGetSize(int *w
, int *h
) const
1915 #ifdef __WXMICROWIN__
1916 if (!GetHDC()) return;
1919 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1920 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1923 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1925 #ifdef __WXMICROWIN__
1926 if (!GetHDC()) return;
1929 // if we implement it in terms of DoGetSize() instead of directly using the
1930 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
1931 // will also work for wxWindowDC and wxClientDC even though their size is
1932 // not the same as the total size of the screen
1933 int wPixels
, hPixels
;
1934 DoGetSize(&wPixels
, &hPixels
);
1938 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1940 wxCHECK_RET( wTotal
, _T("0 width device?") );
1942 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
1947 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1949 wxCHECK_RET( hTotal
, _T("0 height device?") );
1951 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
1955 wxSize
wxDC::GetPPI() const
1957 #ifdef __WXMICROWIN__
1958 if (!GetHDC()) return wxSize();
1961 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1962 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1964 return wxSize(x
, y
);
1967 // For use by wxWindows only, unless custom units are required.
1968 void wxDC::SetLogicalScale(double x
, double y
)
1970 #ifdef __WXMICROWIN__
1971 if (!GetHDC()) return;
1974 m_logicalScaleX
= x
;
1975 m_logicalScaleY
= y
;
1978 #if WXWIN_COMPATIBILITY
1979 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1980 float *descent
, float *externalLeading
,
1981 wxFont
*theFont
, bool use16bit
) const
1983 #ifdef __WXMICROWIN__
1984 if (!GetHDC()) return;
1987 wxCoord x1
, y1
, descent1
, externalLeading1
;
1988 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1991 *descent
= descent1
;
1992 if (externalLeading
)
1993 *externalLeading
= externalLeading1
;
1997 #if wxUSE_DC_CACHEING
2000 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2001 * improve it in due course, either using arrays, or simply storing pointers to one
2002 * entry for the bitmap, and two for the DCs. -- JACS
2005 wxList
wxDC::sm_bitmapCache
;
2006 wxList
wxDC::sm_dcCache
;
2008 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2017 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2026 wxDCCacheEntry::~wxDCCacheEntry()
2029 ::DeleteObject((HBITMAP
) m_bitmap
);
2031 ::DeleteDC((HDC
) m_dc
);
2034 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2036 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2037 wxNode
* node
= sm_bitmapCache
.First();
2040 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2042 if (entry
->m_depth
== depth
)
2044 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2046 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2047 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2048 if ( !entry
->m_bitmap
)
2050 wxLogLastError(wxT("CreateCompatibleBitmap"));
2052 entry
->m_width
= w
; entry
->m_height
= h
;
2058 node
= node
->Next();
2060 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2063 wxLogLastError(wxT("CreateCompatibleBitmap"));
2065 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2066 AddToBitmapCache(entry
);
2070 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2072 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2073 wxNode
* node
= sm_dcCache
.First();
2076 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2078 // Don't return the same one as we already have
2079 if (!notThis
|| (notThis
!= entry
))
2081 if (entry
->m_depth
== depth
)
2087 node
= node
->Next();
2089 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2092 wxLogLastError(wxT("CreateCompatibleDC"));
2094 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2095 AddToDCCache(entry
);
2099 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2101 sm_bitmapCache
.Append(entry
);
2104 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2106 sm_dcCache
.Append(entry
);
2109 void wxDC::ClearCache()
2111 sm_bitmapCache
.DeleteContents(TRUE
);
2112 sm_bitmapCache
.Clear();
2113 sm_bitmapCache
.DeleteContents(FALSE
);
2114 sm_dcCache
.DeleteContents(TRUE
);
2116 sm_dcCache
.DeleteContents(FALSE
);
2119 // Clean up cache at app exit
2120 class wxDCModule
: public wxModule
2123 virtual bool OnInit() { return TRUE
; }
2124 virtual void OnExit() { wxDC::ClearCache(); }
2127 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2130 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2133 // wxUSE_DC_CACHEING