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/dcprint.h"
48 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
50 #if wxUSE_COMMON_DIALOGS
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
60 // ---------------------------------------------------------------------------
62 // ---------------------------------------------------------------------------
64 static const int VIEWPORT_EXTENT
= 1000;
66 static const int MM_POINTS
= 9;
67 static const int MM_METRIC
= 10;
69 // usually this is defined in math.h
71 static const double M_PI
= 3.14159265358979323846;
74 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
75 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
76 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
78 // ---------------------------------------------------------------------------
80 // ---------------------------------------------------------------------------
82 // convert degrees to radians
83 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
85 // ===========================================================================
87 // ===========================================================================
89 // ---------------------------------------------------------------------------
91 // ---------------------------------------------------------------------------
93 // Default constructor
107 m_windowExtX
= VIEWPORT_EXTENT
;
108 m_windowExtY
= VIEWPORT_EXTENT
;
117 SelectOldObjects(m_hDC
);
119 if ( m_canvas
== NULL
)
120 ::DeleteDC(GetHdc());
122 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
128 // This will select current objects out of the DC,
129 // which is what you have to do before deleting the
131 void wxDC::SelectOldObjects(WXHDC dc
)
137 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
138 if (m_selectedBitmap
.Ok())
140 m_selectedBitmap
.SetSelectedInto(NULL
);
146 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
151 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
156 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
161 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
166 m_brush
= wxNullBrush
;
168 m_palette
= wxNullPalette
;
170 m_backgroundBrush
= wxNullBrush
;
171 m_selectedBitmap
= wxNullBitmap
;
174 // ---------------------------------------------------------------------------
176 // ---------------------------------------------------------------------------
178 #define DO_SET_CLIPPING_BOX() \
182 GetClipBox(GetHdc(), &rect); \
184 m_clipX1 = (wxCoord) XDEV2LOG(rect.left); \
185 m_clipY1 = (wxCoord) YDEV2LOG(rect.top); \
186 m_clipX2 = (wxCoord) XDEV2LOG(rect.right); \
187 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); \
190 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
193 IntersectClipRect(GetHdc(), XLOG2DEV(cx
), YLOG2DEV(cy
),
194 XLOG2DEV(cx
+ cw
), YLOG2DEV(cy
+ ch
));
195 DO_SET_CLIPPING_BOX()
198 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
200 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
205 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
207 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
210 DO_SET_CLIPPING_BOX()
213 void wxDC::DestroyClippingRegion()
215 if (m_clipping
&& m_hDC
)
217 // TODO: this should restore the previous clipping region,
218 // so that OnPaint processing works correctly, and the update clipping region
219 // doesn't get destroyed after the first DestroyClippingRegion.
220 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
221 SelectClipRgn(GetHdc(), rgn
);
227 // ---------------------------------------------------------------------------
228 // query capabilities
229 // ---------------------------------------------------------------------------
231 bool wxDC::CanDrawBitmap() const
236 bool wxDC::CanGetTextExtent() const
238 // What sort of display is it?
239 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
241 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
244 int wxDC::GetDepth() const
246 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
249 // ---------------------------------------------------------------------------
251 // ---------------------------------------------------------------------------
258 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
262 // No, I think we should simply ignore this if printing on e.g.
264 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
265 if (!m_selectedBitmap
.Ok())
268 rect
.left
= 0; rect
.top
= 0;
269 rect
.right
= m_selectedBitmap
.GetWidth();
270 rect
.bottom
= m_selectedBitmap
.GetHeight();
273 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
275 DWORD colour
= GetBkColor(GetHdc());
276 HBRUSH brush
= CreateSolidBrush(colour
);
277 FillRect(GetHdc(), &rect
, brush
);
280 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
281 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
282 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
283 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
284 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
287 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
289 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
291 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
294 // quoting from the MSDN docs:
296 // Following are some of the reasons this function might fail:
298 // * The filling could not be completed.
299 // * The specified point has the boundary color specified by the
300 // crColor parameter (if FLOODFILLBORDER was requested).
301 // * The specified point does not have the color specified by
302 // crColor (if FLOODFILLSURFACE was requested)
303 // * The point is outside the clipping region that is, it is not
304 // visible on the device.
306 wxLogLastError("ExtFloodFill");
309 CalcBoundingBox(x
, y
);
312 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
314 // get the color of the pixel
315 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
317 // JACS: what was this for?
319 // get the color of the pen
320 COLORREF pencolor
= 0x00ffffff;
323 pencolor
= m_pen
.GetColour().GetPixel();
327 // return the color of the pixel
330 col
->Set(GetRValue(pixelcolor
),
331 GetGValue(pixelcolor
),
332 GetBValue(pixelcolor
));
335 // check, if color of the pixels is the same as the color of the current
336 // pen and return TRUE if it is, FALSE otherwise
337 // JACS, 24/02/2000: can't understand the reason for this, so returning TRUE instead.
338 // return pixelcolor == pencolor;
343 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
345 wxCoord x1
= x
-VIEWPORT_EXTENT
;
346 wxCoord y1
= y
-VIEWPORT_EXTENT
;
347 wxCoord x2
= x
+VIEWPORT_EXTENT
;
348 wxCoord y2
= y
+VIEWPORT_EXTENT
;
350 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
351 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
353 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
354 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
356 CalcBoundingBox(x1
, y1
);
357 CalcBoundingBox(x2
, y2
);
360 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
362 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
363 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
365 // Normalization: Windows doesn't draw the last point of the line.
366 // But apparently neither does GTK+, so we take it out again.
367 // (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2));
369 CalcBoundingBox(x1
, y1
);
370 CalcBoundingBox(x2
, y2
);
373 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
375 COLORREF colFgOld
= 0,
378 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
380 colFgOld
= ::GetTextColor(GetHdc());
381 colBgOld
= ::GetBkColor(GetHdc());
383 if (m_textForegroundColour
.Ok())
384 { //just the oposite from what is expected see help on pattern brush
385 // 1 in mask becomes bk color
386 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
388 if (m_textBackgroundColour
.Ok())
389 { //just the oposite from what is expected
390 // 0 in mask becomes text color
391 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
394 if (m_backgroundMode
== wxTRANSPARENT
)
395 SetBkMode(GetHdc(), TRANSPARENT
);
397 SetBkMode(GetHdc(), OPAQUE
);
402 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
403 if (x1
==x2
&& x2
==y2
)
405 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
409 wxCoord xx1
= XLOG2DEV(x1
);
410 wxCoord yy1
= YLOG2DEV(y1
);
411 wxCoord xx2
= XLOG2DEV(x2
);
412 wxCoord yy2
= YLOG2DEV(y2
);
413 wxCoord xxc
= XLOG2DEV(xc
);
414 wxCoord yyc
= YLOG2DEV(yc
);
415 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
417 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
418 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
419 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
420 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
421 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
422 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
424 // Have to add 1 to bottom-right corner of rectangle
425 // to make semi-circles look right (crooked line otherwise).
426 // Unfortunately this is not a reliable method, depends
427 // on the size of shape.
428 // TODO: figure out why this happens!
429 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
433 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
436 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
437 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
439 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
441 // restore the colours we changed
442 ::SetBkMode(GetHdc(), TRANSPARENT
);
443 ::SetTextColor(GetHdc(), colFgOld
);
444 ::SetBkColor(GetHdc(), colBgOld
);
448 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
449 wxCoord width
, wxCoord height
)
451 wxCoord x2
= x1
+ width
,
454 #if defined(__WIN32__) && !defined(__SC__)
461 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
463 // In WIN16, draw a cross
464 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
465 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
466 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
467 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
468 ::SetROP2(GetHdc(), R2_COPYPEN
);
469 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
470 MoveTo(GetHdc(), x1
, y1
);
471 LineTo(GetHdc(), x2
, y2
);
472 MoveTo(GetHdc(), x2
, y1
);
473 LineTo(GetHdc(), x1
, y2
);
474 ::SelectObject(GetHdc(), hPenOld
);
475 ::SelectObject(GetHdc(), hBrushOld
);
476 ::DeleteObject(blackPen
);
479 CalcBoundingBox(x1
, y1
);
480 CalcBoundingBox(x2
, y2
);
483 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
485 COLORREF color
= 0x00ffffff;
488 color
= m_pen
.GetColour().GetPixel();
491 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
493 CalcBoundingBox(x
, y
);
496 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
498 COLORREF colFgOld
= 0,
501 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
503 colFgOld
= ::GetTextColor(GetHdc());
504 colBgOld
= ::GetBkColor(GetHdc());
506 if (m_textForegroundColour
.Ok())
507 { //just the oposite from what is expected see help on pattern brush
508 // 1 in mask becomes bk color
509 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
511 if (m_textBackgroundColour
.Ok())
512 { //just the oposite from what is expected
513 // 0 in mask becomes text color
514 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
517 if (m_backgroundMode
== wxTRANSPARENT
)
518 SetBkMode(GetHdc(), TRANSPARENT
);
520 SetBkMode(GetHdc(), OPAQUE
);
523 // Do things less efficiently if we have offsets
524 if (xoffset
!= 0 || yoffset
!= 0)
526 POINT
*cpoints
= new POINT
[n
];
528 for (i
= 0; i
< n
; i
++)
530 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
531 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
533 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
535 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
536 (void)Polygon(GetHdc(), cpoints
, n
);
537 SetPolyFillMode(GetHdc(),prev
);
543 for (i
= 0; i
< n
; i
++)
544 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
546 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
547 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
548 SetPolyFillMode(GetHdc(),prev
);
551 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
553 // restore the colours we changed
554 ::SetBkMode(GetHdc(), TRANSPARENT
);
555 ::SetTextColor(GetHdc(), colFgOld
);
556 ::SetBkColor(GetHdc(), colBgOld
);
560 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
562 // Do things less efficiently if we have offsets
563 if (xoffset
!= 0 || yoffset
!= 0)
565 POINT
*cpoints
= new POINT
[n
];
567 for (i
= 0; i
< n
; i
++)
569 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
570 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
572 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
574 (void)Polyline(GetHdc(), cpoints
, n
);
580 for (i
= 0; i
< n
; i
++)
581 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
583 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
587 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
589 COLORREF colFgOld
= 0,
592 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
594 colFgOld
= ::GetTextColor(GetHdc());
595 colBgOld
= ::GetBkColor(GetHdc());
597 if ( m_textForegroundColour
.Ok() )
599 // just the oposite from what is expected see help on pattern brush
600 // 1 in mask becomes bk color
601 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
604 if ( m_textBackgroundColour
.Ok() )
606 // 0 in mask becomes text color
607 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
610 // VZ: IMHO this does strictly nothing here
611 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
615 wxCoord x2
= x
+ width
;
616 wxCoord y2
= y
+ height
;
618 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
621 rect
.left
= XLOG2DEV(x
);
622 rect
.top
= YLOG2DEV(y
);
623 rect
.right
= XLOG2DEV(x2
);
624 rect
.bottom
= YLOG2DEV(y2
);
625 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
629 // Windows draws the filled rectangles without outline (i.e. drawn with a
630 // transparent pen) one pixel smaller in both directions and we want them
631 // to have the same size regardless of which pen is used - adjust
633 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
634 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
640 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
644 CalcBoundingBox(x
, y
);
645 CalcBoundingBox(x2
, y2
);
647 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
649 // restore the colours we changed
650 ::SetBkMode(GetHdc(), TRANSPARENT
);
651 ::SetTextColor(GetHdc(), colFgOld
);
652 ::SetBkColor(GetHdc(), colBgOld
);
656 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
658 COLORREF colFgOld
= 0,
661 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
663 colFgOld
= ::GetTextColor(GetHdc());
664 colBgOld
= ::GetBkColor(GetHdc());
666 if ( m_textForegroundColour
.Ok() )
668 // just the oposite from what is expected see help on pattern brush
669 // 1 in mask becomes bk color
670 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
673 if ( m_textBackgroundColour
.Ok() )
675 // 0 in mask becomes text color
676 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
679 // VZ: IMHO this does strictly nothing here
680 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
684 // Now, a negative radius value is interpreted to mean
685 // 'the proportion of the smallest X or Y dimension'
689 double smallest
= 0.0;
694 radius
= (- radius
* smallest
);
697 wxCoord x2
= (x
+width
);
698 wxCoord y2
= (y
+height
);
700 // Windows draws the filled rectangles without outline (i.e. drawn with a
701 // transparent pen) one pixel smaller in both directions and we want them
702 // to have the same size regardless of which pen is used - adjust
703 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
709 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
710 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
712 CalcBoundingBox(x
, y
);
713 CalcBoundingBox(x2
, y2
);
715 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
717 // restore the colours we changed
718 ::SetBkMode(GetHdc(), TRANSPARENT
);
719 ::SetTextColor(GetHdc(), colFgOld
);
720 ::SetBkColor(GetHdc(), colBgOld
);
724 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
726 COLORREF colFgOld
= 0,
729 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
731 colFgOld
= ::GetTextColor(GetHdc());
732 colBgOld
= ::GetBkColor(GetHdc());
734 if ( m_textForegroundColour
.Ok() )
736 // just the oposite from what is expected see help on pattern brush
737 // 1 in mask becomes bk color
738 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
741 if ( m_textBackgroundColour
.Ok() )
743 // 0 in mask becomes text color
744 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
747 // VZ: IMHO this does strictly nothing here
748 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
752 wxCoord x2
= (x
+width
);
753 wxCoord y2
= (y
+height
);
755 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
757 CalcBoundingBox(x
, y
);
758 CalcBoundingBox(x2
, y2
);
760 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
762 // restore the colours we changed
763 ::SetBkMode(GetHdc(), TRANSPARENT
);
764 ::SetTextColor(GetHdc(), colFgOld
);
765 ::SetBkColor(GetHdc(), colBgOld
);
769 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
770 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
772 COLORREF colFgOld
= 0,
775 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
777 colFgOld
= ::GetTextColor(GetHdc());
778 colBgOld
= ::GetBkColor(GetHdc());
780 if ( m_textForegroundColour
.Ok() )
782 // just the oposite from what is expected see help on pattern brush
783 // 1 in mask becomes bk color
784 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
787 if ( m_textBackgroundColour
.Ok() )
789 // 0 in mask becomes text color
790 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
793 // VZ: IMHO this does strictly nothing here
794 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
801 int rx1
= XLOG2DEV(x
+w
/2);
802 int ry1
= YLOG2DEV(y
+h
/2);
809 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
810 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
811 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
812 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
814 // draw pie with NULL_PEN first and then outline otherwise a line is
815 // drawn from the start and end points to the centre
816 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
819 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
824 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
825 rx1
, ry1
-1, rx2
, ry2
-1);
827 ::SelectObject(GetHdc(), orig_pen
);
828 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
831 CalcBoundingBox(x
, y
);
832 CalcBoundingBox(x2
, y2
);
834 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
836 // restore the colours we changed
837 ::SetBkMode(GetHdc(), TRANSPARENT
);
838 ::SetTextColor(GetHdc(), colFgOld
);
839 ::SetBkColor(GetHdc(), colBgOld
);
843 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
845 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
847 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
849 CalcBoundingBox(x
, y
);
850 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
853 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
855 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
857 int width
= bmp
.GetWidth(),
858 height
= bmp
.GetHeight();
860 HBITMAP hbmpMask
= 0;
864 wxMask
*mask
= bmp
.GetMask();
866 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
870 // don't give assert here because this would break existing
871 // programs - just silently ignore useMask parameter
879 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
880 ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
882 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
884 bool ok
= ::MaskBlt(GetHdc(), x
, y
, width
, height
,
887 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
893 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
896 memDC
.SelectObject(bmp
);
898 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
900 memDC
.SelectObject(wxNullBitmap
);
903 else // no mask, just use BitBlt()
906 HDC memdc
= ::CreateCompatibleDC( cdc
);
907 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
909 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
911 COLORREF old_textground
= ::GetTextColor(GetHdc());
912 COLORREF old_background
= ::GetBkColor(GetHdc());
913 if (m_textForegroundColour
.Ok())
915 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
917 if (m_textBackgroundColour
.Ok())
919 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
922 ::SelectObject( memdc
, hbitmap
);
923 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
926 ::SetTextColor(GetHdc(), old_textground
);
927 ::SetBkColor(GetHdc(), old_background
);
931 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
933 DrawAnyText(text
, x
, y
);
935 // update the bounding box
936 CalcBoundingBox(x
, y
);
939 GetTextExtent(text
, &w
, &h
);
940 CalcBoundingBox(x
+ w
, y
+ h
);
943 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
945 // prepare for drawing the text
946 if ( m_textForegroundColour
.Ok() )
947 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
949 DWORD old_background
= 0;
950 if ( m_textBackgroundColour
.Ok() )
952 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
955 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
958 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
959 text
.c_str(), text
.length()) == 0 )
961 wxLogLastError("TextOut");
964 // restore the old parameters (text foreground colour may be left because
965 // it never is set to anything else, but background should remain
966 // transparent even if we just drew an opaque string)
967 if ( m_textBackgroundColour
.Ok() )
968 (void)SetBkColor(GetHdc(), old_background
);
970 SetBkMode(GetHdc(), TRANSPARENT
);
973 void wxDC::DoDrawRotatedText(const wxString
& text
,
974 wxCoord x
, wxCoord y
,
977 // we test that we have some font because otherwise we should still use the
978 // "else" part below to avoid that DrawRotatedText(angle = 180) and
979 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
980 // font for drawing rotated fonts unfortunately)
981 if ( (angle
== 0.0) && m_font
.Ok() )
983 DoDrawText(text
, x
, y
);
987 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
988 // can't have non zero orientation/escapement
989 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
990 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
992 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
994 wxLogLastError("GetObject(hfont)");
997 // GDI wants the angle in tenth of degree
998 long angle10
= (long)(angle
* 10);
999 lf
.lfEscapement
= angle10
;
1000 lf
. lfOrientation
= angle10
;
1002 hfont
= ::CreateFontIndirect(&lf
);
1005 wxLogLastError("CreateFont");
1009 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1011 DrawAnyText(text
, x
, y
);
1013 (void)::SelectObject(GetHdc(), hfontOld
);
1014 (void)::DeleteObject(hfont
);
1017 // call the bounding box by adding all four vertices of the rectangle
1018 // containing the text to it (simpler and probably not slower than
1019 // determining which of them is really topmost/leftmost/...)
1021 GetTextExtent(text
, &w
, &h
);
1023 double rad
= DegToRad(angle
);
1025 // "upper left" and "upper right"
1026 CalcBoundingBox(x
, y
);
1027 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
1029 // "bottom left" and "bottom right"
1030 x
+= (wxCoord
)(h
*sin(rad
));
1031 y
+= (wxCoord
)(h
*cos(rad
));
1032 CalcBoundingBox(x
, y
);
1033 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
1037 // ---------------------------------------------------------------------------
1039 // ---------------------------------------------------------------------------
1041 void wxDC::SetPalette(const wxPalette
& palette
)
1043 // Set the old object temporarily, in case the assignment deletes an object
1044 // that's not yet selected out.
1047 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
1051 m_palette
= palette
;
1053 if (!m_palette
.Ok())
1055 // Setting a NULL colourmap is a way of restoring
1056 // the original colourmap
1059 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
1066 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
1068 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
1070 m_oldPalette
= (WXHPALETTE
) oldPal
;
1072 ::RealizePalette(GetHdc());
1076 void wxDC::SetFont(const wxFont
& the_font
)
1078 // Set the old object temporarily, in case the assignment deletes an object
1079 // that's not yet selected out.
1082 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1091 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1095 if (m_font
.Ok() && m_font
.GetResourceHandle())
1097 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1098 if (f
== (HFONT
) NULL
)
1100 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1103 m_oldFont
= (WXHFONT
) f
;
1107 void wxDC::SetPen(const wxPen
& pen
)
1109 // Set the old object temporarily, in case the assignment deletes an object
1110 // that's not yet selected out.
1113 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1122 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1128 if (m_pen
.GetResourceHandle())
1130 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1132 m_oldPen
= (WXHPEN
) p
;
1137 void wxDC::SetBrush(const wxBrush
& brush
)
1139 // Set the old object temporarily, in case the assignment deletes an object
1140 // that's not yet selected out.
1143 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1152 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1158 // to make sure the brush is alligned with the logical coordinates
1159 wxBitmap
*stipple
= m_brush
.GetStipple();
1160 if ( stipple
&& stipple
->Ok() )
1162 ::SetBrushOrgEx(GetHdc(),
1163 m_deviceOriginX
% stipple
->GetWidth(),
1164 m_deviceOriginY
% stipple
->GetHeight(),
1165 NULL
); // don't need previous brush origin
1168 if ( m_brush
.GetResourceHandle() )
1171 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1173 m_oldBrush
= (WXHBRUSH
) b
;
1178 void wxDC::SetBackground(const wxBrush
& brush
)
1180 m_backgroundBrush
= brush
;
1182 if (!m_backgroundBrush
.Ok())
1187 bool customColours
= TRUE
;
1188 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1189 // change background colours from the control-panel specified colours.
1190 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1191 customColours
= FALSE
;
1195 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1197 m_canvas
->SetTransparent(TRUE
);
1201 // New behaviour, 10/2/99: setting the background brush of a DC
1202 // doesn't affect the window background colour. However,
1203 // I'm leaving in the transparency setting because it's needed by
1204 // various controls (e.g. wxStaticText) to determine whether to draw
1205 // transparently or not. TODO: maybe this should be a new function
1206 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1208 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1209 m_canvas
->SetTransparent(FALSE
);
1213 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1215 (void)SetBkColor(GetHdc(), new_color
);
1219 void wxDC::SetBackgroundMode(int mode
)
1221 m_backgroundMode
= mode
;
1223 // SetBackgroundColour now only refers to text background
1224 // and m_backgroundMode is used there
1227 if (m_backgroundMode == wxTRANSPARENT)
1228 ::SetBkMode(GetHdc(), TRANSPARENT);
1230 ::SetBkMode(GetHdc(), OPAQUE);
1234 void wxDC::SetLogicalFunction(int function
)
1236 m_logicalFunction
= function
;
1241 void wxDC::SetRop(WXHDC dc
)
1243 if ( !dc
|| m_logicalFunction
< 0 )
1248 switch (m_logicalFunction
)
1250 case wxCLEAR
: rop
= R2_BLACK
; break;
1251 case wxXOR
: rop
= R2_XORPEN
; break;
1252 case wxINVERT
: rop
= R2_NOT
; break;
1253 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1254 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1255 case wxCOPY
: rop
= R2_COPYPEN
; break;
1256 case wxAND
: rop
= R2_MASKPEN
; break;
1257 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1258 case wxNO_OP
: rop
= R2_NOP
; break;
1259 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1260 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1261 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1262 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1263 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1264 case wxOR
: rop
= R2_MERGEPEN
; break;
1265 case wxSET
: rop
= R2_WHITE
; break;
1268 wxFAIL_MSG( wxT("unsupported logical function") );
1272 SetROP2(GetHdc(), rop
);
1275 bool wxDC::StartDoc(const wxString
& message
)
1277 // We might be previewing, so return TRUE to let it continue.
1285 void wxDC::StartPage()
1289 void wxDC::EndPage()
1293 // ---------------------------------------------------------------------------
1295 // ---------------------------------------------------------------------------
1297 wxCoord
wxDC::GetCharHeight() const
1299 TEXTMETRIC lpTextMetric
;
1301 GetTextMetrics(GetHdc(), &lpTextMetric
);
1303 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1306 wxCoord
wxDC::GetCharWidth() const
1308 TEXTMETRIC lpTextMetric
;
1310 GetTextMetrics(GetHdc(), &lpTextMetric
);
1312 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1315 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1316 wxCoord
*descent
, wxCoord
*externalLeading
,
1317 wxFont
*theFont
) const
1319 wxFont
*fontToUse
= (wxFont
*) theFont
;
1321 fontToUse
= (wxFont
*) &m_font
;
1326 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1327 GetTextMetrics(GetHdc(), &tm
);
1329 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1330 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1331 if (descent
) *descent
= tm
.tmDescent
;
1332 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1335 void wxDC::SetMapMode(int mode
)
1337 m_mappingMode
= mode
;
1339 int pixel_width
= 0;
1340 int pixel_height
= 0;
1344 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1345 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1346 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1347 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1349 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1354 double mm2pixelsX
= pixel_width
/mm_width
;
1355 double mm2pixelsY
= pixel_height
/mm_height
;
1361 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1362 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1367 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1368 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1373 m_logicalScaleX
= mm2pixelsX
;
1374 m_logicalScaleY
= mm2pixelsY
;
1379 m_logicalScaleX
= (mm2pixelsX
/10.0);
1380 m_logicalScaleY
= (mm2pixelsY
/10.0);
1386 m_logicalScaleX
= 1.0;
1387 m_logicalScaleY
= 1.0;
1392 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1393 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1395 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1396 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1397 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1398 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1399 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1400 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1403 void wxDC::SetUserScale(double x
, double y
)
1408 SetMapMode(m_mappingMode
);
1411 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1413 m_signX
= xLeftRight
? 1 : -1;
1414 m_signY
= yBottomUp
? -1 : 1;
1416 SetMapMode(m_mappingMode
);
1419 void wxDC::SetSystemScale(double x
, double y
)
1424 SetMapMode(m_mappingMode
);
1427 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1429 m_logicalOriginX
= x
;
1430 m_logicalOriginY
= y
;
1432 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1435 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1437 m_deviceOriginX
= x
;
1438 m_deviceOriginY
= y
;
1440 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1443 // ---------------------------------------------------------------------------
1444 // coordinates transformations
1445 // ---------------------------------------------------------------------------
1447 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1449 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1452 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1454 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1457 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1459 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1462 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1464 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1467 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1469 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1472 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1474 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1477 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1479 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1482 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1484 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1487 // ---------------------------------------------------------------------------
1489 // ---------------------------------------------------------------------------
1491 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1492 wxCoord width
, wxCoord height
,
1493 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1494 int rop
, bool useMask
)
1496 wxMask
*mask
= NULL
;
1499 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1500 mask
= bmp
.GetMask();
1502 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1504 // don't give assert here because this would break existing
1505 // programs - just silently ignore useMask parameter
1510 COLORREF old_textground
= ::GetTextColor(GetHdc());
1511 COLORREF old_background
= ::GetBkColor(GetHdc());
1512 if (m_textForegroundColour
.Ok())
1514 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1516 if (m_textBackgroundColour
.Ok())
1518 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1521 DWORD dwRop
= SRCCOPY
;
1524 case wxXOR
: dwRop
= SRCINVERT
; break;
1525 case wxINVERT
: dwRop
= DSTINVERT
; break;
1526 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1527 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1528 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1529 case wxSET
: dwRop
= WHITENESS
; break;
1530 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1531 case wxAND
: dwRop
= SRCAND
; break;
1532 case wxOR
: dwRop
= SRCPAINT
; break;
1533 case wxEQUIV
: dwRop
= 0x00990066; break;
1534 case wxNAND
: dwRop
= 0x007700E6; break;
1535 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1536 case wxCOPY
: dwRop
= SRCCOPY
; break;
1537 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1538 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1539 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1541 wxFAIL_MSG( wxT("unsupported logical function") );
1550 // we want the part of the image corresponding to the mask to be
1551 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1552 // meaning of fg and bg is inverted which corresponds to wxWin notion
1553 // of the mask which is also contrary to the Windows one)
1554 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1555 GetHdcOf(*source
), xsrc
, ysrc
,
1556 (HBITMAP
)mask
->GetMaskBitmap(), 0, 0,
1557 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1562 // Blit bitmap with mask
1564 // create a temp buffer bitmap and DCs to access it and the mask
1565 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1566 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1567 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1568 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1569 ::SelectObject(dc_buffer
, buffer_bmap
);
1571 // copy dest to buffer
1572 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1573 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1575 wxLogLastError("BitBlt");
1578 // copy src to buffer using selected raster op
1579 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1580 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1582 wxLogLastError("BitBlt");
1585 // set masked area in buffer to BLACK (pixel value 0)
1586 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1587 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1588 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1589 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1591 wxLogLastError("BitBlt");
1594 // set unmasked area in dest to BLACK
1595 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1596 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1597 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1598 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1600 wxLogLastError("BitBlt");
1602 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1603 ::SetTextColor(GetHdc(), prevCol
);
1605 // OR buffer to dest
1606 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1607 (int)width
, (int)height
,
1608 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1611 wxLogLastError("BitBlt");
1614 // tidy up temporary DCs and bitmap
1615 ::SelectObject(dc_mask
, 0);
1616 ::DeleteDC(dc_mask
);
1617 ::SelectObject(dc_buffer
, 0);
1618 ::DeleteDC(dc_buffer
);
1619 ::DeleteObject(buffer_bmap
);
1622 else // no mask, just BitBlt() it
1624 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1625 (int)width
, (int)height
,
1626 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1629 wxLogLastError("BitBlt");
1632 ::SetTextColor(GetHdc(), old_textground
);
1633 ::SetBkColor(GetHdc(), old_background
);
1638 void wxDC::DoGetSize(int *w
, int *h
) const
1640 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1641 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1644 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1646 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1647 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1650 wxSize
wxDC::GetPPI() const
1652 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1653 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1655 return wxSize(x
, y
);
1658 // For use by wxWindows only, unless custom units are required.
1659 void wxDC::SetLogicalScale(double x
, double y
)
1661 m_logicalScaleX
= x
;
1662 m_logicalScaleY
= y
;
1665 #if WXWIN_COMPATIBILITY
1666 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1667 float *descent
, float *externalLeading
,
1668 wxFont
*theFont
, bool use16bit
) const
1670 wxCoord x1
, y1
, descent1
, externalLeading1
;
1671 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1674 *descent
= descent1
;
1675 if (externalLeading
)
1676 *externalLeading
= externalLeading1
;
1680 // ---------------------------------------------------------------------------
1681 // spline drawing code
1682 // ---------------------------------------------------------------------------
1686 class wxSpline
: public wxObject
1692 wxSpline(wxList
*list
);
1693 void DeletePoints();
1695 // Doesn't delete points
1699 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1701 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1702 double a3
, double b3
, double a4
, double b4
);
1703 void wx_clear_stack();
1704 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1705 double *y3
, double *x4
, double *y4
);
1706 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1707 double x4
, double y4
);
1708 static bool wx_spline_add_point(double x
, double y
);
1709 static void wx_spline_draw_point_array(wxDC
*dc
);
1710 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1712 void wxDC::DoDrawSpline(wxList
*list
)
1714 wxSpline
spline(list
);
1716 wx_draw_open_spline(this, &spline
);
1719 wxList wx_spline_point_list
;
1721 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1724 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1725 double x1
, y1
, x2
, y2
;
1727 wxNode
*node
= spline
->points
->First();
1728 p
= (wxPoint
*)node
->Data();
1733 node
= node
->Next();
1734 p
= (wxPoint
*)node
->Data();
1738 cx1
= (double)((x1
+ x2
) / 2);
1739 cy1
= (double)((y1
+ y2
) / 2);
1740 cx2
= (double)((cx1
+ x2
) / 2);
1741 cy2
= (double)((cy1
+ y2
) / 2);
1743 wx_spline_add_point(x1
, y1
);
1745 while ((node
= node
->Next()) != NULL
)
1747 p
= (wxPoint
*)node
->Data();
1752 cx4
= (double)(x1
+ x2
) / 2;
1753 cy4
= (double)(y1
+ y2
) / 2;
1754 cx3
= (double)(x1
+ cx4
) / 2;
1755 cy3
= (double)(y1
+ cy4
) / 2;
1757 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1761 cx2
= (double)(cx1
+ x2
) / 2;
1762 cy2
= (double)(cy1
+ y2
) / 2;
1765 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1766 wx_spline_add_point(x2
, y2
);
1768 wx_spline_draw_point_array(dc
);
1772 /********************* CURVES FOR SPLINES *****************************
1774 The following spline drawing routine is from
1776 "An Algorithm for High-Speed Curve Generation"
1777 by George Merrill Chaikin,
1778 Computer Graphics and Image Processing, 3, Academic Press,
1783 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1784 Computer Graphics and Image Processing, 4, Academic Press,
1787 ***********************************************************************/
1789 #define half(z1, z2) ((z1+z2)/2.0)
1792 /* iterative version */
1794 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1797 register double xmid
, ymid
;
1798 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1801 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1803 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1804 xmid
= (double)half(x2
, x3
);
1805 ymid
= (double)half(y2
, y3
);
1806 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1807 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1808 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1809 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1811 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1812 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1813 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1814 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1820 /* utilities used by spline drawing routines */
1823 typedef struct wx_spline_stack_struct
{
1824 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1828 #define SPLINE_STACK_DEPTH 20
1829 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1830 static Stack
*wx_stack_top
;
1831 static int wx_stack_count
;
1833 void wx_clear_stack()
1835 wx_stack_top
= wx_spline_stack
;
1839 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1841 wx_stack_top
->x1
= x1
;
1842 wx_stack_top
->y1
= y1
;
1843 wx_stack_top
->x2
= x2
;
1844 wx_stack_top
->y2
= y2
;
1845 wx_stack_top
->x3
= x3
;
1846 wx_stack_top
->y3
= y3
;
1847 wx_stack_top
->x4
= x4
;
1848 wx_stack_top
->y4
= y4
;
1853 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1854 double *x3
, double *y3
, double *x4
, double *y4
)
1856 if (wx_stack_count
== 0)
1860 *x1
= wx_stack_top
->x1
;
1861 *y1
= wx_stack_top
->y1
;
1862 *x2
= wx_stack_top
->x2
;
1863 *y2
= wx_stack_top
->y2
;
1864 *x3
= wx_stack_top
->x3
;
1865 *y3
= wx_stack_top
->y3
;
1866 *x4
= wx_stack_top
->x4
;
1867 *y4
= wx_stack_top
->y4
;
1871 static bool wx_spline_add_point(double x
, double y
)
1873 wxPoint
*point
= new wxPoint
;
1876 wx_spline_point_list
.Append((wxObject
*)point
);
1880 static void wx_spline_draw_point_array(wxDC
*dc
)
1882 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1883 wxNode
*node
= wx_spline_point_list
.First();
1886 wxPoint
*point
= (wxPoint
*)node
->Data();
1889 node
= wx_spline_point_list
.First();
1893 wxSpline::wxSpline(wxList
*list
)
1898 wxSpline::~wxSpline()
1902 void wxSpline::DeletePoints()
1904 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1906 wxPoint
*point
= (wxPoint
*)node
->Data();
1914 #endif // wxUSE_SPLINES