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 // instead of duplicating the same code which sets and then restores text
90 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
91 // encapsulate this in a small helper class
93 // wxColourChanger: changes the text colours in the ctor if required and
94 // restores them in the dtor
98 wxColourChanger(wxDC
& dc
);
104 COLORREF m_colFgOld
, m_colBgOld
;
109 // ===========================================================================
111 // ===========================================================================
113 // ----------------------------------------------------------------------------
115 // ----------------------------------------------------------------------------
117 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
119 if ( dc
.GetBrush().GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
121 HDC hdc
= GetHdcOf(dc
);
122 m_colFgOld
= ::GetTextColor(hdc
);
123 m_colBgOld
= ::GetBkColor(hdc
);
125 // note that Windows convention is opposite to wxWindows one, this is
126 // why text colour becomes the background one and vice versa
127 const wxColour
& colFg
= dc
.GetTextForeground();
130 ::SetBkColor(hdc
, colFg
.GetPixel());
133 const wxColour
& colBg
= dc
.GetTextBackground();
136 ::SetTextColor(hdc
, colBg
.GetPixel());
140 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
143 // flag which telsl us to undo changes in the dtor
148 // nothing done, nothing to undo
153 wxColourChanger::~wxColourChanger()
157 // restore the colours we changed
158 HDC hdc
= GetHdcOf(m_dc
);
160 ::SetBkMode(hdc
, TRANSPARENT
);
161 ::SetTextColor(hdc
, m_colFgOld
);
162 ::SetBkColor(hdc
, m_colBgOld
);
166 // ---------------------------------------------------------------------------
168 // ---------------------------------------------------------------------------
170 // Default constructor
184 m_windowExtX
= VIEWPORT_EXTENT
;
185 m_windowExtY
= VIEWPORT_EXTENT
;
194 SelectOldObjects(m_hDC
);
196 if ( m_canvas
== NULL
)
197 ::DeleteDC(GetHdc());
199 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
205 // This will select current objects out of the DC,
206 // which is what you have to do before deleting the
208 void wxDC::SelectOldObjects(WXHDC dc
)
214 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
215 if (m_selectedBitmap
.Ok())
217 m_selectedBitmap
.SetSelectedInto(NULL
);
223 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
228 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
233 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
238 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
243 m_brush
= wxNullBrush
;
245 m_palette
= wxNullPalette
;
247 m_backgroundBrush
= wxNullBrush
;
248 m_selectedBitmap
= wxNullBitmap
;
251 // ---------------------------------------------------------------------------
253 // ---------------------------------------------------------------------------
255 #define DO_SET_CLIPPING_BOX() \
259 GetClipBox(GetHdc(), &rect); \
261 m_clipX1 = (wxCoord) XDEV2LOG(rect.left); \
262 m_clipY1 = (wxCoord) YDEV2LOG(rect.top); \
263 m_clipX2 = (wxCoord) XDEV2LOG(rect.right); \
264 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); \
267 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
270 IntersectClipRect(GetHdc(), XLOG2DEV(cx
), YLOG2DEV(cy
),
271 XLOG2DEV(cx
+ cw
), YLOG2DEV(cy
+ ch
));
272 DO_SET_CLIPPING_BOX()
275 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
277 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
282 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
284 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
287 DO_SET_CLIPPING_BOX()
290 void wxDC::DestroyClippingRegion()
292 if (m_clipping
&& m_hDC
)
294 // TODO: this should restore the previous clipping region,
295 // so that OnPaint processing works correctly, and the update clipping region
296 // doesn't get destroyed after the first DestroyClippingRegion.
297 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
298 SelectClipRgn(GetHdc(), rgn
);
304 // ---------------------------------------------------------------------------
305 // query capabilities
306 // ---------------------------------------------------------------------------
308 bool wxDC::CanDrawBitmap() const
313 bool wxDC::CanGetTextExtent() const
315 // What sort of display is it?
316 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
318 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
321 int wxDC::GetDepth() const
323 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
326 // ---------------------------------------------------------------------------
328 // ---------------------------------------------------------------------------
335 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
339 // No, I think we should simply ignore this if printing on e.g.
341 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
342 if (!m_selectedBitmap
.Ok())
345 rect
.left
= 0; rect
.top
= 0;
346 rect
.right
= m_selectedBitmap
.GetWidth();
347 rect
.bottom
= m_selectedBitmap
.GetHeight();
350 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
352 DWORD colour
= GetBkColor(GetHdc());
353 HBRUSH brush
= CreateSolidBrush(colour
);
354 FillRect(GetHdc(), &rect
, brush
);
357 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
358 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
359 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
360 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
361 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
364 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
366 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
368 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
371 // quoting from the MSDN docs:
373 // Following are some of the reasons this function might fail:
375 // * The filling could not be completed.
376 // * The specified point has the boundary color specified by the
377 // crColor parameter (if FLOODFILLBORDER was requested).
378 // * The specified point does not have the color specified by
379 // crColor (if FLOODFILLSURFACE was requested)
380 // * The point is outside the clipping region that is, it is not
381 // visible on the device.
383 wxLogLastError(wxT("ExtFloodFill"));
386 CalcBoundingBox(x
, y
);
389 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
391 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
393 // get the color of the pixel
394 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
396 wxRGBToColour(*col
, pixelcolor
);
401 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
403 wxCoord x1
= x
-VIEWPORT_EXTENT
;
404 wxCoord y1
= y
-VIEWPORT_EXTENT
;
405 wxCoord x2
= x
+VIEWPORT_EXTENT
;
406 wxCoord y2
= y
+VIEWPORT_EXTENT
;
408 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
409 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
411 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
412 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
414 CalcBoundingBox(x1
, y1
);
415 CalcBoundingBox(x2
, y2
);
418 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
420 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
421 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
423 // Normalization: Windows doesn't draw the last point of the line.
424 // But apparently neither does GTK+, so we take it out again.
425 // (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2));
427 CalcBoundingBox(x1
, y1
);
428 CalcBoundingBox(x2
, y2
);
431 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
432 // and ending at (x2, y2)
433 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
434 wxCoord x2
, wxCoord y2
,
435 wxCoord xc
, wxCoord yc
)
437 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
441 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
442 wxCoord r
= (wxCoord
)radius
;
444 // treat the special case of full circle separately
445 if ( x1
== x2
&& y1
== y2
)
447 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
451 wxCoord xx1
= XLOG2DEV(x1
);
452 wxCoord yy1
= YLOG2DEV(y1
);
453 wxCoord xx2
= XLOG2DEV(x2
);
454 wxCoord yy2
= YLOG2DEV(y2
);
455 wxCoord xxc
= XLOG2DEV(xc
);
456 wxCoord yyc
= YLOG2DEV(yc
);
457 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
459 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
460 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
461 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
462 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
464 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
466 // Have to add 1 to bottom-right corner of rectangle
467 // to make semi-circles look right (crooked line otherwise).
468 // Unfortunately this is not a reliable method, depends
469 // on the size of shape.
470 // TODO: figure out why this happens!
471 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
475 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
478 CalcBoundingBox(xc
- r
, yc
- r
);
479 CalcBoundingBox(xc
+ r
, yc
+ r
);
482 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
483 wxCoord width
, wxCoord height
)
485 wxCoord x2
= x1
+ width
,
488 #if defined(__WIN32__) && !defined(__SC__)
495 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
497 // In WIN16, draw a cross
498 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
499 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
500 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
501 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
502 ::SetROP2(GetHdc(), R2_COPYPEN
);
503 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
504 MoveTo(GetHdc(), x1
, y1
);
505 LineTo(GetHdc(), x2
, y2
);
506 MoveTo(GetHdc(), x2
, y1
);
507 LineTo(GetHdc(), x1
, y2
);
508 ::SelectObject(GetHdc(), hPenOld
);
509 ::SelectObject(GetHdc(), hBrushOld
);
510 ::DeleteObject(blackPen
);
513 CalcBoundingBox(x1
, y1
);
514 CalcBoundingBox(x2
, y2
);
517 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
519 COLORREF color
= 0x00ffffff;
522 color
= m_pen
.GetColour().GetPixel();
525 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
527 CalcBoundingBox(x
, y
);
530 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
532 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
534 // Do things less efficiently if we have offsets
535 if (xoffset
!= 0 || yoffset
!= 0)
537 POINT
*cpoints
= new POINT
[n
];
539 for (i
= 0; i
< n
; i
++)
541 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
542 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
544 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
546 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
547 (void)Polygon(GetHdc(), cpoints
, n
);
548 SetPolyFillMode(GetHdc(),prev
);
554 for (i
= 0; i
< n
; i
++)
555 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
557 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
558 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
559 SetPolyFillMode(GetHdc(),prev
);
563 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
565 // Do things less efficiently if we have offsets
566 if (xoffset
!= 0 || yoffset
!= 0)
568 POINT
*cpoints
= new POINT
[n
];
570 for (i
= 0; i
< n
; i
++)
572 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
573 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
575 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
577 (void)Polyline(GetHdc(), cpoints
, n
);
583 for (i
= 0; i
< n
; i
++)
584 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
586 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
590 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
592 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
594 wxCoord x2
= x
+ width
;
595 wxCoord y2
= y
+ height
;
597 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
600 rect
.left
= XLOG2DEV(x
);
601 rect
.top
= YLOG2DEV(y
);
602 rect
.right
= XLOG2DEV(x2
);
603 rect
.bottom
= YLOG2DEV(y2
);
604 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
608 // Windows draws the filled rectangles without outline (i.e. drawn with a
609 // transparent pen) one pixel smaller in both directions and we want them
610 // to have the same size regardless of which pen is used - adjust
612 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
613 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
619 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
623 CalcBoundingBox(x
, y
);
624 CalcBoundingBox(x2
, y2
);
627 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
629 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
631 // Now, a negative radius value is interpreted to mean
632 // 'the proportion of the smallest X or Y dimension'
636 double smallest
= 0.0;
641 radius
= (- radius
* smallest
);
644 wxCoord x2
= (x
+width
);
645 wxCoord y2
= (y
+height
);
647 // Windows draws the filled rectangles without outline (i.e. drawn with a
648 // transparent pen) one pixel smaller in both directions and we want them
649 // to have the same size regardless of which pen is used - adjust
650 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
656 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
657 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
659 CalcBoundingBox(x
, y
);
660 CalcBoundingBox(x2
, y2
);
663 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
665 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
667 wxCoord x2
= (x
+width
);
668 wxCoord y2
= (y
+height
);
670 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
672 CalcBoundingBox(x
, y
);
673 CalcBoundingBox(x2
, y2
);
676 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
677 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
679 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
684 int rx1
= XLOG2DEV(x
+w
/2);
685 int ry1
= YLOG2DEV(y
+h
/2);
692 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
693 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
694 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
695 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
697 // draw pie with NULL_PEN first and then outline otherwise a line is
698 // drawn from the start and end points to the centre
699 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
702 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
707 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
708 rx1
, ry1
-1, rx2
, ry2
-1);
711 ::SelectObject(GetHdc(), hpenOld
);
713 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
716 CalcBoundingBox(x
, y
);
717 CalcBoundingBox(x2
, y2
);
720 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
722 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
725 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
727 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
730 CalcBoundingBox(x
, y
);
731 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
734 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
736 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
738 int width
= bmp
.GetWidth(),
739 height
= bmp
.GetHeight();
741 HBITMAP hbmpMask
= 0;
745 wxMask
*mask
= bmp
.GetMask();
747 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
751 // don't give assert here because this would break existing
752 // programs - just silently ignore useMask parameter
760 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
761 ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
763 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
765 bool ok
= ::MaskBlt(GetHdc(), x
, y
, width
, height
,
768 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
774 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
777 memDC
.SelectObject(bmp
);
779 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
781 memDC
.SelectObject(wxNullBitmap
);
784 else // no mask, just use BitBlt()
787 HDC memdc
= ::CreateCompatibleDC( cdc
);
788 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
790 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
792 COLORREF old_textground
= ::GetTextColor(GetHdc());
793 COLORREF old_background
= ::GetBkColor(GetHdc());
794 if (m_textForegroundColour
.Ok())
796 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
798 if (m_textBackgroundColour
.Ok())
800 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
803 ::SelectObject( memdc
, hbitmap
);
804 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
807 ::SetTextColor(GetHdc(), old_textground
);
808 ::SetBkColor(GetHdc(), old_background
);
812 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
814 DrawAnyText(text
, x
, y
);
816 // update the bounding box
817 CalcBoundingBox(x
, y
);
820 GetTextExtent(text
, &w
, &h
);
821 CalcBoundingBox(x
+ w
, y
+ h
);
824 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
826 // prepare for drawing the text
827 if ( m_textForegroundColour
.Ok() )
828 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
830 DWORD old_background
= 0;
831 if ( m_textBackgroundColour
.Ok() )
833 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
836 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
839 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
840 text
.c_str(), text
.length()) == 0 )
842 wxLogLastError(wxT("TextOut"));
845 // restore the old parameters (text foreground colour may be left because
846 // it never is set to anything else, but background should remain
847 // transparent even if we just drew an opaque string)
848 if ( m_textBackgroundColour
.Ok() )
849 (void)SetBkColor(GetHdc(), old_background
);
851 SetBkMode(GetHdc(), TRANSPARENT
);
854 void wxDC::DoDrawRotatedText(const wxString
& text
,
855 wxCoord x
, wxCoord y
,
858 // we test that we have some font because otherwise we should still use the
859 // "else" part below to avoid that DrawRotatedText(angle = 180) and
860 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
861 // font for drawing rotated fonts unfortunately)
862 if ( (angle
== 0.0) && m_font
.Ok() )
864 DoDrawText(text
, x
, y
);
868 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
869 // can't have non zero orientation/escapement
870 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
871 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
873 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
875 wxLogLastError(wxT("GetObject(hfont)"));
878 // GDI wants the angle in tenth of degree
879 long angle10
= (long)(angle
* 10);
880 lf
.lfEscapement
= angle10
;
881 lf
. lfOrientation
= angle10
;
883 hfont
= ::CreateFontIndirect(&lf
);
886 wxLogLastError(wxT("CreateFont"));
890 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
892 DrawAnyText(text
, x
, y
);
894 (void)::SelectObject(GetHdc(), hfontOld
);
895 (void)::DeleteObject(hfont
);
898 // call the bounding box by adding all four vertices of the rectangle
899 // containing the text to it (simpler and probably not slower than
900 // determining which of them is really topmost/leftmost/...)
902 GetTextExtent(text
, &w
, &h
);
904 double rad
= DegToRad(angle
);
906 // "upper left" and "upper right"
907 CalcBoundingBox(x
, y
);
908 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
910 // "bottom left" and "bottom right"
911 x
+= (wxCoord
)(h
*sin(rad
));
912 y
+= (wxCoord
)(h
*cos(rad
));
913 CalcBoundingBox(x
, y
);
914 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
918 // ---------------------------------------------------------------------------
920 // ---------------------------------------------------------------------------
922 void wxDC::SetPalette(const wxPalette
& palette
)
924 // Set the old object temporarily, in case the assignment deletes an object
925 // that's not yet selected out.
928 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
936 // Setting a NULL colourmap is a way of restoring
937 // the original colourmap
940 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
947 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
949 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
951 m_oldPalette
= (WXHPALETTE
) oldPal
;
953 ::RealizePalette(GetHdc());
957 void wxDC::SetFont(const wxFont
& the_font
)
959 // Set the old object temporarily, in case the assignment deletes an object
960 // that's not yet selected out.
963 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
972 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
976 if (m_font
.Ok() && m_font
.GetResourceHandle())
978 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
979 if (f
== (HFONT
) NULL
)
981 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
984 m_oldFont
= (WXHFONT
) f
;
988 void wxDC::SetPen(const wxPen
& pen
)
990 // Set the old object temporarily, in case the assignment deletes an object
991 // that's not yet selected out.
994 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1003 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1009 if (m_pen
.GetResourceHandle())
1011 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1013 m_oldPen
= (WXHPEN
) p
;
1018 void wxDC::SetBrush(const wxBrush
& brush
)
1020 // Set the old object temporarily, in case the assignment deletes an object
1021 // that's not yet selected out.
1024 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1033 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1039 // to make sure the brush is alligned with the logical coordinates
1040 wxBitmap
*stipple
= m_brush
.GetStipple();
1041 if ( stipple
&& stipple
->Ok() )
1044 ::SetBrushOrgEx(GetHdc(),
1045 m_deviceOriginX
% stipple
->GetWidth(),
1046 m_deviceOriginY
% stipple
->GetHeight(),
1047 NULL
); // don't need previous brush origin
1049 ::SetBrushOrg(GetHdc(),
1050 m_deviceOriginX
% stipple
->GetWidth(),
1051 m_deviceOriginY
% stipple
->GetHeight());
1055 if ( m_brush
.GetResourceHandle() )
1058 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1060 m_oldBrush
= (WXHBRUSH
) b
;
1065 void wxDC::SetBackground(const wxBrush
& brush
)
1067 m_backgroundBrush
= brush
;
1069 if (!m_backgroundBrush
.Ok())
1074 bool customColours
= TRUE
;
1075 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1076 // change background colours from the control-panel specified colours.
1077 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1078 customColours
= FALSE
;
1082 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1084 m_canvas
->SetTransparent(TRUE
);
1088 // New behaviour, 10/2/99: setting the background brush of a DC
1089 // doesn't affect the window background colour. However,
1090 // I'm leaving in the transparency setting because it's needed by
1091 // various controls (e.g. wxStaticText) to determine whether to draw
1092 // transparently or not. TODO: maybe this should be a new function
1093 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1095 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1096 m_canvas
->SetTransparent(FALSE
);
1100 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1102 (void)SetBkColor(GetHdc(), new_color
);
1106 void wxDC::SetBackgroundMode(int mode
)
1108 m_backgroundMode
= mode
;
1110 // SetBackgroundColour now only refers to text background
1111 // and m_backgroundMode is used there
1114 if (m_backgroundMode == wxTRANSPARENT)
1115 ::SetBkMode(GetHdc(), TRANSPARENT);
1117 ::SetBkMode(GetHdc(), OPAQUE);
1118 Last change: AC 29 Jan 101 8:54 pm
1122 void wxDC::SetLogicalFunction(int function
)
1124 m_logicalFunction
= function
;
1129 void wxDC::SetRop(WXHDC dc
)
1131 if ( !dc
|| m_logicalFunction
< 0 )
1136 switch (m_logicalFunction
)
1138 case wxCLEAR
: rop
= R2_BLACK
; break;
1139 case wxXOR
: rop
= R2_XORPEN
; break;
1140 case wxINVERT
: rop
= R2_NOT
; break;
1141 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1142 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1143 case wxCOPY
: rop
= R2_COPYPEN
; break;
1144 case wxAND
: rop
= R2_MASKPEN
; break;
1145 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1146 case wxNO_OP
: rop
= R2_NOP
; break;
1147 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1148 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1149 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1150 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1151 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1152 case wxOR
: rop
= R2_MERGEPEN
; break;
1153 case wxSET
: rop
= R2_WHITE
; break;
1156 wxFAIL_MSG( wxT("unsupported logical function") );
1160 SetROP2(GetHdc(), rop
);
1163 bool wxDC::StartDoc(const wxString
& message
)
1165 // We might be previewing, so return TRUE to let it continue.
1173 void wxDC::StartPage()
1177 void wxDC::EndPage()
1181 // ---------------------------------------------------------------------------
1183 // ---------------------------------------------------------------------------
1185 wxCoord
wxDC::GetCharHeight() const
1187 TEXTMETRIC lpTextMetric
;
1189 GetTextMetrics(GetHdc(), &lpTextMetric
);
1191 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1194 wxCoord
wxDC::GetCharWidth() const
1196 TEXTMETRIC lpTextMetric
;
1198 GetTextMetrics(GetHdc(), &lpTextMetric
);
1200 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1203 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1204 wxCoord
*descent
, wxCoord
*externalLeading
,
1205 wxFont
*theFont
) const
1207 wxFont
*fontToUse
= (wxFont
*) theFont
;
1209 fontToUse
= (wxFont
*) &m_font
;
1214 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1215 GetTextMetrics(GetHdc(), &tm
);
1217 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1218 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1219 if (descent
) *descent
= tm
.tmDescent
;
1220 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1223 void wxDC::SetMapMode(int mode
)
1225 m_mappingMode
= mode
;
1227 int pixel_width
= 0;
1228 int pixel_height
= 0;
1232 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1233 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1234 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1235 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1237 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1242 double mm2pixelsX
= pixel_width
/mm_width
;
1243 double mm2pixelsY
= pixel_height
/mm_height
;
1249 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1250 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1255 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1256 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1261 m_logicalScaleX
= mm2pixelsX
;
1262 m_logicalScaleY
= mm2pixelsY
;
1267 m_logicalScaleX
= (mm2pixelsX
/10.0);
1268 m_logicalScaleY
= (mm2pixelsY
/10.0);
1274 m_logicalScaleX
= 1.0;
1275 m_logicalScaleY
= 1.0;
1280 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1281 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1283 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1284 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1285 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1286 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1287 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1288 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1291 void wxDC::SetUserScale(double x
, double y
)
1296 SetMapMode(m_mappingMode
);
1299 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1301 m_signX
= xLeftRight
? 1 : -1;
1302 m_signY
= yBottomUp
? -1 : 1;
1304 SetMapMode(m_mappingMode
);
1307 void wxDC::SetSystemScale(double x
, double y
)
1312 SetMapMode(m_mappingMode
);
1315 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1317 m_logicalOriginX
= x
;
1318 m_logicalOriginY
= y
;
1320 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1323 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1325 m_deviceOriginX
= x
;
1326 m_deviceOriginY
= y
;
1328 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1331 // ---------------------------------------------------------------------------
1332 // coordinates transformations
1333 // ---------------------------------------------------------------------------
1335 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1337 double xRel
= x
- m_deviceOriginX
;
1338 xRel
/= m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
;
1339 return (wxCoord
)(xRel
+ m_logicalOriginX
);
1342 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1344 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1347 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1349 double yRel
= y
- m_deviceOriginY
;
1350 yRel
/= m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
;
1351 return (wxCoord
)(yRel
+ m_logicalOriginY
);
1354 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1356 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1359 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1361 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1364 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1366 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1369 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1371 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1374 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1376 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1379 // ---------------------------------------------------------------------------
1381 // ---------------------------------------------------------------------------
1383 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1384 wxCoord width
, wxCoord height
,
1385 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1386 int rop
, bool useMask
)
1388 wxMask
*mask
= NULL
;
1391 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1392 mask
= bmp
.GetMask();
1394 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1396 // don't give assert here because this would break existing
1397 // programs - just silently ignore useMask parameter
1402 COLORREF old_textground
= ::GetTextColor(GetHdc());
1403 COLORREF old_background
= ::GetBkColor(GetHdc());
1404 if (m_textForegroundColour
.Ok())
1406 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1408 if (m_textBackgroundColour
.Ok())
1410 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1413 DWORD dwRop
= SRCCOPY
;
1416 case wxXOR
: dwRop
= SRCINVERT
; break;
1417 case wxINVERT
: dwRop
= DSTINVERT
; break;
1418 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1419 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1420 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1421 case wxSET
: dwRop
= WHITENESS
; break;
1422 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1423 case wxAND
: dwRop
= SRCAND
; break;
1424 case wxOR
: dwRop
= SRCPAINT
; break;
1425 case wxEQUIV
: dwRop
= 0x00990066; break;
1426 case wxNAND
: dwRop
= 0x007700E6; break;
1427 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1428 case wxCOPY
: dwRop
= SRCCOPY
; break;
1429 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1430 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1431 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1433 wxFAIL_MSG( wxT("unsupported logical function") );
1442 // we want the part of the image corresponding to the mask to be
1443 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1444 // meaning of fg and bg is inverted which corresponds to wxWin notion
1445 // of the mask which is also contrary to the Windows one)
1446 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1447 GetHdcOf(*source
), xsrc
, ysrc
,
1448 (HBITMAP
)mask
->GetMaskBitmap(), xsrc
, ysrc
,
1449 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1454 // Blit bitmap with mask
1456 // create a temp buffer bitmap and DCs to access it and the mask
1457 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1458 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1459 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1460 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1461 ::SelectObject(dc_buffer
, buffer_bmap
);
1463 // copy dest to buffer
1464 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1465 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1467 wxLogLastError(wxT("BitBlt"));
1470 // copy src to buffer using selected raster op
1471 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1472 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1474 wxLogLastError(wxT("BitBlt"));
1477 // set masked area in buffer to BLACK (pixel value 0)
1478 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1479 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1480 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1481 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1483 wxLogLastError(wxT("BitBlt"));
1486 // set unmasked area in dest to BLACK
1487 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1488 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1489 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1490 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1492 wxLogLastError(wxT("BitBlt"));
1494 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1495 ::SetTextColor(GetHdc(), prevCol
);
1497 // OR buffer to dest
1498 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1499 (int)width
, (int)height
,
1500 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1503 wxLogLastError(wxT("BitBlt"));
1506 // tidy up temporary DCs and bitmap
1507 ::SelectObject(dc_mask
, 0);
1508 ::DeleteDC(dc_mask
);
1509 ::SelectObject(dc_buffer
, 0);
1510 ::DeleteDC(dc_buffer
);
1511 ::DeleteObject(buffer_bmap
);
1514 else // no mask, just BitBlt() it
1516 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1517 (int)width
, (int)height
,
1518 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1521 wxLogLastError(wxT("BitBlt"));
1524 ::SetTextColor(GetHdc(), old_textground
);
1525 ::SetBkColor(GetHdc(), old_background
);
1530 void wxDC::DoGetSize(int *w
, int *h
) const
1532 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1533 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1536 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1538 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1539 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1542 wxSize
wxDC::GetPPI() const
1544 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1545 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1547 return wxSize(x
, y
);
1550 // For use by wxWindows only, unless custom units are required.
1551 void wxDC::SetLogicalScale(double x
, double y
)
1553 m_logicalScaleX
= x
;
1554 m_logicalScaleY
= y
;
1557 #if WXWIN_COMPATIBILITY
1558 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1559 float *descent
, float *externalLeading
,
1560 wxFont
*theFont
, bool use16bit
) const
1562 wxCoord x1
, y1
, descent1
, externalLeading1
;
1563 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1566 *descent
= descent1
;
1567 if (externalLeading
)
1568 *externalLeading
= externalLeading1
;
1572 // ---------------------------------------------------------------------------
1573 // spline drawing code
1574 // ---------------------------------------------------------------------------
1578 class wxSpline
: public wxObject
1584 wxSpline(wxList
*list
);
1585 void DeletePoints();
1587 // Doesn't delete points
1591 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1593 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1594 double a3
, double b3
, double a4
, double b4
);
1595 void wx_clear_stack();
1596 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1597 double *y3
, double *x4
, double *y4
);
1598 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1599 double x4
, double y4
);
1600 static bool wx_spline_add_point(double x
, double y
);
1601 static void wx_spline_draw_point_array(wxDC
*dc
);
1602 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1604 void wxDC::DoDrawSpline(wxList
*list
)
1606 wxSpline
spline(list
);
1608 wx_draw_open_spline(this, &spline
);
1611 wxList wx_spline_point_list
;
1613 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1616 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1617 double x1
, y1
, x2
, y2
;
1619 wxNode
*node
= spline
->points
->First();
1620 p
= (wxPoint
*)node
->Data();
1625 node
= node
->Next();
1626 p
= (wxPoint
*)node
->Data();
1630 cx1
= (double)((x1
+ x2
) / 2);
1631 cy1
= (double)((y1
+ y2
) / 2);
1632 cx2
= (double)((cx1
+ x2
) / 2);
1633 cy2
= (double)((cy1
+ y2
) / 2);
1635 wx_spline_add_point(x1
, y1
);
1637 while ((node
= node
->Next()) != NULL
)
1639 p
= (wxPoint
*)node
->Data();
1644 cx4
= (double)(x1
+ x2
) / 2;
1645 cy4
= (double)(y1
+ y2
) / 2;
1646 cx3
= (double)(x1
+ cx4
) / 2;
1647 cy3
= (double)(y1
+ cy4
) / 2;
1649 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1653 cx2
= (double)(cx1
+ x2
) / 2;
1654 cy2
= (double)(cy1
+ y2
) / 2;
1657 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1658 wx_spline_add_point(x2
, y2
);
1660 wx_spline_draw_point_array(dc
);
1664 /********************* CURVES FOR SPLINES *****************************
1666 The following spline drawing routine is from
1668 "An Algorithm for High-Speed Curve Generation"
1669 by George Merrill Chaikin,
1670 Computer Graphics and Image Processing, 3, Academic Press,
1675 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1676 Computer Graphics and Image Processing, 4, Academic Press,
1679 ***********************************************************************/
1681 #define half(z1, z2) ((z1+z2)/2.0)
1684 /* iterative version */
1686 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1689 register double xmid
, ymid
;
1690 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1693 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1695 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1696 xmid
= (double)half(x2
, x3
);
1697 ymid
= (double)half(y2
, y3
);
1698 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1699 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1700 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1701 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1703 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1704 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1705 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1706 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1712 /* utilities used by spline drawing routines */
1715 typedef struct wx_spline_stack_struct
{
1716 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1720 #define SPLINE_STACK_DEPTH 20
1721 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1722 static Stack
*wx_stack_top
;
1723 static int wx_stack_count
;
1725 void wx_clear_stack()
1727 wx_stack_top
= wx_spline_stack
;
1731 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1733 wx_stack_top
->x1
= x1
;
1734 wx_stack_top
->y1
= y1
;
1735 wx_stack_top
->x2
= x2
;
1736 wx_stack_top
->y2
= y2
;
1737 wx_stack_top
->x3
= x3
;
1738 wx_stack_top
->y3
= y3
;
1739 wx_stack_top
->x4
= x4
;
1740 wx_stack_top
->y4
= y4
;
1745 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1746 double *x3
, double *y3
, double *x4
, double *y4
)
1748 if (wx_stack_count
== 0)
1752 *x1
= wx_stack_top
->x1
;
1753 *y1
= wx_stack_top
->y1
;
1754 *x2
= wx_stack_top
->x2
;
1755 *y2
= wx_stack_top
->y2
;
1756 *x3
= wx_stack_top
->x3
;
1757 *y3
= wx_stack_top
->y3
;
1758 *x4
= wx_stack_top
->x4
;
1759 *y4
= wx_stack_top
->y4
;
1763 static bool wx_spline_add_point(double x
, double y
)
1765 wxPoint
*point
= new wxPoint
;
1768 wx_spline_point_list
.Append((wxObject
*)point
);
1772 static void wx_spline_draw_point_array(wxDC
*dc
)
1774 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1775 wxNode
*node
= wx_spline_point_list
.First();
1778 wxPoint
*point
= (wxPoint
*)node
->Data();
1781 node
= wx_spline_point_list
.First();
1785 wxSpline::wxSpline(wxList
*list
)
1790 wxSpline::~wxSpline()
1794 void wxSpline::DeletePoints()
1796 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1798 wxPoint
*point
= (wxPoint
*)node
->Data();
1806 #endif // wxUSE_SPLINES