]>
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 /* Quaternary raster codes */
62 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
65 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
67 // ---------------------------------------------------------------------------
69 // ---------------------------------------------------------------------------
71 static const int VIEWPORT_EXTENT
= 1000;
73 static const int MM_POINTS
= 9;
74 static const int MM_METRIC
= 10;
76 // usually this is defined in math.h
78 static const double M_PI
= 3.14159265358979323846;
81 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
82 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
83 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
85 // ----------------------------------------------------------------------------
86 // macros for logical <-> device coords conversion
87 // ----------------------------------------------------------------------------
90 We currently let Windows do all the translations itself so these macros are
91 not really needed (any more) but keep them to enhance readability of the
92 code by allowing to see where are the logical and where are the device
97 #define XLOG2DEV(x) (x)
98 #define YLOG2DEV(y) (y)
101 #define XDEV2LOG(x) (x)
102 #define YDEV2LOG(y) (y)
104 // ---------------------------------------------------------------------------
106 // ---------------------------------------------------------------------------
108 // convert degrees to radians
109 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
111 // ----------------------------------------------------------------------------
113 // ----------------------------------------------------------------------------
115 // instead of duplicating the same code which sets and then restores text
116 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
117 // encapsulate this in a small helper class
119 // wxColourChanger: changes the text colours in the ctor if required and
120 // restores them in the dtor
121 class wxColourChanger
124 wxColourChanger(wxDC
& dc
);
130 COLORREF m_colFgOld
, m_colBgOld
;
135 // this class saves the old stretch blit mode during its life time
136 class StretchBltModeChanger
139 StretchBltModeChanger(HDC hdc
, int mode
)
142 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
144 wxLogLastError(_T("SetStretchBltMode"));
147 ~StretchBltModeChanger()
149 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
150 wxLogLastError(_T("SetStretchBltMode"));
159 // ===========================================================================
161 // ===========================================================================
163 // ----------------------------------------------------------------------------
165 // ----------------------------------------------------------------------------
167 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
169 const wxBrush
& brush
= dc
.GetBrush();
170 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
172 HDC hdc
= GetHdcOf(dc
);
173 m_colFgOld
= ::GetTextColor(hdc
);
174 m_colBgOld
= ::GetBkColor(hdc
);
176 // note that Windows convention is opposite to wxWindows one, this is
177 // why text colour becomes the background one and vice versa
178 const wxColour
& colFg
= dc
.GetTextForeground();
181 ::SetBkColor(hdc
, colFg
.GetPixel());
184 const wxColour
& colBg
= dc
.GetTextBackground();
187 ::SetTextColor(hdc
, colBg
.GetPixel());
191 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
194 // flag which telsl us to undo changes in the dtor
199 // nothing done, nothing to undo
204 wxColourChanger::~wxColourChanger()
208 // restore the colours we changed
209 HDC hdc
= GetHdcOf(m_dc
);
211 ::SetBkMode(hdc
, TRANSPARENT
);
212 ::SetTextColor(hdc
, m_colFgOld
);
213 ::SetBkColor(hdc
, m_colBgOld
);
217 // ---------------------------------------------------------------------------
219 // ---------------------------------------------------------------------------
221 // Default constructor
232 #endif // wxUSE_PALETTE
242 SelectOldObjects(m_hDC
);
244 // if we own the HDC, we delete it, otherwise we just release it
248 ::DeleteDC(GetHdc());
250 else // we don't own our HDC
254 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
258 // Must have been a wxScreenDC
259 ::ReleaseDC((HWND
) NULL
, GetHdc());
265 // This will select current objects out of the DC,
266 // which is what you have to do before deleting the
268 void wxDC::SelectOldObjects(WXHDC dc
)
274 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
275 if (m_selectedBitmap
.Ok())
277 m_selectedBitmap
.SetSelectedInto(NULL
);
283 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
288 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
293 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
300 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
303 #endif // wxUSE_PALETTE
306 m_brush
= wxNullBrush
;
309 m_palette
= wxNullPalette
;
310 #endif // wxUSE_PALETTE
312 m_backgroundBrush
= wxNullBrush
;
313 m_selectedBitmap
= wxNullBitmap
;
316 // ---------------------------------------------------------------------------
318 // ---------------------------------------------------------------------------
320 void wxDC::UpdateClipBox()
322 #ifdef __WXMICROWIN__
323 if (!GetHDC()) return;
327 ::GetClipBox(GetHdc(), &rect
);
329 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
330 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
331 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
332 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
335 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
336 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
338 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
340 #ifdef __WXMICROWIN__
341 if (!GetHdc()) return;
342 #endif // __WXMICROWIN__
344 // note that we combine the new clipping region with the existing one: this
345 // is compatible with what the other ports do and is the documented
346 // behaviour now (starting with 2.3.3)
349 if ( !::GetClipBox(GetHdc(), &rectClip
) )
352 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
353 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
354 rectClip
.right
, rectClip
.bottom
);
356 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
358 ::SelectClipRgn(GetHdc(), hrgnDest
);
361 ::DeleteObject(hrgnClipOld
);
362 ::DeleteObject(hrgnDest
);
364 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
366 wxLogLastError(_T("ExtSelectClipRgn"));
377 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
379 // the region coords are always the device ones, so do the translation
382 // FIXME: possible +/-1 error here, to check!
383 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
385 LogicalToDeviceX(x
+ w
),
386 LogicalToDeviceY(y
+ h
));
389 wxLogLastError(_T("CreateRectRgn"));
393 SetClippingHrgn((WXHRGN
)hrgn
);
395 ::DeleteObject(hrgn
);
399 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
401 SetClippingHrgn(region
.GetHRGN());
404 void wxDC::DestroyClippingRegion()
406 #ifdef __WXMICROWIN__
407 if (!GetHDC()) return;
410 if (m_clipping
&& m_hDC
)
412 // TODO: this should restore the previous clipping region,
413 // so that OnPaint processing works correctly, and the update
414 // clipping region doesn't get destroyed after the first
415 // DestroyClippingRegion.
416 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
417 ::SelectClipRgn(GetHdc(), rgn
);
424 // ---------------------------------------------------------------------------
425 // query capabilities
426 // ---------------------------------------------------------------------------
428 bool wxDC::CanDrawBitmap() const
433 bool wxDC::CanGetTextExtent() const
435 #ifdef __WXMICROWIN__
436 // TODO Extend MicroWindows' GetDeviceCaps function
439 // What sort of display is it?
440 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
442 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
446 int wxDC::GetDepth() const
448 #ifdef __WXMICROWIN__
449 if (!GetHDC()) return 16;
452 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
455 // ---------------------------------------------------------------------------
457 // ---------------------------------------------------------------------------
461 #ifdef __WXMICROWIN__
462 if (!GetHDC()) return;
468 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
472 // No, I think we should simply ignore this if printing on e.g.
474 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
475 if (!m_selectedBitmap
.Ok())
478 rect
.left
= 0; rect
.top
= 0;
479 rect
.right
= m_selectedBitmap
.GetWidth();
480 rect
.bottom
= m_selectedBitmap
.GetHeight();
483 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
485 DWORD colour
= ::GetBkColor(GetHdc());
486 HBRUSH brush
= ::CreateSolidBrush(colour
);
487 ::FillRect(GetHdc(), &rect
, brush
);
488 ::DeleteObject(brush
);
490 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
491 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
493 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
494 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
495 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
496 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
497 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
500 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
502 #ifdef __WXMICROWIN__
503 if (!GetHDC()) return FALSE
;
506 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
508 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
509 : FLOODFILLBORDER
) ) ;
512 // quoting from the MSDN docs:
514 // Following are some of the reasons this function might fail:
516 // * The filling could not be completed.
517 // * The specified point has the boundary color specified by the
518 // crColor parameter (if FLOODFILLBORDER was requested).
519 // * The specified point does not have the color specified by
520 // crColor (if FLOODFILLSURFACE was requested)
521 // * The point is outside the clipping region that is, it is not
522 // visible on the device.
524 wxLogLastError(wxT("ExtFloodFill"));
527 CalcBoundingBox(x
, y
);
532 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
534 #ifdef __WXMICROWIN__
535 if (!GetHDC()) return FALSE
;
538 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
540 // get the color of the pixel
541 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
543 wxRGBToColour(*col
, pixelcolor
);
548 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
550 #ifdef __WXMICROWIN__
551 if (!GetHDC()) return;
554 wxCoord x1
= x
-VIEWPORT_EXTENT
;
555 wxCoord y1
= y
-VIEWPORT_EXTENT
;
556 wxCoord x2
= x
+VIEWPORT_EXTENT
;
557 wxCoord y2
= y
+VIEWPORT_EXTENT
;
559 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
560 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
562 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
563 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
565 CalcBoundingBox(x1
, y1
);
566 CalcBoundingBox(x2
, y2
);
569 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
571 #ifdef __WXMICROWIN__
572 if (!GetHDC()) return;
575 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
576 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
578 CalcBoundingBox(x1
, y1
);
579 CalcBoundingBox(x2
, y2
);
582 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
583 // and ending at (x2, y2)
584 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
585 wxCoord x2
, wxCoord y2
,
586 wxCoord xc
, wxCoord yc
)
588 #ifdef __WXMICROWIN__
589 if (!GetHDC()) return;
592 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
596 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
597 wxCoord r
= (wxCoord
)radius
;
599 // treat the special case of full circle separately
600 if ( x1
== x2
&& y1
== y2
)
602 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
606 wxCoord xx1
= XLOG2DEV(x1
);
607 wxCoord yy1
= YLOG2DEV(y1
);
608 wxCoord xx2
= XLOG2DEV(x2
);
609 wxCoord yy2
= YLOG2DEV(y2
);
610 wxCoord xxc
= XLOG2DEV(xc
);
611 wxCoord yyc
= YLOG2DEV(yc
);
612 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
614 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
615 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
616 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
617 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
619 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
621 // Have to add 1 to bottom-right corner of rectangle
622 // to make semi-circles look right (crooked line otherwise).
623 // Unfortunately this is not a reliable method, depends
624 // on the size of shape.
625 // TODO: figure out why this happens!
626 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
630 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
633 CalcBoundingBox(xc
- r
, yc
- r
);
634 CalcBoundingBox(xc
+ r
, yc
+ r
);
637 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
638 wxCoord width
, wxCoord height
)
640 #ifdef __WXMICROWIN__
641 if (!GetHDC()) return;
644 wxCoord x2
= x1
+ width
,
647 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__)
654 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
656 // In WIN16, draw a cross
657 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
658 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
659 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
660 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
661 ::SetROP2(GetHdc(), R2_COPYPEN
);
662 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
663 MoveToEx(GetHdc(), x1
, y1
, NULL
);
664 LineTo(GetHdc(), x2
, y2
);
665 MoveToEx(GetHdc(), x2
, y1
, NULL
);
666 LineTo(GetHdc(), x1
, y2
);
667 ::SelectObject(GetHdc(), hPenOld
);
668 ::SelectObject(GetHdc(), hBrushOld
);
669 ::DeleteObject(blackPen
);
672 CalcBoundingBox(x1
, y1
);
673 CalcBoundingBox(x2
, y2
);
676 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
678 #ifdef __WXMICROWIN__
679 if (!GetHDC()) return;
682 COLORREF color
= 0x00ffffff;
685 color
= m_pen
.GetColour().GetPixel();
688 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
690 CalcBoundingBox(x
, y
);
693 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
695 #ifdef __WXMICROWIN__
696 if (!GetHDC()) return;
699 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
701 // Do things less efficiently if we have offsets
702 if (xoffset
!= 0 || yoffset
!= 0)
704 POINT
*cpoints
= new POINT
[n
];
706 for (i
= 0; i
< n
; i
++)
708 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
709 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
711 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
713 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
714 (void)Polygon(GetHdc(), cpoints
, n
);
715 SetPolyFillMode(GetHdc(),prev
);
721 for (i
= 0; i
< n
; i
++)
722 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
724 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
725 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
726 SetPolyFillMode(GetHdc(),prev
);
730 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
732 #ifdef __WXMICROWIN__
733 if (!GetHDC()) return;
736 // Do things less efficiently if we have offsets
737 if (xoffset
!= 0 || yoffset
!= 0)
739 POINT
*cpoints
= new POINT
[n
];
741 for (i
= 0; i
< n
; i
++)
743 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
744 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
746 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
748 (void)Polyline(GetHdc(), cpoints
, n
);
754 for (i
= 0; i
< n
; i
++)
755 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
757 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
761 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
763 #ifdef __WXMICROWIN__
764 if (!GetHDC()) return;
767 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
769 wxCoord x2
= x
+ width
;
770 wxCoord y2
= y
+ height
;
772 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
775 rect
.left
= XLOG2DEV(x
);
776 rect
.top
= YLOG2DEV(y
);
777 rect
.right
= XLOG2DEV(x2
);
778 rect
.bottom
= YLOG2DEV(y2
);
779 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
783 // Windows draws the filled rectangles without outline (i.e. drawn with a
784 // transparent pen) one pixel smaller in both directions and we want them
785 // to have the same size regardless of which pen is used - adjust
787 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
788 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
794 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
798 CalcBoundingBox(x
, y
);
799 CalcBoundingBox(x2
, y2
);
802 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
804 #ifdef __WXMICROWIN__
805 if (!GetHDC()) return;
808 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
810 // Now, a negative radius value is interpreted to mean
811 // 'the proportion of the smallest X or Y dimension'
815 double smallest
= 0.0;
820 radius
= (- radius
* smallest
);
823 wxCoord x2
= (x
+width
);
824 wxCoord y2
= (y
+height
);
826 // Windows draws the filled rectangles without outline (i.e. drawn with a
827 // transparent pen) one pixel smaller in both directions and we want them
828 // to have the same size regardless of which pen is used - adjust
829 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
835 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
836 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
838 CalcBoundingBox(x
, y
);
839 CalcBoundingBox(x2
, y2
);
842 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
844 #ifdef __WXMICROWIN__
845 if (!GetHDC()) return;
848 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
850 wxCoord x2
= (x
+width
);
851 wxCoord y2
= (y
+height
);
853 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
855 CalcBoundingBox(x
, y
);
856 CalcBoundingBox(x2
, y2
);
859 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
860 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
862 #ifdef __WXMICROWIN__
863 if (!GetHDC()) return;
866 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
871 int rx1
= XLOG2DEV(x
+w
/2);
872 int ry1
= YLOG2DEV(y
+h
/2);
879 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
880 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
881 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
882 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
884 // draw pie with NULL_PEN first and then outline otherwise a line is
885 // drawn from the start and end points to the centre
886 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
889 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
894 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
895 rx1
, ry1
-1, rx2
, ry2
-1);
898 ::SelectObject(GetHdc(), hpenOld
);
900 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
903 CalcBoundingBox(x
, y
);
904 CalcBoundingBox(x2
, y2
);
907 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
909 #ifdef __WXMICROWIN__
910 if (!GetHDC()) return;
913 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
916 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
918 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
921 CalcBoundingBox(x
, y
);
922 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
925 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
927 #ifdef __WXMICROWIN__
928 if (!GetHDC()) return;
931 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
933 int width
= bmp
.GetWidth(),
934 height
= bmp
.GetHeight();
936 HBITMAP hbmpMask
= 0;
940 #endif // wxUSE_PALETTE
944 wxMask
*mask
= bmp
.GetMask();
946 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
950 // don't give assert here because this would break existing
951 // programs - just silently ignore useMask parameter
958 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
960 // On some systems, MaskBlt succeeds yet is much much slower
961 // than the wxWindows fall-back implementation. So we need
962 // to be able to switch this on and off at runtime.
964 #if wxUSE_SYSTEM_OPTIONS
965 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
969 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
970 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
972 wxPalette
*pal
= bmp
.GetPalette();
973 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
975 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
976 ::RealizePalette(hdcMem
);
978 #endif // wxUSE_PALETTE
980 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
983 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
987 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
988 #endif // wxUSE_PALETTE
990 ::SelectObject(hdcMem
, hOldBitmap
);
997 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1000 memDC
.SelectObject(bmp
);
1002 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1004 memDC
.SelectObject(wxNullBitmap
);
1007 else // no mask, just use BitBlt()
1010 HDC memdc
= ::CreateCompatibleDC( cdc
);
1011 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1013 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1015 COLORREF old_textground
= ::GetTextColor(GetHdc());
1016 COLORREF old_background
= ::GetBkColor(GetHdc());
1017 if (m_textForegroundColour
.Ok())
1019 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1021 if (m_textBackgroundColour
.Ok())
1023 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1027 wxPalette
*pal
= bmp
.GetPalette();
1028 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1030 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1031 ::RealizePalette(memdc
);
1033 #endif // wxUSE_PALETTE
1035 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1036 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1040 ::SelectPalette(memdc
, oldPal
, FALSE
);
1041 #endif // wxUSE_PALETTE
1043 ::SelectObject( memdc
, hOldBitmap
);
1044 ::DeleteDC( memdc
);
1046 ::SetTextColor(GetHdc(), old_textground
);
1047 ::SetBkColor(GetHdc(), old_background
);
1051 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1053 #ifdef __WXMICROWIN__
1054 if (!GetHDC()) return;
1057 DrawAnyText(text
, x
, y
);
1059 // update the bounding box
1060 CalcBoundingBox(x
, y
);
1063 GetTextExtent(text
, &w
, &h
);
1064 CalcBoundingBox(x
+ w
, y
+ h
);
1067 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1069 #ifdef __WXMICROWIN__
1070 if (!GetHDC()) return;
1073 // prepare for drawing the text
1074 if ( m_textForegroundColour
.Ok() )
1075 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1077 DWORD old_background
= 0;
1078 if ( m_textBackgroundColour
.Ok() )
1080 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1083 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1086 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1087 text
.c_str(), text
.length()) == 0 )
1089 wxLogLastError(wxT("TextOut"));
1092 // restore the old parameters (text foreground colour may be left because
1093 // it never is set to anything else, but background should remain
1094 // transparent even if we just drew an opaque string)
1095 if ( m_textBackgroundColour
.Ok() )
1096 (void)SetBkColor(GetHdc(), old_background
);
1098 SetBkMode(GetHdc(), TRANSPARENT
);
1101 void wxDC::DoDrawRotatedText(const wxString
& text
,
1102 wxCoord x
, wxCoord y
,
1105 #ifdef __WXMICROWIN__
1106 if (!GetHDC()) return;
1109 // we test that we have some font because otherwise we should still use the
1110 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1111 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1112 // font for drawing rotated fonts unfortunately)
1113 if ( (angle
== 0.0) && m_font
.Ok() )
1115 DoDrawText(text
, x
, y
);
1117 #ifndef __WXMICROWIN__
1120 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1121 // because it's not TrueType and so can't have non zero
1122 // orientation/escapement under Win9x
1123 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1124 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1126 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1128 wxLogLastError(wxT("GetObject(hfont)"));
1131 // GDI wants the angle in tenth of degree
1132 long angle10
= (long)(angle
* 10);
1133 lf
.lfEscapement
= angle10
;
1134 lf
. lfOrientation
= angle10
;
1136 hfont
= ::CreateFontIndirect(&lf
);
1139 wxLogLastError(wxT("CreateFont"));
1143 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1145 DrawAnyText(text
, x
, y
);
1147 (void)::SelectObject(GetHdc(), hfontOld
);
1148 (void)::DeleteObject(hfont
);
1151 // call the bounding box by adding all four vertices of the rectangle
1152 // containing the text to it (simpler and probably not slower than
1153 // determining which of them is really topmost/leftmost/...)
1155 GetTextExtent(text
, &w
, &h
);
1157 double rad
= DegToRad(angle
);
1159 // "upper left" and "upper right"
1160 CalcBoundingBox(x
, y
);
1161 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1163 // "bottom left" and "bottom right"
1164 x
+= (wxCoord
)(h
*sin(rad
));
1165 y
+= (wxCoord
)(h
*cos(rad
));
1166 CalcBoundingBox(x
, y
);
1167 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1172 // ---------------------------------------------------------------------------
1174 // ---------------------------------------------------------------------------
1178 void wxDC::DoSelectPalette(bool realize
)
1180 #ifdef __WXMICROWIN__
1181 if (!GetHDC()) return;
1184 // Set the old object temporarily, in case the assignment deletes an object
1185 // that's not yet selected out.
1188 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1192 if ( m_palette
.Ok() )
1194 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1195 GetHpaletteOf(m_palette
),
1198 m_oldPalette
= (WXHPALETTE
) oldPal
;
1201 ::RealizePalette(GetHdc());
1205 void wxDC::SetPalette(const wxPalette
& palette
)
1209 m_palette
= palette
;
1210 DoSelectPalette(TRUE
);
1214 void wxDC::InitializePalette()
1216 if ( wxDisplayDepth() <= 8 )
1218 // look for any window or parent that has a custom palette. If any has
1219 // one then we need to use it in drawing operations
1220 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1222 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1223 if ( m_hasCustomPalette
)
1225 m_palette
= win
->GetPalette();
1227 // turn on MSW translation for this palette
1233 #endif // wxUSE_PALETTE
1235 void wxDC::SetFont(const wxFont
& the_font
)
1237 #ifdef __WXMICROWIN__
1238 if (!GetHDC()) return;
1241 // Set the old object temporarily, in case the assignment deletes an object
1242 // that's not yet selected out.
1245 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1254 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1258 if (m_font
.Ok() && m_font
.GetResourceHandle())
1260 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1261 if (f
== (HFONT
) NULL
)
1263 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1266 m_oldFont
= (WXHFONT
) f
;
1270 void wxDC::SetPen(const wxPen
& pen
)
1272 #ifdef __WXMICROWIN__
1273 if (!GetHDC()) return;
1276 // Set the old object temporarily, in case the assignment deletes an object
1277 // that's not yet selected out.
1280 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1289 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1295 if (m_pen
.GetResourceHandle())
1297 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1299 m_oldPen
= (WXHPEN
) p
;
1304 void wxDC::SetBrush(const wxBrush
& brush
)
1306 #ifdef __WXMICROWIN__
1307 if (!GetHDC()) return;
1310 // Set the old object temporarily, in case the assignment deletes an object
1311 // that's not yet selected out.
1314 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1323 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1329 // to make sure the brush is alligned with the logical coordinates
1330 wxBitmap
*stipple
= m_brush
.GetStipple();
1331 if ( stipple
&& stipple
->Ok() )
1334 ::SetBrushOrgEx(GetHdc(),
1335 m_deviceOriginX
% stipple
->GetWidth(),
1336 m_deviceOriginY
% stipple
->GetHeight(),
1337 NULL
); // don't need previous brush origin
1339 ::SetBrushOrg(GetHdc(),
1340 m_deviceOriginX
% stipple
->GetWidth(),
1341 m_deviceOriginY
% stipple
->GetHeight());
1345 if ( m_brush
.GetResourceHandle() )
1348 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1350 m_oldBrush
= (WXHBRUSH
) b
;
1355 void wxDC::SetBackground(const wxBrush
& brush
)
1357 #ifdef __WXMICROWIN__
1358 if (!GetHDC()) return;
1361 m_backgroundBrush
= brush
;
1363 if (!m_backgroundBrush
.Ok())
1368 bool customColours
= TRUE
;
1369 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1370 // change background colours from the control-panel specified colours.
1371 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1372 customColours
= FALSE
;
1376 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1378 m_canvas
->SetTransparent(TRUE
);
1382 // New behaviour, 10/2/99: setting the background brush of a DC
1383 // doesn't affect the window background colour. However,
1384 // I'm leaving in the transparency setting because it's needed by
1385 // various controls (e.g. wxStaticText) to determine whether to draw
1386 // transparently or not. TODO: maybe this should be a new function
1387 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1389 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1390 m_canvas
->SetTransparent(FALSE
);
1394 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1396 (void)SetBkColor(GetHdc(), new_color
);
1400 void wxDC::SetBackgroundMode(int mode
)
1402 #ifdef __WXMICROWIN__
1403 if (!GetHDC()) return;
1406 m_backgroundMode
= mode
;
1408 // SetBackgroundColour now only refers to text background
1409 // and m_backgroundMode is used there
1412 void wxDC::SetLogicalFunction(int function
)
1414 #ifdef __WXMICROWIN__
1415 if (!GetHDC()) return;
1418 m_logicalFunction
= function
;
1423 void wxDC::SetRop(WXHDC dc
)
1425 if ( !dc
|| m_logicalFunction
< 0 )
1430 switch (m_logicalFunction
)
1432 case wxCLEAR
: rop
= R2_BLACK
; break;
1433 case wxXOR
: rop
= R2_XORPEN
; break;
1434 case wxINVERT
: rop
= R2_NOT
; break;
1435 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1436 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1437 case wxCOPY
: rop
= R2_COPYPEN
; break;
1438 case wxAND
: rop
= R2_MASKPEN
; break;
1439 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1440 case wxNO_OP
: rop
= R2_NOP
; break;
1441 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1442 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1443 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1444 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1445 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1446 case wxOR
: rop
= R2_MERGEPEN
; break;
1447 case wxSET
: rop
= R2_WHITE
; break;
1450 wxFAIL_MSG( wxT("unsupported logical function") );
1454 SetROP2(GetHdc(), rop
);
1457 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1459 // We might be previewing, so return TRUE to let it continue.
1467 void wxDC::StartPage()
1471 void wxDC::EndPage()
1475 // ---------------------------------------------------------------------------
1477 // ---------------------------------------------------------------------------
1479 wxCoord
wxDC::GetCharHeight() const
1481 #ifdef __WXMICROWIN__
1482 if (!GetHDC()) return 0;
1485 TEXTMETRIC lpTextMetric
;
1487 GetTextMetrics(GetHdc(), &lpTextMetric
);
1489 return lpTextMetric
.tmHeight
;
1492 wxCoord
wxDC::GetCharWidth() const
1494 #ifdef __WXMICROWIN__
1495 if (!GetHDC()) return 0;
1498 TEXTMETRIC lpTextMetric
;
1500 GetTextMetrics(GetHdc(), &lpTextMetric
);
1502 return lpTextMetric
.tmAveCharWidth
;
1505 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1506 wxCoord
*descent
, wxCoord
*externalLeading
,
1509 #ifdef __WXMICROWIN__
1514 if (descent
) *descent
= 0;
1515 if (externalLeading
) *externalLeading
= 0;
1518 #endif // __WXMICROWIN__
1523 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1525 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1527 else // don't change the font
1535 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1536 GetTextMetrics(GetHdc(), &tm
);
1543 *descent
= tm
.tmDescent
;
1544 if (externalLeading
)
1545 *externalLeading
= tm
.tmExternalLeading
;
1549 ::SelectObject(GetHdc(), hfontOld
);
1553 void wxDC::SetMapMode(int mode
)
1555 #ifdef __WXMICROWIN__
1556 if (!GetHDC()) return;
1559 m_mappingMode
= mode
;
1561 if ( mode
== wxMM_TEXT
)
1564 m_logicalScaleY
= 1.0;
1566 else // need to do some calculations
1568 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1569 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1570 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1571 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1573 if ( (mm_width
== 0) || (mm_height
== 0) )
1575 // we can't calculate mm2pixels[XY] then!
1579 double mm2pixelsX
= pixel_width
/ mm_width
,
1580 mm2pixelsY
= pixel_height
/ mm_height
;
1585 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1586 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1590 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1591 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1595 m_logicalScaleX
= mm2pixelsX
;
1596 m_logicalScaleY
= mm2pixelsY
;
1600 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1601 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1605 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1609 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1610 // cases we could do with MM_TEXT and in the remaining 0.9% with
1611 // MM_ISOTROPIC (TODO!)
1612 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1614 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1615 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1617 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1618 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1620 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1621 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1624 void wxDC::SetUserScale(double x
, double y
)
1626 #ifdef __WXMICROWIN__
1627 if (!GetHDC()) return;
1630 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1636 SetMapMode(m_mappingMode
);
1639 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1641 #ifdef __WXMICROWIN__
1642 if (!GetHDC()) return;
1645 int signX
= xLeftRight
? 1 : -1,
1646 signY
= yBottomUp
? -1 : 1;
1648 if ( signX
!= m_signX
|| signY
!= m_signY
)
1653 SetMapMode(m_mappingMode
);
1657 void wxDC::SetSystemScale(double x
, double y
)
1659 #ifdef __WXMICROWIN__
1660 if (!GetHDC()) return;
1663 if ( x
== m_scaleX
&& y
== m_scaleY
)
1669 SetMapMode(m_mappingMode
);
1672 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1674 #ifdef __WXMICROWIN__
1675 if (!GetHDC()) return;
1678 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1681 m_logicalOriginX
= x
;
1682 m_logicalOriginY
= y
;
1684 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1687 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1689 #ifdef __WXMICROWIN__
1690 if (!GetHDC()) return;
1693 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1696 m_deviceOriginX
= x
;
1697 m_deviceOriginY
= y
;
1699 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1702 // ---------------------------------------------------------------------------
1703 // coordinates transformations
1704 // ---------------------------------------------------------------------------
1706 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1708 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1711 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1713 // axis orientation is not taken into account for conversion of a distance
1714 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1717 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1719 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1722 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1724 // axis orientation is not taken into account for conversion of a distance
1725 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1728 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1730 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1733 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1735 // axis orientation is not taken into account for conversion of a distance
1736 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1739 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1741 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1744 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1746 // axis orientation is not taken into account for conversion of a distance
1747 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1750 // ---------------------------------------------------------------------------
1752 // ---------------------------------------------------------------------------
1754 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1755 wxCoord width
, wxCoord height
,
1756 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1757 int rop
, bool useMask
,
1758 wxCoord xsrcMask
, wxCoord ysrcMask
)
1760 #ifdef __WXMICROWIN__
1761 if (!GetHDC()) return FALSE
;
1764 wxMask
*mask
= NULL
;
1767 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1768 mask
= bmp
.GetMask();
1770 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1772 // don't give assert here because this would break existing
1773 // programs - just silently ignore useMask parameter
1778 if (xsrcMask
== -1 && ysrcMask
== -1)
1780 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1783 COLORREF old_textground
= ::GetTextColor(GetHdc());
1784 COLORREF old_background
= ::GetBkColor(GetHdc());
1785 if (m_textForegroundColour
.Ok())
1787 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1789 if (m_textBackgroundColour
.Ok())
1791 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1794 DWORD dwRop
= SRCCOPY
;
1797 case wxXOR
: dwRop
= SRCINVERT
; break;
1798 case wxINVERT
: dwRop
= DSTINVERT
; break;
1799 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1800 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1801 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1802 case wxSET
: dwRop
= WHITENESS
; break;
1803 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1804 case wxAND
: dwRop
= SRCAND
; break;
1805 case wxOR
: dwRop
= SRCPAINT
; break;
1806 case wxEQUIV
: dwRop
= 0x00990066; break;
1807 case wxNAND
: dwRop
= 0x007700E6; break;
1808 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1809 case wxCOPY
: dwRop
= SRCCOPY
; break;
1810 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1811 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1812 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1814 wxFAIL_MSG( wxT("unsupported logical function") );
1818 bool success
= FALSE
;
1823 // we want the part of the image corresponding to the mask to be
1824 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1825 // meaning of fg and bg is inverted which corresponds to wxWin notion
1826 // of the mask which is also contrary to the Windows one)
1828 // On some systems, MaskBlt succeeds yet is much much slower
1829 // than the wxWindows fall-back implementation. So we need
1830 // to be able to switch this on and off at runtime.
1831 #if wxUSE_SYSTEM_OPTIONS
1832 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1838 xdest
, ydest
, width
, height
,
1841 (HBITMAP
)mask
->GetMaskBitmap(),
1843 MAKEROP4(dwRop
, DSTCOPY
)
1850 // Blit bitmap with mask
1853 HBITMAP buffer_bmap
;
1855 #if wxUSE_DC_CACHEING
1856 // create a temp buffer bitmap and DCs to access it and the mask
1857 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1858 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1860 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1861 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1863 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1866 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1867 #else // !wxUSE_DC_CACHEING
1868 // create a temp buffer bitmap and DCs to access it and the mask
1869 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1870 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1871 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1872 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1873 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1874 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1876 // copy dest to buffer
1877 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1878 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1880 wxLogLastError(wxT("BitBlt"));
1883 // copy src to buffer using selected raster op
1884 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1885 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1887 wxLogLastError(wxT("BitBlt"));
1890 // set masked area in buffer to BLACK (pixel value 0)
1891 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1892 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1893 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1894 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1896 wxLogLastError(wxT("BitBlt"));
1899 // set unmasked area in dest to BLACK
1900 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1901 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1902 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1903 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1905 wxLogLastError(wxT("BitBlt"));
1907 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1908 ::SetTextColor(GetHdc(), prevCol
);
1910 // OR buffer to dest
1911 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1912 (int)width
, (int)height
,
1913 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1916 wxLogLastError(wxT("BitBlt"));
1919 // tidy up temporary DCs and bitmap
1920 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1921 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1923 #if !wxUSE_DC_CACHEING
1925 ::DeleteDC(dc_mask
);
1926 ::DeleteDC(dc_buffer
);
1927 ::DeleteObject(buffer_bmap
);
1932 else // no mask, just BitBlt() it
1934 // use StretchBlt() if available
1935 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS
) & RC_STRETCHBLT
)
1937 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
1939 success
= ::StretchBlt
1942 xdest
, ydest
, width
, height
,
1944 xsrc
, ysrc
, width
, height
,
1954 (int)width
, (int)height
,
1963 wxLogLastError(wxT("BitBlt/StretchBlt"));
1967 ::SetTextColor(GetHdc(), old_textground
);
1968 ::SetBkColor(GetHdc(), old_background
);
1973 void wxDC::DoGetSize(int *w
, int *h
) const
1975 #ifdef __WXMICROWIN__
1976 if (!GetHDC()) return;
1979 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1980 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1983 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1985 #ifdef __WXMICROWIN__
1986 if (!GetHDC()) return;
1989 // if we implement it in terms of DoGetSize() instead of directly using the
1990 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
1991 // will also work for wxWindowDC and wxClientDC even though their size is
1992 // not the same as the total size of the screen
1993 int wPixels
, hPixels
;
1994 DoGetSize(&wPixels
, &hPixels
);
1998 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2000 wxCHECK_RET( wTotal
, _T("0 width device?") );
2002 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2007 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2009 wxCHECK_RET( hTotal
, _T("0 height device?") );
2011 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2015 wxSize
wxDC::GetPPI() const
2017 #ifdef __WXMICROWIN__
2018 if (!GetHDC()) return wxSize();
2021 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2022 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2024 return wxSize(x
, y
);
2027 // For use by wxWindows only, unless custom units are required.
2028 void wxDC::SetLogicalScale(double x
, double y
)
2030 #ifdef __WXMICROWIN__
2031 if (!GetHDC()) return;
2034 m_logicalScaleX
= x
;
2035 m_logicalScaleY
= y
;
2038 #if wxUSE_DC_CACHEING
2041 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2042 * improve it in due course, either using arrays, or simply storing pointers to one
2043 * entry for the bitmap, and two for the DCs. -- JACS
2046 wxList
wxDC::sm_bitmapCache
;
2047 wxList
wxDC::sm_dcCache
;
2049 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2058 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2067 wxDCCacheEntry::~wxDCCacheEntry()
2070 ::DeleteObject((HBITMAP
) m_bitmap
);
2072 ::DeleteDC((HDC
) m_dc
);
2075 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2077 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2078 wxNode
* node
= sm_bitmapCache
.First();
2081 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2083 if (entry
->m_depth
== depth
)
2085 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2087 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2088 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2089 if ( !entry
->m_bitmap
)
2091 wxLogLastError(wxT("CreateCompatibleBitmap"));
2093 entry
->m_width
= w
; entry
->m_height
= h
;
2099 node
= node
->Next();
2101 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2104 wxLogLastError(wxT("CreateCompatibleBitmap"));
2106 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2107 AddToBitmapCache(entry
);
2111 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2113 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2114 wxNode
* node
= sm_dcCache
.First();
2117 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2119 // Don't return the same one as we already have
2120 if (!notThis
|| (notThis
!= entry
))
2122 if (entry
->m_depth
== depth
)
2128 node
= node
->Next();
2130 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2133 wxLogLastError(wxT("CreateCompatibleDC"));
2135 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2136 AddToDCCache(entry
);
2140 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2142 sm_bitmapCache
.Append(entry
);
2145 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2147 sm_dcCache
.Append(entry
);
2150 void wxDC::ClearCache()
2152 sm_dcCache
.DeleteContents(TRUE
);
2154 sm_dcCache
.DeleteContents(FALSE
);
2155 sm_bitmapCache
.DeleteContents(TRUE
);
2156 sm_bitmapCache
.Clear();
2157 sm_bitmapCache
.DeleteContents(FALSE
);
2160 // Clean up cache at app exit
2161 class wxDCModule
: public wxModule
2164 virtual bool OnInit() { return TRUE
; }
2165 virtual void OnExit() { wxDC::ClearCache(); }
2168 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2171 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2174 // wxUSE_DC_CACHEING