]>
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 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
473 #ifdef __WXMICROWIN__
474 if (!GetHDC()) return;
477 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
479 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
482 // quoting from the MSDN docs:
484 // Following are some of the reasons this function might fail:
486 // * The filling could not be completed.
487 // * The specified point has the boundary color specified by the
488 // crColor parameter (if FLOODFILLBORDER was requested).
489 // * The specified point does not have the color specified by
490 // crColor (if FLOODFILLSURFACE was requested)
491 // * The point is outside the clipping region that is, it is not
492 // visible on the device.
494 wxLogLastError(wxT("ExtFloodFill"));
497 CalcBoundingBox(x
, y
);
500 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
502 #ifdef __WXMICROWIN__
503 if (!GetHDC()) return FALSE
;
506 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
508 // get the color of the pixel
509 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
511 wxRGBToColour(*col
, pixelcolor
);
516 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
518 #ifdef __WXMICROWIN__
519 if (!GetHDC()) return;
522 wxCoord x1
= x
-VIEWPORT_EXTENT
;
523 wxCoord y1
= y
-VIEWPORT_EXTENT
;
524 wxCoord x2
= x
+VIEWPORT_EXTENT
;
525 wxCoord y2
= y
+VIEWPORT_EXTENT
;
527 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
528 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
530 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
531 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
533 CalcBoundingBox(x1
, y1
);
534 CalcBoundingBox(x2
, y2
);
537 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
539 #ifdef __WXMICROWIN__
540 if (!GetHDC()) return;
543 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
544 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
546 CalcBoundingBox(x1
, y1
);
547 CalcBoundingBox(x2
, y2
);
550 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
551 // and ending at (x2, y2)
552 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
553 wxCoord x2
, wxCoord y2
,
554 wxCoord xc
, wxCoord yc
)
556 #ifdef __WXMICROWIN__
557 if (!GetHDC()) return;
560 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
564 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
565 wxCoord r
= (wxCoord
)radius
;
567 // treat the special case of full circle separately
568 if ( x1
== x2
&& y1
== y2
)
570 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
574 wxCoord xx1
= XLOG2DEV(x1
);
575 wxCoord yy1
= YLOG2DEV(y1
);
576 wxCoord xx2
= XLOG2DEV(x2
);
577 wxCoord yy2
= YLOG2DEV(y2
);
578 wxCoord xxc
= XLOG2DEV(xc
);
579 wxCoord yyc
= YLOG2DEV(yc
);
580 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
582 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
583 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
584 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
585 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
587 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
589 // Have to add 1 to bottom-right corner of rectangle
590 // to make semi-circles look right (crooked line otherwise).
591 // Unfortunately this is not a reliable method, depends
592 // on the size of shape.
593 // TODO: figure out why this happens!
594 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
598 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
601 CalcBoundingBox(xc
- r
, yc
- r
);
602 CalcBoundingBox(xc
+ r
, yc
+ r
);
605 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
606 wxCoord width
, wxCoord height
)
608 #ifdef __WXMICROWIN__
609 if (!GetHDC()) return;
612 wxCoord x2
= x1
+ width
,
615 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__)
622 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
624 // In WIN16, draw a cross
625 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
626 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
627 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
628 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
629 ::SetROP2(GetHdc(), R2_COPYPEN
);
630 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
631 MoveToEx(GetHdc(), x1
, y1
, NULL
);
632 LineTo(GetHdc(), x2
, y2
);
633 MoveToEx(GetHdc(), x2
, y1
, NULL
);
634 LineTo(GetHdc(), x1
, y2
);
635 ::SelectObject(GetHdc(), hPenOld
);
636 ::SelectObject(GetHdc(), hBrushOld
);
637 ::DeleteObject(blackPen
);
640 CalcBoundingBox(x1
, y1
);
641 CalcBoundingBox(x2
, y2
);
644 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
646 #ifdef __WXMICROWIN__
647 if (!GetHDC()) return;
650 COLORREF color
= 0x00ffffff;
653 color
= m_pen
.GetColour().GetPixel();
656 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
658 CalcBoundingBox(x
, y
);
661 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
663 #ifdef __WXMICROWIN__
664 if (!GetHDC()) return;
667 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
669 // Do things less efficiently if we have offsets
670 if (xoffset
!= 0 || yoffset
!= 0)
672 POINT
*cpoints
= new POINT
[n
];
674 for (i
= 0; i
< n
; i
++)
676 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
677 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
679 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
681 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
682 (void)Polygon(GetHdc(), cpoints
, n
);
683 SetPolyFillMode(GetHdc(),prev
);
689 for (i
= 0; i
< n
; i
++)
690 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
692 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
693 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
694 SetPolyFillMode(GetHdc(),prev
);
698 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
700 #ifdef __WXMICROWIN__
701 if (!GetHDC()) return;
704 // Do things less efficiently if we have offsets
705 if (xoffset
!= 0 || yoffset
!= 0)
707 POINT
*cpoints
= new POINT
[n
];
709 for (i
= 0; i
< n
; i
++)
711 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
712 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
714 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
716 (void)Polyline(GetHdc(), cpoints
, n
);
722 for (i
= 0; i
< n
; i
++)
723 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
725 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
729 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
731 #ifdef __WXMICROWIN__
732 if (!GetHDC()) return;
735 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
737 wxCoord x2
= x
+ width
;
738 wxCoord y2
= y
+ height
;
740 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
743 rect
.left
= XLOG2DEV(x
);
744 rect
.top
= YLOG2DEV(y
);
745 rect
.right
= XLOG2DEV(x2
);
746 rect
.bottom
= YLOG2DEV(y2
);
747 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
751 // Windows draws the filled rectangles without outline (i.e. drawn with a
752 // transparent pen) one pixel smaller in both directions and we want them
753 // to have the same size regardless of which pen is used - adjust
755 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
756 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
762 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
766 CalcBoundingBox(x
, y
);
767 CalcBoundingBox(x2
, y2
);
770 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
772 #ifdef __WXMICROWIN__
773 if (!GetHDC()) return;
776 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
778 // Now, a negative radius value is interpreted to mean
779 // 'the proportion of the smallest X or Y dimension'
783 double smallest
= 0.0;
788 radius
= (- radius
* smallest
);
791 wxCoord x2
= (x
+width
);
792 wxCoord y2
= (y
+height
);
794 // Windows draws the filled rectangles without outline (i.e. drawn with a
795 // transparent pen) one pixel smaller in both directions and we want them
796 // to have the same size regardless of which pen is used - adjust
797 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
803 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
804 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
806 CalcBoundingBox(x
, y
);
807 CalcBoundingBox(x2
, y2
);
810 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
812 #ifdef __WXMICROWIN__
813 if (!GetHDC()) return;
816 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
818 wxCoord x2
= (x
+width
);
819 wxCoord y2
= (y
+height
);
821 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
823 CalcBoundingBox(x
, y
);
824 CalcBoundingBox(x2
, y2
);
827 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
828 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
830 #ifdef __WXMICROWIN__
831 if (!GetHDC()) return;
834 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
839 int rx1
= XLOG2DEV(x
+w
/2);
840 int ry1
= YLOG2DEV(y
+h
/2);
847 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
848 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
849 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
850 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
852 // draw pie with NULL_PEN first and then outline otherwise a line is
853 // drawn from the start and end points to the centre
854 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
857 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
862 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
863 rx1
, ry1
-1, rx2
, ry2
-1);
866 ::SelectObject(GetHdc(), hpenOld
);
868 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
871 CalcBoundingBox(x
, y
);
872 CalcBoundingBox(x2
, y2
);
875 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
877 #ifdef __WXMICROWIN__
878 if (!GetHDC()) return;
881 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
884 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
886 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
889 CalcBoundingBox(x
, y
);
890 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
893 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
895 #ifdef __WXMICROWIN__
896 if (!GetHDC()) return;
899 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
901 int width
= bmp
.GetWidth(),
902 height
= bmp
.GetHeight();
904 HBITMAP hbmpMask
= 0;
908 #endif // wxUSE_PALETTE
912 wxMask
*mask
= bmp
.GetMask();
914 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
918 // don't give assert here because this would break existing
919 // programs - just silently ignore useMask parameter
926 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
928 // On some systems, MaskBlt succeeds yet is much much slower
929 // than the wxWindows fall-back implementation. So we need
930 // to be able to switch this on and off at runtime.
932 #if wxUSE_SYSTEM_OPTIONS
933 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
937 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
938 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
940 wxPalette
*pal
= bmp
.GetPalette();
941 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
943 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
944 ::RealizePalette(hdcMem
);
946 #endif // wxUSE_PALETTE
948 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
951 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
955 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
956 #endif // wxUSE_PALETTE
958 ::SelectObject(hdcMem
, hOldBitmap
);
965 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
968 memDC
.SelectObject(bmp
);
970 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
972 memDC
.SelectObject(wxNullBitmap
);
975 else // no mask, just use BitBlt()
978 HDC memdc
= ::CreateCompatibleDC( cdc
);
979 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
981 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
983 COLORREF old_textground
= ::GetTextColor(GetHdc());
984 COLORREF old_background
= ::GetBkColor(GetHdc());
985 if (m_textForegroundColour
.Ok())
987 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
989 if (m_textBackgroundColour
.Ok())
991 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
995 wxPalette
*pal
= bmp
.GetPalette();
996 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
998 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
999 ::RealizePalette(memdc
);
1001 #endif // wxUSE_PALETTE
1003 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1004 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1008 ::SelectPalette(memdc
, oldPal
, FALSE
);
1009 #endif // wxUSE_PALETTE
1011 ::SelectObject( memdc
, hOldBitmap
);
1012 ::DeleteDC( memdc
);
1014 ::SetTextColor(GetHdc(), old_textground
);
1015 ::SetBkColor(GetHdc(), old_background
);
1019 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1021 #ifdef __WXMICROWIN__
1022 if (!GetHDC()) return;
1025 DrawAnyText(text
, x
, y
);
1027 // update the bounding box
1028 CalcBoundingBox(x
, y
);
1031 GetTextExtent(text
, &w
, &h
);
1032 CalcBoundingBox(x
+ w
, y
+ h
);
1035 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1037 #ifdef __WXMICROWIN__
1038 if (!GetHDC()) return;
1041 // prepare for drawing the text
1042 if ( m_textForegroundColour
.Ok() )
1043 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1045 DWORD old_background
= 0;
1046 if ( m_textBackgroundColour
.Ok() )
1048 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1051 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1054 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1055 text
.c_str(), text
.length()) == 0 )
1057 wxLogLastError(wxT("TextOut"));
1060 // restore the old parameters (text foreground colour may be left because
1061 // it never is set to anything else, but background should remain
1062 // transparent even if we just drew an opaque string)
1063 if ( m_textBackgroundColour
.Ok() )
1064 (void)SetBkColor(GetHdc(), old_background
);
1066 SetBkMode(GetHdc(), TRANSPARENT
);
1069 void wxDC::DoDrawRotatedText(const wxString
& text
,
1070 wxCoord x
, wxCoord y
,
1073 #ifdef __WXMICROWIN__
1074 if (!GetHDC()) return;
1077 // we test that we have some font because otherwise we should still use the
1078 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1079 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1080 // font for drawing rotated fonts unfortunately)
1081 if ( (angle
== 0.0) && m_font
.Ok() )
1083 DoDrawText(text
, x
, y
);
1085 #ifndef __WXMICROWIN__
1088 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1089 // because it's not TrueType and so can't have non zero
1090 // orientation/escapement under Win9x
1091 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1092 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1094 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1096 wxLogLastError(wxT("GetObject(hfont)"));
1099 // GDI wants the angle in tenth of degree
1100 long angle10
= (long)(angle
* 10);
1101 lf
.lfEscapement
= angle10
;
1102 lf
. lfOrientation
= angle10
;
1104 hfont
= ::CreateFontIndirect(&lf
);
1107 wxLogLastError(wxT("CreateFont"));
1111 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1113 DrawAnyText(text
, x
, y
);
1115 (void)::SelectObject(GetHdc(), hfontOld
);
1116 (void)::DeleteObject(hfont
);
1119 // call the bounding box by adding all four vertices of the rectangle
1120 // containing the text to it (simpler and probably not slower than
1121 // determining which of them is really topmost/leftmost/...)
1123 GetTextExtent(text
, &w
, &h
);
1125 double rad
= DegToRad(angle
);
1127 // "upper left" and "upper right"
1128 CalcBoundingBox(x
, y
);
1129 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
1131 // "bottom left" and "bottom right"
1132 x
+= (wxCoord
)(h
*sin(rad
));
1133 y
+= (wxCoord
)(h
*cos(rad
));
1134 CalcBoundingBox(x
, y
);
1135 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
1140 // ---------------------------------------------------------------------------
1142 // ---------------------------------------------------------------------------
1146 void wxDC::DoSelectPalette(bool realize
)
1148 #ifdef __WXMICROWIN__
1149 if (!GetHDC()) return;
1152 // Set the old object temporarily, in case the assignment deletes an object
1153 // that's not yet selected out.
1156 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1160 if ( m_palette
.Ok() )
1162 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1163 GetHpaletteOf(m_palette
),
1166 m_oldPalette
= (WXHPALETTE
) oldPal
;
1169 ::RealizePalette(GetHdc());
1173 void wxDC::SetPalette(const wxPalette
& palette
)
1177 m_palette
= palette
;
1178 DoSelectPalette(TRUE
);
1182 void wxDC::InitializePalette()
1184 if ( wxDisplayDepth() <= 8 )
1186 // look for any window or parent that has a custom palette. If any has
1187 // one then we need to use it in drawing operations
1188 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1190 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1191 if ( m_hasCustomPalette
)
1193 m_palette
= win
->GetPalette();
1195 // turn on MSW translation for this palette
1201 #endif // wxUSE_PALETTE
1203 void wxDC::SetFont(const wxFont
& the_font
)
1205 #ifdef __WXMICROWIN__
1206 if (!GetHDC()) return;
1209 // Set the old object temporarily, in case the assignment deletes an object
1210 // that's not yet selected out.
1213 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1222 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1226 if (m_font
.Ok() && m_font
.GetResourceHandle())
1228 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1229 if (f
== (HFONT
) NULL
)
1231 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1234 m_oldFont
= (WXHFONT
) f
;
1238 void wxDC::SetPen(const wxPen
& pen
)
1240 #ifdef __WXMICROWIN__
1241 if (!GetHDC()) return;
1244 // Set the old object temporarily, in case the assignment deletes an object
1245 // that's not yet selected out.
1248 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1257 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1263 if (m_pen
.GetResourceHandle())
1265 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1267 m_oldPen
= (WXHPEN
) p
;
1272 void wxDC::SetBrush(const wxBrush
& brush
)
1274 #ifdef __WXMICROWIN__
1275 if (!GetHDC()) return;
1278 // Set the old object temporarily, in case the assignment deletes an object
1279 // that's not yet selected out.
1282 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1291 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1297 // to make sure the brush is alligned with the logical coordinates
1298 wxBitmap
*stipple
= m_brush
.GetStipple();
1299 if ( stipple
&& stipple
->Ok() )
1302 ::SetBrushOrgEx(GetHdc(),
1303 m_deviceOriginX
% stipple
->GetWidth(),
1304 m_deviceOriginY
% stipple
->GetHeight(),
1305 NULL
); // don't need previous brush origin
1307 ::SetBrushOrg(GetHdc(),
1308 m_deviceOriginX
% stipple
->GetWidth(),
1309 m_deviceOriginY
% stipple
->GetHeight());
1313 if ( m_brush
.GetResourceHandle() )
1316 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1318 m_oldBrush
= (WXHBRUSH
) b
;
1323 void wxDC::SetBackground(const wxBrush
& brush
)
1325 #ifdef __WXMICROWIN__
1326 if (!GetHDC()) return;
1329 m_backgroundBrush
= brush
;
1331 if (!m_backgroundBrush
.Ok())
1336 bool customColours
= TRUE
;
1337 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1338 // change background colours from the control-panel specified colours.
1339 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1340 customColours
= FALSE
;
1344 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1346 m_canvas
->SetTransparent(TRUE
);
1350 // New behaviour, 10/2/99: setting the background brush of a DC
1351 // doesn't affect the window background colour. However,
1352 // I'm leaving in the transparency setting because it's needed by
1353 // various controls (e.g. wxStaticText) to determine whether to draw
1354 // transparently or not. TODO: maybe this should be a new function
1355 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1357 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1358 m_canvas
->SetTransparent(FALSE
);
1362 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1364 (void)SetBkColor(GetHdc(), new_color
);
1368 void wxDC::SetBackgroundMode(int mode
)
1370 #ifdef __WXMICROWIN__
1371 if (!GetHDC()) return;
1374 m_backgroundMode
= mode
;
1376 // SetBackgroundColour now only refers to text background
1377 // and m_backgroundMode is used there
1380 void wxDC::SetLogicalFunction(int function
)
1382 #ifdef __WXMICROWIN__
1383 if (!GetHDC()) return;
1386 m_logicalFunction
= function
;
1391 void wxDC::SetRop(WXHDC dc
)
1393 if ( !dc
|| m_logicalFunction
< 0 )
1398 switch (m_logicalFunction
)
1400 case wxCLEAR
: rop
= R2_BLACK
; break;
1401 case wxXOR
: rop
= R2_XORPEN
; break;
1402 case wxINVERT
: rop
= R2_NOT
; break;
1403 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1404 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1405 case wxCOPY
: rop
= R2_COPYPEN
; break;
1406 case wxAND
: rop
= R2_MASKPEN
; break;
1407 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1408 case wxNO_OP
: rop
= R2_NOP
; break;
1409 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1410 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1411 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1412 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1413 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1414 case wxOR
: rop
= R2_MERGEPEN
; break;
1415 case wxSET
: rop
= R2_WHITE
; break;
1418 wxFAIL_MSG( wxT("unsupported logical function") );
1422 SetROP2(GetHdc(), rop
);
1425 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1427 // We might be previewing, so return TRUE to let it continue.
1435 void wxDC::StartPage()
1439 void wxDC::EndPage()
1443 // ---------------------------------------------------------------------------
1445 // ---------------------------------------------------------------------------
1447 wxCoord
wxDC::GetCharHeight() const
1449 #ifdef __WXMICROWIN__
1450 if (!GetHDC()) return 0;
1453 TEXTMETRIC lpTextMetric
;
1455 GetTextMetrics(GetHdc(), &lpTextMetric
);
1457 return lpTextMetric
.tmHeight
;
1460 wxCoord
wxDC::GetCharWidth() const
1462 #ifdef __WXMICROWIN__
1463 if (!GetHDC()) return 0;
1466 TEXTMETRIC lpTextMetric
;
1468 GetTextMetrics(GetHdc(), &lpTextMetric
);
1470 return lpTextMetric
.tmAveCharWidth
;
1473 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1474 wxCoord
*descent
, wxCoord
*externalLeading
,
1477 #ifdef __WXMICROWIN__
1482 if (descent
) *descent
= 0;
1483 if (externalLeading
) *externalLeading
= 0;
1486 #endif // __WXMICROWIN__
1491 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1493 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1495 else // don't change the font
1503 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1504 GetTextMetrics(GetHdc(), &tm
);
1511 *descent
= tm
.tmDescent
;
1512 if (externalLeading
)
1513 *externalLeading
= tm
.tmExternalLeading
;
1517 ::SelectObject(GetHdc(), hfontOld
);
1521 void wxDC::SetMapMode(int mode
)
1523 #ifdef __WXMICROWIN__
1524 if (!GetHDC()) return;
1527 m_mappingMode
= mode
;
1529 if ( mode
== wxMM_TEXT
)
1532 m_logicalScaleY
= 1.0;
1534 else // need to do some calculations
1536 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1537 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1538 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1539 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1541 if ( (mm_width
== 0) || (mm_height
== 0) )
1543 // we can't calculate mm2pixels[XY] then!
1547 double mm2pixelsX
= pixel_width
/ mm_width
,
1548 mm2pixelsY
= pixel_height
/ mm_height
;
1553 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1554 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1558 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1559 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1563 m_logicalScaleX
= mm2pixelsX
;
1564 m_logicalScaleY
= mm2pixelsY
;
1568 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1569 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1573 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1577 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1578 // cases we could do with MM_TEXT and in the remaining 0.9% with
1579 // MM_ISOTROPIC (TODO!)
1580 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1582 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1583 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1585 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1586 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1588 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1589 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1592 void wxDC::SetUserScale(double x
, double y
)
1594 #ifdef __WXMICROWIN__
1595 if (!GetHDC()) return;
1598 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1604 SetMapMode(m_mappingMode
);
1607 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1609 #ifdef __WXMICROWIN__
1610 if (!GetHDC()) return;
1613 int signX
= xLeftRight
? 1 : -1,
1614 signY
= yBottomUp
? -1 : 1;
1616 if ( signX
!= m_signX
|| signY
!= m_signY
)
1621 SetMapMode(m_mappingMode
);
1625 void wxDC::SetSystemScale(double x
, double y
)
1627 #ifdef __WXMICROWIN__
1628 if (!GetHDC()) return;
1631 if ( x
== m_scaleX
&& y
== m_scaleY
)
1637 SetMapMode(m_mappingMode
);
1640 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1642 #ifdef __WXMICROWIN__
1643 if (!GetHDC()) return;
1646 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1649 m_logicalOriginX
= x
;
1650 m_logicalOriginY
= y
;
1652 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1655 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1657 #ifdef __WXMICROWIN__
1658 if (!GetHDC()) return;
1661 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1664 m_deviceOriginX
= x
;
1665 m_deviceOriginY
= y
;
1667 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1670 // ---------------------------------------------------------------------------
1671 // coordinates transformations
1672 // ---------------------------------------------------------------------------
1674 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1676 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1679 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1681 // axis orientation is not taken into account for conversion of a distance
1682 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1685 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1687 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1690 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1692 // axis orientation is not taken into account for conversion of a distance
1693 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1696 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1698 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1701 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1703 // axis orientation is not taken into account for conversion of a distance
1704 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1707 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1709 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1712 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1714 // axis orientation is not taken into account for conversion of a distance
1715 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1718 // ---------------------------------------------------------------------------
1720 // ---------------------------------------------------------------------------
1722 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1723 wxCoord width
, wxCoord height
,
1724 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1725 int rop
, bool useMask
,
1726 wxCoord xsrcMask
, wxCoord ysrcMask
)
1728 #ifdef __WXMICROWIN__
1729 if (!GetHDC()) return FALSE
;
1732 wxMask
*mask
= NULL
;
1735 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1736 mask
= bmp
.GetMask();
1738 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1740 // don't give assert here because this would break existing
1741 // programs - just silently ignore useMask parameter
1746 if (xsrcMask
== -1 && ysrcMask
== -1)
1748 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1751 COLORREF old_textground
= ::GetTextColor(GetHdc());
1752 COLORREF old_background
= ::GetBkColor(GetHdc());
1753 if (m_textForegroundColour
.Ok())
1755 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1757 if (m_textBackgroundColour
.Ok())
1759 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1762 DWORD dwRop
= SRCCOPY
;
1765 case wxXOR
: dwRop
= SRCINVERT
; break;
1766 case wxINVERT
: dwRop
= DSTINVERT
; break;
1767 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1768 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1769 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1770 case wxSET
: dwRop
= WHITENESS
; break;
1771 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1772 case wxAND
: dwRop
= SRCAND
; break;
1773 case wxOR
: dwRop
= SRCPAINT
; break;
1774 case wxEQUIV
: dwRop
= 0x00990066; break;
1775 case wxNAND
: dwRop
= 0x007700E6; break;
1776 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1777 case wxCOPY
: dwRop
= SRCCOPY
; break;
1778 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1779 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1780 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1782 wxFAIL_MSG( wxT("unsupported logical function") );
1786 bool success
= FALSE
;
1791 // we want the part of the image corresponding to the mask to be
1792 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1793 // meaning of fg and bg is inverted which corresponds to wxWin notion
1794 // of the mask which is also contrary to the Windows one)
1796 // On some systems, MaskBlt succeeds yet is much much slower
1797 // than the wxWindows fall-back implementation. So we need
1798 // to be able to switch this on and off at runtime.
1799 #if wxUSE_SYSTEM_OPTIONS
1800 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1803 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1804 GetHdcOf(*source
), xsrc
, ysrc
,
1805 (HBITMAP
)mask
->GetMaskBitmap(), xsrcMask
, ysrcMask
,
1806 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1812 // Blit bitmap with mask
1815 HBITMAP buffer_bmap
;
1817 #if wxUSE_DC_CACHEING
1818 // create a temp buffer bitmap and DCs to access it and the mask
1819 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1820 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1822 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1823 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1825 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1828 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1829 #else // !wxUSE_DC_CACHEING
1830 // create a temp buffer bitmap and DCs to access it and the mask
1831 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1832 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1833 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1834 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1835 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1836 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1838 // copy dest to buffer
1839 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1840 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1842 wxLogLastError(wxT("BitBlt"));
1845 // copy src to buffer using selected raster op
1846 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1847 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1849 wxLogLastError(wxT("BitBlt"));
1852 // set masked area in buffer to BLACK (pixel value 0)
1853 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1854 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1855 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1856 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1858 wxLogLastError(wxT("BitBlt"));
1861 // set unmasked area in dest to BLACK
1862 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1863 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1864 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1865 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1867 wxLogLastError(wxT("BitBlt"));
1869 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1870 ::SetTextColor(GetHdc(), prevCol
);
1872 // OR buffer to dest
1873 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1874 (int)width
, (int)height
,
1875 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1878 wxLogLastError(wxT("BitBlt"));
1881 // tidy up temporary DCs and bitmap
1882 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1883 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1885 #if !wxUSE_DC_CACHEING
1887 ::DeleteDC(dc_mask
);
1888 ::DeleteDC(dc_buffer
);
1889 ::DeleteObject(buffer_bmap
);
1894 else // no mask, just BitBlt() it
1896 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1897 (int)width
, (int)height
,
1898 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1901 wxLogLastError(wxT("BitBlt"));
1904 ::SetTextColor(GetHdc(), old_textground
);
1905 ::SetBkColor(GetHdc(), old_background
);
1910 void wxDC::DoGetSize(int *w
, int *h
) const
1912 #ifdef __WXMICROWIN__
1913 if (!GetHDC()) return;
1916 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1917 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1920 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1922 #ifdef __WXMICROWIN__
1923 if (!GetHDC()) return;
1926 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1927 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1930 wxSize
wxDC::GetPPI() const
1932 #ifdef __WXMICROWIN__
1933 if (!GetHDC()) return wxSize();
1936 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1937 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1939 return wxSize(x
, y
);
1942 // For use by wxWindows only, unless custom units are required.
1943 void wxDC::SetLogicalScale(double x
, double y
)
1945 #ifdef __WXMICROWIN__
1946 if (!GetHDC()) return;
1949 m_logicalScaleX
= x
;
1950 m_logicalScaleY
= y
;
1953 #if WXWIN_COMPATIBILITY
1954 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1955 float *descent
, float *externalLeading
,
1956 wxFont
*theFont
, bool use16bit
) const
1958 #ifdef __WXMICROWIN__
1959 if (!GetHDC()) return;
1962 wxCoord x1
, y1
, descent1
, externalLeading1
;
1963 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1966 *descent
= descent1
;
1967 if (externalLeading
)
1968 *externalLeading
= externalLeading1
;
1972 #if wxUSE_DC_CACHEING
1975 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
1976 * improve it in due course, either using arrays, or simply storing pointers to one
1977 * entry for the bitmap, and two for the DCs. -- JACS
1980 wxList
wxDC::sm_bitmapCache
;
1981 wxList
wxDC::sm_dcCache
;
1983 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
1992 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2001 wxDCCacheEntry::~wxDCCacheEntry()
2004 ::DeleteObject((HBITMAP
) m_bitmap
);
2006 ::DeleteDC((HDC
) m_dc
);
2009 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2011 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2012 wxNode
* node
= sm_bitmapCache
.First();
2015 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2017 if (entry
->m_depth
== depth
)
2019 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2021 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2022 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2023 if ( !entry
->m_bitmap
)
2025 wxLogLastError(wxT("CreateCompatibleBitmap"));
2027 entry
->m_width
= w
; entry
->m_height
= h
;
2033 node
= node
->Next();
2035 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2038 wxLogLastError(wxT("CreateCompatibleBitmap"));
2040 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2041 AddToBitmapCache(entry
);
2045 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2047 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2048 wxNode
* node
= sm_dcCache
.First();
2051 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2053 // Don't return the same one as we already have
2054 if (!notThis
|| (notThis
!= entry
))
2056 if (entry
->m_depth
== depth
)
2062 node
= node
->Next();
2064 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2067 wxLogLastError(wxT("CreateCompatibleDC"));
2069 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2070 AddToDCCache(entry
);
2074 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2076 sm_bitmapCache
.Append(entry
);
2079 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2081 sm_dcCache
.Append(entry
);
2084 void wxDC::ClearCache()
2086 sm_bitmapCache
.DeleteContents(TRUE
);
2087 sm_bitmapCache
.Clear();
2088 sm_bitmapCache
.DeleteContents(FALSE
);
2089 sm_dcCache
.DeleteContents(TRUE
);
2091 sm_dcCache
.DeleteContents(FALSE
);
2094 // Clean up cache at app exit
2095 class wxDCModule
: public wxModule
2098 virtual bool OnInit() { return TRUE
; }
2099 virtual void OnExit() { wxDC::ClearCache(); }
2102 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2105 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2108 // wxUSE_DC_CACHEING