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() )
1163 ::SetBrushOrgEx(GetHdc(),
1164 m_deviceOriginX
% stipple
->GetWidth(),
1165 m_deviceOriginY
% stipple
->GetHeight(),
1166 NULL
); // don't need previous brush origin
1168 ::SetBrushOrg(GetHdc(),
1169 m_deviceOriginX
% stipple
->GetWidth(),
1170 m_deviceOriginY
% stipple
->GetHeight());
1174 if ( m_brush
.GetResourceHandle() )
1177 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1179 m_oldBrush
= (WXHBRUSH
) b
;
1184 void wxDC::SetBackground(const wxBrush
& brush
)
1186 m_backgroundBrush
= brush
;
1188 if (!m_backgroundBrush
.Ok())
1193 bool customColours
= TRUE
;
1194 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1195 // change background colours from the control-panel specified colours.
1196 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1197 customColours
= FALSE
;
1201 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1203 m_canvas
->SetTransparent(TRUE
);
1207 // New behaviour, 10/2/99: setting the background brush of a DC
1208 // doesn't affect the window background colour. However,
1209 // I'm leaving in the transparency setting because it's needed by
1210 // various controls (e.g. wxStaticText) to determine whether to draw
1211 // transparently or not. TODO: maybe this should be a new function
1212 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1214 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1215 m_canvas
->SetTransparent(FALSE
);
1219 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1221 (void)SetBkColor(GetHdc(), new_color
);
1225 void wxDC::SetBackgroundMode(int mode
)
1227 m_backgroundMode
= mode
;
1229 // SetBackgroundColour now only refers to text background
1230 // and m_backgroundMode is used there
1233 if (m_backgroundMode == wxTRANSPARENT)
1234 ::SetBkMode(GetHdc(), TRANSPARENT);
1236 ::SetBkMode(GetHdc(), OPAQUE);
1240 void wxDC::SetLogicalFunction(int function
)
1242 m_logicalFunction
= function
;
1247 void wxDC::SetRop(WXHDC dc
)
1249 if ( !dc
|| m_logicalFunction
< 0 )
1254 switch (m_logicalFunction
)
1256 case wxCLEAR
: rop
= R2_BLACK
; break;
1257 case wxXOR
: rop
= R2_XORPEN
; break;
1258 case wxINVERT
: rop
= R2_NOT
; break;
1259 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1260 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1261 case wxCOPY
: rop
= R2_COPYPEN
; break;
1262 case wxAND
: rop
= R2_MASKPEN
; break;
1263 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1264 case wxNO_OP
: rop
= R2_NOP
; break;
1265 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1266 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1267 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1268 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1269 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1270 case wxOR
: rop
= R2_MERGEPEN
; break;
1271 case wxSET
: rop
= R2_WHITE
; break;
1274 wxFAIL_MSG( wxT("unsupported logical function") );
1278 SetROP2(GetHdc(), rop
);
1281 bool wxDC::StartDoc(const wxString
& message
)
1283 // We might be previewing, so return TRUE to let it continue.
1291 void wxDC::StartPage()
1295 void wxDC::EndPage()
1299 // ---------------------------------------------------------------------------
1301 // ---------------------------------------------------------------------------
1303 wxCoord
wxDC::GetCharHeight() const
1305 TEXTMETRIC lpTextMetric
;
1307 GetTextMetrics(GetHdc(), &lpTextMetric
);
1309 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1312 wxCoord
wxDC::GetCharWidth() const
1314 TEXTMETRIC lpTextMetric
;
1316 GetTextMetrics(GetHdc(), &lpTextMetric
);
1318 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1321 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1322 wxCoord
*descent
, wxCoord
*externalLeading
,
1323 wxFont
*theFont
) const
1325 wxFont
*fontToUse
= (wxFont
*) theFont
;
1327 fontToUse
= (wxFont
*) &m_font
;
1332 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1333 GetTextMetrics(GetHdc(), &tm
);
1335 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1336 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1337 if (descent
) *descent
= tm
.tmDescent
;
1338 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1341 void wxDC::SetMapMode(int mode
)
1343 m_mappingMode
= mode
;
1345 int pixel_width
= 0;
1346 int pixel_height
= 0;
1350 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1351 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1352 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1353 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1355 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1360 double mm2pixelsX
= pixel_width
/mm_width
;
1361 double mm2pixelsY
= pixel_height
/mm_height
;
1367 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1368 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1373 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1374 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1379 m_logicalScaleX
= mm2pixelsX
;
1380 m_logicalScaleY
= mm2pixelsY
;
1385 m_logicalScaleX
= (mm2pixelsX
/10.0);
1386 m_logicalScaleY
= (mm2pixelsY
/10.0);
1392 m_logicalScaleX
= 1.0;
1393 m_logicalScaleY
= 1.0;
1398 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1399 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1401 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1402 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1403 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1404 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1405 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1406 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1409 void wxDC::SetUserScale(double x
, double y
)
1414 SetMapMode(m_mappingMode
);
1417 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1419 m_signX
= xLeftRight
? 1 : -1;
1420 m_signY
= yBottomUp
? -1 : 1;
1422 SetMapMode(m_mappingMode
);
1425 void wxDC::SetSystemScale(double x
, double y
)
1430 SetMapMode(m_mappingMode
);
1433 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1435 m_logicalOriginX
= x
;
1436 m_logicalOriginY
= y
;
1438 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1441 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1443 m_deviceOriginX
= x
;
1444 m_deviceOriginY
= y
;
1446 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1449 // ---------------------------------------------------------------------------
1450 // coordinates transformations
1451 // ---------------------------------------------------------------------------
1453 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1455 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1458 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1460 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1463 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1465 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1468 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1470 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1473 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1475 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1478 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1480 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1483 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1485 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1488 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1490 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1493 // ---------------------------------------------------------------------------
1495 // ---------------------------------------------------------------------------
1497 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1498 wxCoord width
, wxCoord height
,
1499 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1500 int rop
, bool useMask
)
1502 wxMask
*mask
= NULL
;
1505 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1506 mask
= bmp
.GetMask();
1508 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1510 // don't give assert here because this would break existing
1511 // programs - just silently ignore useMask parameter
1516 COLORREF old_textground
= ::GetTextColor(GetHdc());
1517 COLORREF old_background
= ::GetBkColor(GetHdc());
1518 if (m_textForegroundColour
.Ok())
1520 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1522 if (m_textBackgroundColour
.Ok())
1524 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1527 DWORD dwRop
= SRCCOPY
;
1530 case wxXOR
: dwRop
= SRCINVERT
; break;
1531 case wxINVERT
: dwRop
= DSTINVERT
; break;
1532 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1533 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1534 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1535 case wxSET
: dwRop
= WHITENESS
; break;
1536 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1537 case wxAND
: dwRop
= SRCAND
; break;
1538 case wxOR
: dwRop
= SRCPAINT
; break;
1539 case wxEQUIV
: dwRop
= 0x00990066; break;
1540 case wxNAND
: dwRop
= 0x007700E6; break;
1541 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1542 case wxCOPY
: dwRop
= SRCCOPY
; break;
1543 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1544 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1545 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1547 wxFAIL_MSG( wxT("unsupported logical function") );
1556 // we want the part of the image corresponding to the mask to be
1557 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1558 // meaning of fg and bg is inverted which corresponds to wxWin notion
1559 // of the mask which is also contrary to the Windows one)
1560 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1561 GetHdcOf(*source
), xsrc
, ysrc
,
1562 (HBITMAP
)mask
->GetMaskBitmap(), 0, 0,
1563 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1568 // Blit bitmap with mask
1570 // create a temp buffer bitmap and DCs to access it and the mask
1571 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1572 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1573 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1574 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1575 ::SelectObject(dc_buffer
, buffer_bmap
);
1577 // copy dest to buffer
1578 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1579 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1581 wxLogLastError("BitBlt");
1584 // copy src to buffer using selected raster op
1585 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1586 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1588 wxLogLastError("BitBlt");
1591 // set masked area in buffer to BLACK (pixel value 0)
1592 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1593 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1594 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1595 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1597 wxLogLastError("BitBlt");
1600 // set unmasked area in dest to BLACK
1601 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1602 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1603 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1604 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1606 wxLogLastError("BitBlt");
1608 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1609 ::SetTextColor(GetHdc(), prevCol
);
1611 // OR buffer to dest
1612 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1613 (int)width
, (int)height
,
1614 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1617 wxLogLastError("BitBlt");
1620 // tidy up temporary DCs and bitmap
1621 ::SelectObject(dc_mask
, 0);
1622 ::DeleteDC(dc_mask
);
1623 ::SelectObject(dc_buffer
, 0);
1624 ::DeleteDC(dc_buffer
);
1625 ::DeleteObject(buffer_bmap
);
1628 else // no mask, just BitBlt() it
1630 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1631 (int)width
, (int)height
,
1632 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1635 wxLogLastError("BitBlt");
1638 ::SetTextColor(GetHdc(), old_textground
);
1639 ::SetBkColor(GetHdc(), old_background
);
1644 void wxDC::DoGetSize(int *w
, int *h
) const
1646 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1647 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1650 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1652 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1653 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1656 wxSize
wxDC::GetPPI() const
1658 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1659 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1661 return wxSize(x
, y
);
1664 // For use by wxWindows only, unless custom units are required.
1665 void wxDC::SetLogicalScale(double x
, double y
)
1667 m_logicalScaleX
= x
;
1668 m_logicalScaleY
= y
;
1671 #if WXWIN_COMPATIBILITY
1672 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1673 float *descent
, float *externalLeading
,
1674 wxFont
*theFont
, bool use16bit
) const
1676 wxCoord x1
, y1
, descent1
, externalLeading1
;
1677 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1680 *descent
= descent1
;
1681 if (externalLeading
)
1682 *externalLeading
= externalLeading1
;
1686 // ---------------------------------------------------------------------------
1687 // spline drawing code
1688 // ---------------------------------------------------------------------------
1692 class wxSpline
: public wxObject
1698 wxSpline(wxList
*list
);
1699 void DeletePoints();
1701 // Doesn't delete points
1705 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1707 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1708 double a3
, double b3
, double a4
, double b4
);
1709 void wx_clear_stack();
1710 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1711 double *y3
, double *x4
, double *y4
);
1712 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1713 double x4
, double y4
);
1714 static bool wx_spline_add_point(double x
, double y
);
1715 static void wx_spline_draw_point_array(wxDC
*dc
);
1716 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1718 void wxDC::DoDrawSpline(wxList
*list
)
1720 wxSpline
spline(list
);
1722 wx_draw_open_spline(this, &spline
);
1725 wxList wx_spline_point_list
;
1727 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1730 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1731 double x1
, y1
, x2
, y2
;
1733 wxNode
*node
= spline
->points
->First();
1734 p
= (wxPoint
*)node
->Data();
1739 node
= node
->Next();
1740 p
= (wxPoint
*)node
->Data();
1744 cx1
= (double)((x1
+ x2
) / 2);
1745 cy1
= (double)((y1
+ y2
) / 2);
1746 cx2
= (double)((cx1
+ x2
) / 2);
1747 cy2
= (double)((cy1
+ y2
) / 2);
1749 wx_spline_add_point(x1
, y1
);
1751 while ((node
= node
->Next()) != NULL
)
1753 p
= (wxPoint
*)node
->Data();
1758 cx4
= (double)(x1
+ x2
) / 2;
1759 cy4
= (double)(y1
+ y2
) / 2;
1760 cx3
= (double)(x1
+ cx4
) / 2;
1761 cy3
= (double)(y1
+ cy4
) / 2;
1763 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1767 cx2
= (double)(cx1
+ x2
) / 2;
1768 cy2
= (double)(cy1
+ y2
) / 2;
1771 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1772 wx_spline_add_point(x2
, y2
);
1774 wx_spline_draw_point_array(dc
);
1778 /********************* CURVES FOR SPLINES *****************************
1780 The following spline drawing routine is from
1782 "An Algorithm for High-Speed Curve Generation"
1783 by George Merrill Chaikin,
1784 Computer Graphics and Image Processing, 3, Academic Press,
1789 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1790 Computer Graphics and Image Processing, 4, Academic Press,
1793 ***********************************************************************/
1795 #define half(z1, z2) ((z1+z2)/2.0)
1798 /* iterative version */
1800 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1803 register double xmid
, ymid
;
1804 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1807 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1809 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1810 xmid
= (double)half(x2
, x3
);
1811 ymid
= (double)half(y2
, y3
);
1812 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1813 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1814 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1815 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1817 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1818 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1819 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1820 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1826 /* utilities used by spline drawing routines */
1829 typedef struct wx_spline_stack_struct
{
1830 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1834 #define SPLINE_STACK_DEPTH 20
1835 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1836 static Stack
*wx_stack_top
;
1837 static int wx_stack_count
;
1839 void wx_clear_stack()
1841 wx_stack_top
= wx_spline_stack
;
1845 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1847 wx_stack_top
->x1
= x1
;
1848 wx_stack_top
->y1
= y1
;
1849 wx_stack_top
->x2
= x2
;
1850 wx_stack_top
->y2
= y2
;
1851 wx_stack_top
->x3
= x3
;
1852 wx_stack_top
->y3
= y3
;
1853 wx_stack_top
->x4
= x4
;
1854 wx_stack_top
->y4
= y4
;
1859 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1860 double *x3
, double *y3
, double *x4
, double *y4
)
1862 if (wx_stack_count
== 0)
1866 *x1
= wx_stack_top
->x1
;
1867 *y1
= wx_stack_top
->y1
;
1868 *x2
= wx_stack_top
->x2
;
1869 *y2
= wx_stack_top
->y2
;
1870 *x3
= wx_stack_top
->x3
;
1871 *y3
= wx_stack_top
->y3
;
1872 *x4
= wx_stack_top
->x4
;
1873 *y4
= wx_stack_top
->y4
;
1877 static bool wx_spline_add_point(double x
, double y
)
1879 wxPoint
*point
= new wxPoint
;
1882 wx_spline_point_list
.Append((wxObject
*)point
);
1886 static void wx_spline_draw_point_array(wxDC
*dc
)
1888 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1889 wxNode
*node
= wx_spline_point_list
.First();
1892 wxPoint
*point
= (wxPoint
*)node
->Data();
1895 node
= wx_spline_point_list
.First();
1899 wxSpline::wxSpline(wxList
*list
)
1904 wxSpline::~wxSpline()
1908 void wxSpline::DeletePoints()
1910 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1912 wxPoint
*point
= (wxPoint
*)node
->Data();
1920 #endif // wxUSE_SPLINES