]>
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 // ===========================================================================
137 // ===========================================================================
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
143 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
145 const wxBrush
& brush
= dc
.GetBrush();
146 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
148 HDC hdc
= GetHdcOf(dc
);
149 m_colFgOld
= ::GetTextColor(hdc
);
150 m_colBgOld
= ::GetBkColor(hdc
);
152 // note that Windows convention is opposite to wxWindows one, this is
153 // why text colour becomes the background one and vice versa
154 const wxColour
& colFg
= dc
.GetTextForeground();
157 ::SetBkColor(hdc
, colFg
.GetPixel());
160 const wxColour
& colBg
= dc
.GetTextBackground();
163 ::SetTextColor(hdc
, colBg
.GetPixel());
167 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
170 // flag which telsl us to undo changes in the dtor
175 // nothing done, nothing to undo
180 wxColourChanger::~wxColourChanger()
184 // restore the colours we changed
185 HDC hdc
= GetHdcOf(m_dc
);
187 ::SetBkMode(hdc
, TRANSPARENT
);
188 ::SetTextColor(hdc
, m_colFgOld
);
189 ::SetBkColor(hdc
, m_colBgOld
);
193 // ---------------------------------------------------------------------------
195 // ---------------------------------------------------------------------------
197 // Default constructor
208 #endif // wxUSE_PALETTE
218 SelectOldObjects(m_hDC
);
220 // if we own the HDC, we delete it, otherwise we just release it
224 ::DeleteDC(GetHdc());
226 else // we don't own our HDC
230 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
234 // Must have been a wxScreenDC
235 ::ReleaseDC((HWND
) NULL
, GetHdc());
241 // This will select current objects out of the DC,
242 // which is what you have to do before deleting the
244 void wxDC::SelectOldObjects(WXHDC dc
)
250 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
251 if (m_selectedBitmap
.Ok())
253 m_selectedBitmap
.SetSelectedInto(NULL
);
259 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
264 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
269 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
276 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
279 #endif // wxUSE_PALETTE
282 m_brush
= wxNullBrush
;
285 m_palette
= wxNullPalette
;
286 #endif // wxUSE_PALETTE
288 m_backgroundBrush
= wxNullBrush
;
289 m_selectedBitmap
= wxNullBitmap
;
292 // ---------------------------------------------------------------------------
294 // ---------------------------------------------------------------------------
296 void wxDC::UpdateClipBox()
298 #ifdef __WXMICROWIN__
299 if (!GetHDC()) return;
303 ::GetClipBox(GetHdc(), &rect
);
305 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
306 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
307 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
308 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
311 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
312 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
314 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
316 #ifdef __WXMICROWIN__
317 if (!GetHdc()) return;
318 #endif // __WXMICROWIN__
320 // note that we combine the new clipping region with the existing one: this
321 // is compatible with what the other ports do and is the documented
322 // behaviour now (starting with 2.3.3)
325 if ( !::GetClipBox(GetHdc(), &rectClip
) )
328 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
329 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
330 rectClip
.right
, rectClip
.bottom
);
332 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
334 ::SelectClipRgn(GetHdc(), hrgnDest
);
337 ::DeleteObject(hrgnClipOld
);
338 ::DeleteObject(hrgnDest
);
340 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
342 wxLogLastError(_T("ExtSelectClipRgn"));
353 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
355 // the region coords are always the device ones, so do the translation
358 // FIXME: possible +/-1 error here, to check!
359 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
361 LogicalToDeviceX(x
+ w
),
362 LogicalToDeviceY(y
+ h
));
365 wxLogLastError(_T("CreateRectRgn"));
369 SetClippingHrgn((WXHRGN
)hrgn
);
371 ::DeleteObject(hrgn
);
375 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
377 SetClippingHrgn(region
.GetHRGN());
380 void wxDC::DestroyClippingRegion()
382 #ifdef __WXMICROWIN__
383 if (!GetHDC()) return;
386 if (m_clipping
&& m_hDC
)
388 // TODO: this should restore the previous clipping region,
389 // so that OnPaint processing works correctly, and the update
390 // clipping region doesn't get destroyed after the first
391 // DestroyClippingRegion.
392 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
393 ::SelectClipRgn(GetHdc(), rgn
);
400 // ---------------------------------------------------------------------------
401 // query capabilities
402 // ---------------------------------------------------------------------------
404 bool wxDC::CanDrawBitmap() const
409 bool wxDC::CanGetTextExtent() const
411 #ifdef __WXMICROWIN__
412 // TODO Extend MicroWindows' GetDeviceCaps function
415 // What sort of display is it?
416 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
418 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
422 int wxDC::GetDepth() const
424 #ifdef __WXMICROWIN__
425 if (!GetHDC()) return 16;
428 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
431 // ---------------------------------------------------------------------------
433 // ---------------------------------------------------------------------------
437 #ifdef __WXMICROWIN__
438 if (!GetHDC()) return;
444 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
448 // No, I think we should simply ignore this if printing on e.g.
450 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
451 if (!m_selectedBitmap
.Ok())
454 rect
.left
= 0; rect
.top
= 0;
455 rect
.right
= m_selectedBitmap
.GetWidth();
456 rect
.bottom
= m_selectedBitmap
.GetHeight();
459 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
461 DWORD colour
= ::GetBkColor(GetHdc());
462 HBRUSH brush
= ::CreateSolidBrush(colour
);
463 ::FillRect(GetHdc(), &rect
, brush
);
464 ::DeleteObject(brush
);
466 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
467 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
469 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
470 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
471 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
472 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
473 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
476 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
478 #ifdef __WXMICROWIN__
479 if (!GetHDC()) return FALSE
;
482 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
484 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
485 : FLOODFILLBORDER
) ) ;
488 // quoting from the MSDN docs:
490 // Following are some of the reasons this function might fail:
492 // * The filling could not be completed.
493 // * The specified point has the boundary color specified by the
494 // crColor parameter (if FLOODFILLBORDER was requested).
495 // * The specified point does not have the color specified by
496 // crColor (if FLOODFILLSURFACE was requested)
497 // * The point is outside the clipping region that is, it is not
498 // visible on the device.
500 wxLogLastError(wxT("ExtFloodFill"));
503 CalcBoundingBox(x
, y
);
508 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
510 #ifdef __WXMICROWIN__
511 if (!GetHDC()) return FALSE
;
514 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
516 // get the color of the pixel
517 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
519 wxRGBToColour(*col
, pixelcolor
);
524 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
526 #ifdef __WXMICROWIN__
527 if (!GetHDC()) return;
530 wxCoord x1
= x
-VIEWPORT_EXTENT
;
531 wxCoord y1
= y
-VIEWPORT_EXTENT
;
532 wxCoord x2
= x
+VIEWPORT_EXTENT
;
533 wxCoord y2
= y
+VIEWPORT_EXTENT
;
535 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
536 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
538 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
539 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
541 CalcBoundingBox(x1
, y1
);
542 CalcBoundingBox(x2
, y2
);
545 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
547 #ifdef __WXMICROWIN__
548 if (!GetHDC()) return;
551 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
552 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
554 CalcBoundingBox(x1
, y1
);
555 CalcBoundingBox(x2
, y2
);
558 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
559 // and ending at (x2, y2)
560 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
561 wxCoord x2
, wxCoord y2
,
562 wxCoord xc
, wxCoord yc
)
564 #ifdef __WXMICROWIN__
565 if (!GetHDC()) return;
568 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
572 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
573 wxCoord r
= (wxCoord
)radius
;
575 // treat the special case of full circle separately
576 if ( x1
== x2
&& y1
== y2
)
578 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
582 wxCoord xx1
= XLOG2DEV(x1
);
583 wxCoord yy1
= YLOG2DEV(y1
);
584 wxCoord xx2
= XLOG2DEV(x2
);
585 wxCoord yy2
= YLOG2DEV(y2
);
586 wxCoord xxc
= XLOG2DEV(xc
);
587 wxCoord yyc
= YLOG2DEV(yc
);
588 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
590 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
591 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
592 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
593 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
595 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
597 // Have to add 1 to bottom-right corner of rectangle
598 // to make semi-circles look right (crooked line otherwise).
599 // Unfortunately this is not a reliable method, depends
600 // on the size of shape.
601 // TODO: figure out why this happens!
602 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
606 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
609 CalcBoundingBox(xc
- r
, yc
- r
);
610 CalcBoundingBox(xc
+ r
, yc
+ r
);
613 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
614 wxCoord width
, wxCoord height
)
616 #ifdef __WXMICROWIN__
617 if (!GetHDC()) return;
620 wxCoord x2
= x1
+ width
,
623 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__)
630 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
632 // In WIN16, draw a cross
633 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
634 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
635 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
636 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
637 ::SetROP2(GetHdc(), R2_COPYPEN
);
638 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
639 MoveToEx(GetHdc(), x1
, y1
, NULL
);
640 LineTo(GetHdc(), x2
, y2
);
641 MoveToEx(GetHdc(), x2
, y1
, NULL
);
642 LineTo(GetHdc(), x1
, y2
);
643 ::SelectObject(GetHdc(), hPenOld
);
644 ::SelectObject(GetHdc(), hBrushOld
);
645 ::DeleteObject(blackPen
);
648 CalcBoundingBox(x1
, y1
);
649 CalcBoundingBox(x2
, y2
);
652 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
654 #ifdef __WXMICROWIN__
655 if (!GetHDC()) return;
658 COLORREF color
= 0x00ffffff;
661 color
= m_pen
.GetColour().GetPixel();
664 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
666 CalcBoundingBox(x
, y
);
669 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
671 #ifdef __WXMICROWIN__
672 if (!GetHDC()) return;
675 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
677 // Do things less efficiently if we have offsets
678 if (xoffset
!= 0 || yoffset
!= 0)
680 POINT
*cpoints
= new POINT
[n
];
682 for (i
= 0; i
< n
; i
++)
684 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
685 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
687 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
689 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
690 (void)Polygon(GetHdc(), cpoints
, n
);
691 SetPolyFillMode(GetHdc(),prev
);
697 for (i
= 0; i
< n
; i
++)
698 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
700 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
701 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
702 SetPolyFillMode(GetHdc(),prev
);
706 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
708 #ifdef __WXMICROWIN__
709 if (!GetHDC()) return;
712 // Do things less efficiently if we have offsets
713 if (xoffset
!= 0 || yoffset
!= 0)
715 POINT
*cpoints
= new POINT
[n
];
717 for (i
= 0; i
< n
; i
++)
719 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
720 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
722 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
724 (void)Polyline(GetHdc(), cpoints
, n
);
730 for (i
= 0; i
< n
; i
++)
731 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
733 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
737 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
739 #ifdef __WXMICROWIN__
740 if (!GetHDC()) return;
743 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
745 wxCoord x2
= x
+ width
;
746 wxCoord y2
= y
+ height
;
748 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
751 rect
.left
= XLOG2DEV(x
);
752 rect
.top
= YLOG2DEV(y
);
753 rect
.right
= XLOG2DEV(x2
);
754 rect
.bottom
= YLOG2DEV(y2
);
755 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
759 // Windows draws the filled rectangles without outline (i.e. drawn with a
760 // transparent pen) one pixel smaller in both directions and we want them
761 // to have the same size regardless of which pen is used - adjust
763 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
764 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
770 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
774 CalcBoundingBox(x
, y
);
775 CalcBoundingBox(x2
, y2
);
778 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
780 #ifdef __WXMICROWIN__
781 if (!GetHDC()) return;
784 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
786 // Now, a negative radius value is interpreted to mean
787 // 'the proportion of the smallest X or Y dimension'
791 double smallest
= 0.0;
796 radius
= (- radius
* smallest
);
799 wxCoord x2
= (x
+width
);
800 wxCoord y2
= (y
+height
);
802 // Windows draws the filled rectangles without outline (i.e. drawn with a
803 // transparent pen) one pixel smaller in both directions and we want them
804 // to have the same size regardless of which pen is used - adjust
805 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
811 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
812 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
814 CalcBoundingBox(x
, y
);
815 CalcBoundingBox(x2
, y2
);
818 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
820 #ifdef __WXMICROWIN__
821 if (!GetHDC()) return;
824 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
826 wxCoord x2
= (x
+width
);
827 wxCoord y2
= (y
+height
);
829 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
831 CalcBoundingBox(x
, y
);
832 CalcBoundingBox(x2
, y2
);
835 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
836 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
838 #ifdef __WXMICROWIN__
839 if (!GetHDC()) return;
842 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
847 int rx1
= XLOG2DEV(x
+w
/2);
848 int ry1
= YLOG2DEV(y
+h
/2);
855 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
856 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
857 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
858 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
860 // draw pie with NULL_PEN first and then outline otherwise a line is
861 // drawn from the start and end points to the centre
862 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
865 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
870 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
871 rx1
, ry1
-1, rx2
, ry2
-1);
874 ::SelectObject(GetHdc(), hpenOld
);
876 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
879 CalcBoundingBox(x
, y
);
880 CalcBoundingBox(x2
, y2
);
883 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
885 #ifdef __WXMICROWIN__
886 if (!GetHDC()) return;
889 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
892 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
894 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
897 CalcBoundingBox(x
, y
);
898 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
901 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
903 #ifdef __WXMICROWIN__
904 if (!GetHDC()) return;
907 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
909 int width
= bmp
.GetWidth(),
910 height
= bmp
.GetHeight();
912 HBITMAP hbmpMask
= 0;
916 #endif // wxUSE_PALETTE
920 wxMask
*mask
= bmp
.GetMask();
922 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
926 // don't give assert here because this would break existing
927 // programs - just silently ignore useMask parameter
934 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
936 // On some systems, MaskBlt succeeds yet is much much slower
937 // than the wxWindows fall-back implementation. So we need
938 // to be able to switch this on and off at runtime.
940 #if wxUSE_SYSTEM_OPTIONS
941 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
945 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
946 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
948 wxPalette
*pal
= bmp
.GetPalette();
949 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
951 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
952 ::RealizePalette(hdcMem
);
954 #endif // wxUSE_PALETTE
956 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
959 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
963 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
964 #endif // wxUSE_PALETTE
966 ::SelectObject(hdcMem
, hOldBitmap
);
973 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
976 memDC
.SelectObject(bmp
);
978 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
980 memDC
.SelectObject(wxNullBitmap
);
983 else // no mask, just use BitBlt()
986 HDC memdc
= ::CreateCompatibleDC( cdc
);
987 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
989 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
991 COLORREF old_textground
= ::GetTextColor(GetHdc());
992 COLORREF old_background
= ::GetBkColor(GetHdc());
993 if (m_textForegroundColour
.Ok())
995 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
997 if (m_textBackgroundColour
.Ok())
999 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1003 wxPalette
*pal
= bmp
.GetPalette();
1004 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1006 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1007 ::RealizePalette(memdc
);
1009 #endif // wxUSE_PALETTE
1011 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1012 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1016 ::SelectPalette(memdc
, oldPal
, FALSE
);
1017 #endif // wxUSE_PALETTE
1019 ::SelectObject( memdc
, hOldBitmap
);
1020 ::DeleteDC( memdc
);
1022 ::SetTextColor(GetHdc(), old_textground
);
1023 ::SetBkColor(GetHdc(), old_background
);
1027 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1029 #ifdef __WXMICROWIN__
1030 if (!GetHDC()) return;
1033 DrawAnyText(text
, x
, y
);
1035 // update the bounding box
1036 CalcBoundingBox(x
, y
);
1039 GetTextExtent(text
, &w
, &h
);
1040 CalcBoundingBox(x
+ w
, y
+ h
);
1043 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1045 #ifdef __WXMICROWIN__
1046 if (!GetHDC()) return;
1049 // prepare for drawing the text
1050 if ( m_textForegroundColour
.Ok() )
1051 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1053 DWORD old_background
= 0;
1054 if ( m_textBackgroundColour
.Ok() )
1056 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1059 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1062 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1063 text
.c_str(), text
.length()) == 0 )
1065 wxLogLastError(wxT("TextOut"));
1068 // restore the old parameters (text foreground colour may be left because
1069 // it never is set to anything else, but background should remain
1070 // transparent even if we just drew an opaque string)
1071 if ( m_textBackgroundColour
.Ok() )
1072 (void)SetBkColor(GetHdc(), old_background
);
1074 SetBkMode(GetHdc(), TRANSPARENT
);
1077 void wxDC::DoDrawRotatedText(const wxString
& text
,
1078 wxCoord x
, wxCoord y
,
1081 #ifdef __WXMICROWIN__
1082 if (!GetHDC()) return;
1085 // we test that we have some font because otherwise we should still use the
1086 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1087 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1088 // font for drawing rotated fonts unfortunately)
1089 if ( (angle
== 0.0) && m_font
.Ok() )
1091 DoDrawText(text
, x
, y
);
1093 #ifndef __WXMICROWIN__
1096 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1097 // because it's not TrueType and so can't have non zero
1098 // orientation/escapement under Win9x
1099 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1100 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1102 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1104 wxLogLastError(wxT("GetObject(hfont)"));
1107 // GDI wants the angle in tenth of degree
1108 long angle10
= (long)(angle
* 10);
1109 lf
.lfEscapement
= angle10
;
1110 lf
. lfOrientation
= angle10
;
1112 hfont
= ::CreateFontIndirect(&lf
);
1115 wxLogLastError(wxT("CreateFont"));
1119 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1121 DrawAnyText(text
, x
, y
);
1123 (void)::SelectObject(GetHdc(), hfontOld
);
1124 (void)::DeleteObject(hfont
);
1127 // call the bounding box by adding all four vertices of the rectangle
1128 // containing the text to it (simpler and probably not slower than
1129 // determining which of them is really topmost/leftmost/...)
1131 GetTextExtent(text
, &w
, &h
);
1133 double rad
= DegToRad(angle
);
1135 // "upper left" and "upper right"
1136 CalcBoundingBox(x
, y
);
1137 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1139 // "bottom left" and "bottom right"
1140 x
+= (wxCoord
)(h
*sin(rad
));
1141 y
+= (wxCoord
)(h
*cos(rad
));
1142 CalcBoundingBox(x
, y
);
1143 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1148 // ---------------------------------------------------------------------------
1150 // ---------------------------------------------------------------------------
1154 void wxDC::DoSelectPalette(bool realize
)
1156 #ifdef __WXMICROWIN__
1157 if (!GetHDC()) return;
1160 // Set the old object temporarily, in case the assignment deletes an object
1161 // that's not yet selected out.
1164 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1168 if ( m_palette
.Ok() )
1170 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1171 GetHpaletteOf(m_palette
),
1174 m_oldPalette
= (WXHPALETTE
) oldPal
;
1177 ::RealizePalette(GetHdc());
1181 void wxDC::SetPalette(const wxPalette
& palette
)
1185 m_palette
= palette
;
1186 DoSelectPalette(TRUE
);
1190 void wxDC::InitializePalette()
1192 if ( wxDisplayDepth() <= 8 )
1194 // look for any window or parent that has a custom palette. If any has
1195 // one then we need to use it in drawing operations
1196 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1198 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1199 if ( m_hasCustomPalette
)
1201 m_palette
= win
->GetPalette();
1203 // turn on MSW translation for this palette
1209 #endif // wxUSE_PALETTE
1211 void wxDC::SetFont(const wxFont
& the_font
)
1213 #ifdef __WXMICROWIN__
1214 if (!GetHDC()) return;
1217 // Set the old object temporarily, in case the assignment deletes an object
1218 // that's not yet selected out.
1221 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1230 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1234 if (m_font
.Ok() && m_font
.GetResourceHandle())
1236 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1237 if (f
== (HFONT
) NULL
)
1239 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1242 m_oldFont
= (WXHFONT
) f
;
1246 void wxDC::SetPen(const wxPen
& pen
)
1248 #ifdef __WXMICROWIN__
1249 if (!GetHDC()) return;
1252 // Set the old object temporarily, in case the assignment deletes an object
1253 // that's not yet selected out.
1256 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1265 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1271 if (m_pen
.GetResourceHandle())
1273 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1275 m_oldPen
= (WXHPEN
) p
;
1280 void wxDC::SetBrush(const wxBrush
& brush
)
1282 #ifdef __WXMICROWIN__
1283 if (!GetHDC()) return;
1286 // Set the old object temporarily, in case the assignment deletes an object
1287 // that's not yet selected out.
1290 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1299 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1305 // to make sure the brush is alligned with the logical coordinates
1306 wxBitmap
*stipple
= m_brush
.GetStipple();
1307 if ( stipple
&& stipple
->Ok() )
1310 ::SetBrushOrgEx(GetHdc(),
1311 m_deviceOriginX
% stipple
->GetWidth(),
1312 m_deviceOriginY
% stipple
->GetHeight(),
1313 NULL
); // don't need previous brush origin
1315 ::SetBrushOrg(GetHdc(),
1316 m_deviceOriginX
% stipple
->GetWidth(),
1317 m_deviceOriginY
% stipple
->GetHeight());
1321 if ( m_brush
.GetResourceHandle() )
1324 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1326 m_oldBrush
= (WXHBRUSH
) b
;
1331 void wxDC::SetBackground(const wxBrush
& brush
)
1333 #ifdef __WXMICROWIN__
1334 if (!GetHDC()) return;
1337 m_backgroundBrush
= brush
;
1339 if (!m_backgroundBrush
.Ok())
1344 bool customColours
= TRUE
;
1345 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1346 // change background colours from the control-panel specified colours.
1347 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1348 customColours
= FALSE
;
1352 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1354 m_canvas
->SetTransparent(TRUE
);
1358 // New behaviour, 10/2/99: setting the background brush of a DC
1359 // doesn't affect the window background colour. However,
1360 // I'm leaving in the transparency setting because it's needed by
1361 // various controls (e.g. wxStaticText) to determine whether to draw
1362 // transparently or not. TODO: maybe this should be a new function
1363 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1365 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1366 m_canvas
->SetTransparent(FALSE
);
1370 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1372 (void)SetBkColor(GetHdc(), new_color
);
1376 void wxDC::SetBackgroundMode(int mode
)
1378 #ifdef __WXMICROWIN__
1379 if (!GetHDC()) return;
1382 m_backgroundMode
= mode
;
1384 // SetBackgroundColour now only refers to text background
1385 // and m_backgroundMode is used there
1388 void wxDC::SetLogicalFunction(int function
)
1390 #ifdef __WXMICROWIN__
1391 if (!GetHDC()) return;
1394 m_logicalFunction
= function
;
1399 void wxDC::SetRop(WXHDC dc
)
1401 if ( !dc
|| m_logicalFunction
< 0 )
1406 switch (m_logicalFunction
)
1408 case wxCLEAR
: rop
= R2_BLACK
; break;
1409 case wxXOR
: rop
= R2_XORPEN
; break;
1410 case wxINVERT
: rop
= R2_NOT
; break;
1411 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1412 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1413 case wxCOPY
: rop
= R2_COPYPEN
; break;
1414 case wxAND
: rop
= R2_MASKPEN
; break;
1415 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1416 case wxNO_OP
: rop
= R2_NOP
; break;
1417 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1418 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1419 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1420 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1421 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1422 case wxOR
: rop
= R2_MERGEPEN
; break;
1423 case wxSET
: rop
= R2_WHITE
; break;
1426 wxFAIL_MSG( wxT("unsupported logical function") );
1430 SetROP2(GetHdc(), rop
);
1433 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1435 // We might be previewing, so return TRUE to let it continue.
1443 void wxDC::StartPage()
1447 void wxDC::EndPage()
1451 // ---------------------------------------------------------------------------
1453 // ---------------------------------------------------------------------------
1455 wxCoord
wxDC::GetCharHeight() const
1457 #ifdef __WXMICROWIN__
1458 if (!GetHDC()) return 0;
1461 TEXTMETRIC lpTextMetric
;
1463 GetTextMetrics(GetHdc(), &lpTextMetric
);
1465 return lpTextMetric
.tmHeight
;
1468 wxCoord
wxDC::GetCharWidth() const
1470 #ifdef __WXMICROWIN__
1471 if (!GetHDC()) return 0;
1474 TEXTMETRIC lpTextMetric
;
1476 GetTextMetrics(GetHdc(), &lpTextMetric
);
1478 return lpTextMetric
.tmAveCharWidth
;
1481 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1482 wxCoord
*descent
, wxCoord
*externalLeading
,
1485 #ifdef __WXMICROWIN__
1490 if (descent
) *descent
= 0;
1491 if (externalLeading
) *externalLeading
= 0;
1494 #endif // __WXMICROWIN__
1499 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1501 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1503 else // don't change the font
1511 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1512 GetTextMetrics(GetHdc(), &tm
);
1519 *descent
= tm
.tmDescent
;
1520 if (externalLeading
)
1521 *externalLeading
= tm
.tmExternalLeading
;
1525 ::SelectObject(GetHdc(), hfontOld
);
1529 void wxDC::SetMapMode(int mode
)
1531 #ifdef __WXMICROWIN__
1532 if (!GetHDC()) return;
1535 m_mappingMode
= mode
;
1537 if ( mode
== wxMM_TEXT
)
1540 m_logicalScaleY
= 1.0;
1542 else // need to do some calculations
1544 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1545 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1546 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1547 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1549 if ( (mm_width
== 0) || (mm_height
== 0) )
1551 // we can't calculate mm2pixels[XY] then!
1555 double mm2pixelsX
= pixel_width
/ mm_width
,
1556 mm2pixelsY
= pixel_height
/ mm_height
;
1561 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1562 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1566 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1567 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1571 m_logicalScaleX
= mm2pixelsX
;
1572 m_logicalScaleY
= mm2pixelsY
;
1576 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1577 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1581 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1585 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1586 // cases we could do with MM_TEXT and in the remaining 0.9% with
1587 // MM_ISOTROPIC (TODO!)
1588 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1590 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1591 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1593 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1594 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1596 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1597 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1600 void wxDC::SetUserScale(double x
, double y
)
1602 #ifdef __WXMICROWIN__
1603 if (!GetHDC()) return;
1606 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1612 SetMapMode(m_mappingMode
);
1615 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1617 #ifdef __WXMICROWIN__
1618 if (!GetHDC()) return;
1621 int signX
= xLeftRight
? 1 : -1,
1622 signY
= yBottomUp
? -1 : 1;
1624 if ( signX
!= m_signX
|| signY
!= m_signY
)
1629 SetMapMode(m_mappingMode
);
1633 void wxDC::SetSystemScale(double x
, double y
)
1635 #ifdef __WXMICROWIN__
1636 if (!GetHDC()) return;
1639 if ( x
== m_scaleX
&& y
== m_scaleY
)
1645 SetMapMode(m_mappingMode
);
1648 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1650 #ifdef __WXMICROWIN__
1651 if (!GetHDC()) return;
1654 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1657 m_logicalOriginX
= x
;
1658 m_logicalOriginY
= y
;
1660 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1663 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1665 #ifdef __WXMICROWIN__
1666 if (!GetHDC()) return;
1669 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1672 m_deviceOriginX
= x
;
1673 m_deviceOriginY
= y
;
1675 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1678 // ---------------------------------------------------------------------------
1679 // coordinates transformations
1680 // ---------------------------------------------------------------------------
1682 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1684 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1687 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1689 // axis orientation is not taken into account for conversion of a distance
1690 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1693 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1695 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1698 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1700 // axis orientation is not taken into account for conversion of a distance
1701 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1704 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1706 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1709 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1711 // axis orientation is not taken into account for conversion of a distance
1712 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1715 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1717 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1720 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1722 // axis orientation is not taken into account for conversion of a distance
1723 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1726 // ---------------------------------------------------------------------------
1728 // ---------------------------------------------------------------------------
1730 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1731 wxCoord width
, wxCoord height
,
1732 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1733 int rop
, bool useMask
,
1734 wxCoord xsrcMask
, wxCoord ysrcMask
)
1736 #ifdef __WXMICROWIN__
1737 if (!GetHDC()) return FALSE
;
1740 wxMask
*mask
= NULL
;
1743 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1744 mask
= bmp
.GetMask();
1746 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1748 // don't give assert here because this would break existing
1749 // programs - just silently ignore useMask parameter
1754 if (xsrcMask
== -1 && ysrcMask
== -1)
1756 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1759 COLORREF old_textground
= ::GetTextColor(GetHdc());
1760 COLORREF old_background
= ::GetBkColor(GetHdc());
1761 if (m_textForegroundColour
.Ok())
1763 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1765 if (m_textBackgroundColour
.Ok())
1767 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1770 DWORD dwRop
= SRCCOPY
;
1773 case wxXOR
: dwRop
= SRCINVERT
; break;
1774 case wxINVERT
: dwRop
= DSTINVERT
; break;
1775 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1776 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1777 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1778 case wxSET
: dwRop
= WHITENESS
; break;
1779 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1780 case wxAND
: dwRop
= SRCAND
; break;
1781 case wxOR
: dwRop
= SRCPAINT
; break;
1782 case wxEQUIV
: dwRop
= 0x00990066; break;
1783 case wxNAND
: dwRop
= 0x007700E6; break;
1784 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1785 case wxCOPY
: dwRop
= SRCCOPY
; break;
1786 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1787 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1788 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1790 wxFAIL_MSG( wxT("unsupported logical function") );
1794 bool success
= FALSE
;
1799 // we want the part of the image corresponding to the mask to be
1800 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1801 // meaning of fg and bg is inverted which corresponds to wxWin notion
1802 // of the mask which is also contrary to the Windows one)
1804 // On some systems, MaskBlt succeeds yet is much much slower
1805 // than the wxWindows fall-back implementation. So we need
1806 // to be able to switch this on and off at runtime.
1807 #if wxUSE_SYSTEM_OPTIONS
1808 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1811 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1812 GetHdcOf(*source
), xsrc
, ysrc
,
1813 (HBITMAP
)mask
->GetMaskBitmap(), xsrcMask
, ysrcMask
,
1814 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1820 // Blit bitmap with mask
1823 HBITMAP buffer_bmap
;
1825 #if wxUSE_DC_CACHEING
1826 // create a temp buffer bitmap and DCs to access it and the mask
1827 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1828 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1830 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1831 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1833 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1836 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1837 #else // !wxUSE_DC_CACHEING
1838 // create a temp buffer bitmap and DCs to access it and the mask
1839 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1840 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1841 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1842 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1843 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1844 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1846 // copy dest to buffer
1847 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1848 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1850 wxLogLastError(wxT("BitBlt"));
1853 // copy src to buffer using selected raster op
1854 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1855 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1857 wxLogLastError(wxT("BitBlt"));
1860 // set masked area in buffer to BLACK (pixel value 0)
1861 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1862 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1863 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1864 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1866 wxLogLastError(wxT("BitBlt"));
1869 // set unmasked area in dest to BLACK
1870 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1871 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1872 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1873 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
1875 wxLogLastError(wxT("BitBlt"));
1877 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1878 ::SetTextColor(GetHdc(), prevCol
);
1880 // OR buffer to dest
1881 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1882 (int)width
, (int)height
,
1883 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1886 wxLogLastError(wxT("BitBlt"));
1889 // tidy up temporary DCs and bitmap
1890 ::SelectObject(dc_mask
, hOldMaskBitmap
);
1891 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
1893 #if !wxUSE_DC_CACHEING
1895 ::DeleteDC(dc_mask
);
1896 ::DeleteDC(dc_buffer
);
1897 ::DeleteObject(buffer_bmap
);
1902 else // no mask, just BitBlt() it
1904 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1905 (int)width
, (int)height
,
1906 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1909 wxLogLastError(wxT("BitBlt"));
1912 ::SetTextColor(GetHdc(), old_textground
);
1913 ::SetBkColor(GetHdc(), old_background
);
1918 void wxDC::DoGetSize(int *w
, int *h
) const
1920 #ifdef __WXMICROWIN__
1921 if (!GetHDC()) return;
1924 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1925 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1928 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1930 #ifdef __WXMICROWIN__
1931 if (!GetHDC()) return;
1934 // if we implement it in terms of DoGetSize() instead of directly using the
1935 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
1936 // will also work for wxWindowDC and wxClientDC even though their size is
1937 // not the same as the total size of the screen
1938 int wPixels
, hPixels
;
1939 DoGetSize(&wPixels
, &hPixels
);
1943 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1945 wxCHECK_RET( wTotal
, _T("0 width device?") );
1947 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
1952 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1954 wxCHECK_RET( hTotal
, _T("0 height device?") );
1956 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
1960 wxSize
wxDC::GetPPI() const
1962 #ifdef __WXMICROWIN__
1963 if (!GetHDC()) return wxSize();
1966 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1967 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1969 return wxSize(x
, y
);
1972 // For use by wxWindows only, unless custom units are required.
1973 void wxDC::SetLogicalScale(double x
, double y
)
1975 #ifdef __WXMICROWIN__
1976 if (!GetHDC()) return;
1979 m_logicalScaleX
= x
;
1980 m_logicalScaleY
= y
;
1983 #if WXWIN_COMPATIBILITY
1984 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1985 float *descent
, float *externalLeading
,
1986 wxFont
*theFont
, bool use16bit
) const
1988 #ifdef __WXMICROWIN__
1989 if (!GetHDC()) return;
1992 wxCoord x1
, y1
, descent1
, externalLeading1
;
1993 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1996 *descent
= descent1
;
1997 if (externalLeading
)
1998 *externalLeading
= externalLeading1
;
2002 #if wxUSE_DC_CACHEING
2005 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2006 * improve it in due course, either using arrays, or simply storing pointers to one
2007 * entry for the bitmap, and two for the DCs. -- JACS
2010 wxList
wxDC::sm_bitmapCache
;
2011 wxList
wxDC::sm_dcCache
;
2013 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2022 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2031 wxDCCacheEntry::~wxDCCacheEntry()
2034 ::DeleteObject((HBITMAP
) m_bitmap
);
2036 ::DeleteDC((HDC
) m_dc
);
2039 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2041 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2042 wxNode
* node
= sm_bitmapCache
.First();
2045 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2047 if (entry
->m_depth
== depth
)
2049 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2051 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2052 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2053 if ( !entry
->m_bitmap
)
2055 wxLogLastError(wxT("CreateCompatibleBitmap"));
2057 entry
->m_width
= w
; entry
->m_height
= h
;
2063 node
= node
->Next();
2065 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2068 wxLogLastError(wxT("CreateCompatibleBitmap"));
2070 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2071 AddToBitmapCache(entry
);
2075 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2077 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2078 wxNode
* node
= sm_dcCache
.First();
2081 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->Data();
2083 // Don't return the same one as we already have
2084 if (!notThis
|| (notThis
!= entry
))
2086 if (entry
->m_depth
== depth
)
2092 node
= node
->Next();
2094 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2097 wxLogLastError(wxT("CreateCompatibleDC"));
2099 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2100 AddToDCCache(entry
);
2104 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2106 sm_bitmapCache
.Append(entry
);
2109 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2111 sm_dcCache
.Append(entry
);
2114 void wxDC::ClearCache()
2116 sm_dcCache
.DeleteContents(TRUE
);
2118 sm_dcCache
.DeleteContents(FALSE
);
2119 sm_bitmapCache
.DeleteContents(TRUE
);
2120 sm_bitmapCache
.Clear();
2121 sm_bitmapCache
.DeleteContents(FALSE
);
2124 // Clean up cache at app exit
2125 class wxDCModule
: public wxModule
2128 virtual bool OnInit() { return TRUE
; }
2129 virtual void OnExit() { wxDC::ClearCache(); }
2132 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2135 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2138 // wxUSE_DC_CACHEING