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
51 #if wxUSE_NORLANDER_HEADERS
61 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
63 // ---------------------------------------------------------------------------
65 // ---------------------------------------------------------------------------
67 static const int VIEWPORT_EXTENT
= 1000;
69 static const int MM_POINTS
= 9;
70 static const int MM_METRIC
= 10;
72 // usually this is defined in math.h
74 static const double M_PI
= 3.14159265358979323846;
77 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
78 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
79 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 // convert degrees to radians
86 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
88 // ===========================================================================
90 // ===========================================================================
92 // ---------------------------------------------------------------------------
94 // ---------------------------------------------------------------------------
96 // Default constructor
110 m_windowExtX
= VIEWPORT_EXTENT
;
111 m_windowExtY
= VIEWPORT_EXTENT
;
120 SelectOldObjects(m_hDC
);
122 if ( m_canvas
== NULL
)
123 ::DeleteDC(GetHdc());
125 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
131 // This will select current objects out of the DC,
132 // which is what you have to do before deleting the
134 void wxDC::SelectOldObjects(WXHDC dc
)
140 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
141 if (m_selectedBitmap
.Ok())
143 m_selectedBitmap
.SetSelectedInto(NULL
);
149 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
154 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
159 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
164 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
169 m_brush
= wxNullBrush
;
171 m_palette
= wxNullPalette
;
173 m_backgroundBrush
= wxNullBrush
;
174 m_selectedBitmap
= wxNullBitmap
;
177 // ---------------------------------------------------------------------------
179 // ---------------------------------------------------------------------------
181 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
186 m_clipX2
= (int)(cx
+ cw
);
187 m_clipY2
= (int)(cy
+ ch
);
189 DoClipping((WXHDC
) m_hDC
);
192 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
194 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
196 wxRect box
= region
.GetBox();
201 m_clipX2
= box
.x
+ box
.width
;
202 m_clipY2
= box
.y
+ box
.height
;
205 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
207 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
211 void wxDC::DoClipping(WXHDC dc
)
213 if (m_clipping
&& dc
)
215 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
216 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
220 void wxDC::DestroyClippingRegion()
222 if (m_clipping
&& m_hDC
)
224 // TODO: this should restore the previous clipping region,
225 // so that OnPaint processing works correctly, and the update clipping region
226 // doesn't get destroyed after the first DestroyClippingRegion.
227 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
228 SelectClipRgn(GetHdc(), rgn
);
234 // ---------------------------------------------------------------------------
235 // query capabilities
236 // ---------------------------------------------------------------------------
238 bool wxDC::CanDrawBitmap() const
243 bool wxDC::CanGetTextExtent() const
245 // What sort of display is it?
246 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
248 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
251 int wxDC::GetDepth() const
253 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
256 // ---------------------------------------------------------------------------
258 // ---------------------------------------------------------------------------
265 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
269 // No, I think we should simply ignore this if printing on e.g.
271 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
272 if (!m_selectedBitmap
.Ok())
275 rect
.left
= 0; rect
.top
= 0;
276 rect
.right
= m_selectedBitmap
.GetWidth();
277 rect
.bottom
= m_selectedBitmap
.GetHeight();
280 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
282 DWORD colour
= GetBkColor(GetHdc());
283 HBRUSH brush
= CreateSolidBrush(colour
);
284 FillRect(GetHdc(), &rect
, brush
);
287 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
288 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
289 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
290 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
291 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
294 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
296 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
298 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
301 // quoting from the MSDN docs:
303 // Following are some of the reasons this function might fail:
305 // * The filling could not be completed.
306 // * The specified point has the boundary color specified by the
307 // crColor parameter (if FLOODFILLBORDER was requested).
308 // * The specified point does not have the color specified by
309 // crColor (if FLOODFILLSURFACE was requested)
310 // * The point is outside the clipping region that is, it is not
311 // visible on the device.
313 wxLogLastError("ExtFloodFill");
316 CalcBoundingBox(x
, y
);
319 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
321 // get the color of the pixel
322 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
324 // get the color of the pen
325 COLORREF pencolor
= 0x00ffffff;
328 pencolor
= m_pen
.GetColour().GetPixel();
331 // return the color of the pixel
334 col
->Set(GetRValue(pixelcolor
),
335 GetGValue(pixelcolor
),
336 GetBValue(pixelcolor
));
339 // check, if color of the pixels is the same as the color of the current
340 // pen and return TRUE if it is, FALSE otherwise
341 return pixelcolor
== pencolor
;
344 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
346 wxCoord x1
= x
-VIEWPORT_EXTENT
;
347 wxCoord y1
= y
-VIEWPORT_EXTENT
;
348 wxCoord x2
= x
+VIEWPORT_EXTENT
;
349 wxCoord y2
= y
+VIEWPORT_EXTENT
;
351 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
352 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
354 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
355 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
357 CalcBoundingBox(x1
, y1
);
358 CalcBoundingBox(x2
, y2
);
361 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
363 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
364 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
366 /* MATTHEW: [6] New normalization */
367 #if WX_STANDARD_GRAPHICS
368 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
371 CalcBoundingBox(x1
, y1
);
372 CalcBoundingBox(x2
, y2
);
375 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
379 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
380 if (x1
==x2
&& x2
==y2
)
382 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
386 wxCoord xx1
= XLOG2DEV(x1
);
387 wxCoord yy1
= YLOG2DEV(y1
);
388 wxCoord xx2
= XLOG2DEV(x2
);
389 wxCoord yy2
= YLOG2DEV(y2
);
390 wxCoord xxc
= XLOG2DEV(xc
);
391 wxCoord yyc
= YLOG2DEV(yc
);
392 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
394 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
395 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
396 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
397 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
398 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
399 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
401 // Have to add 1 to bottom-right corner of rectangle
402 // to make semi-circles look right (crooked line otherwise).
403 // Unfortunately this is not a reliable method, depends
404 // on the size of shape.
405 // TODO: figure out why this happens!
406 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
410 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
413 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
414 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
417 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
419 COLORREF color
= 0x00ffffff;
422 color
= m_pen
.GetColour().GetPixel();
425 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
427 CalcBoundingBox(x
, y
);
430 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
432 COLORREF old_textground
= ::GetTextColor(GetHdc());
433 COLORREF old_background
= ::GetBkColor(GetHdc());
434 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
437 if (m_textForegroundColour
.Ok())
438 { //just the oposite from what is expected see help on pattern brush
439 // 1 in mask becomes bk color
440 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
442 if (m_textBackgroundColour
.Ok())
443 { //just the oposite from what is expected
444 // 0 in mask becomes text color
445 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
448 if (m_backgroundMode
== wxTRANSPARENT
)
449 SetBkMode(GetHdc(), TRANSPARENT
);
451 SetBkMode(GetHdc(), OPAQUE
);
454 // Do things less efficiently if we have offsets
455 if (xoffset
!= 0 || yoffset
!= 0)
457 POINT
*cpoints
= new POINT
[n
];
459 for (i
= 0; i
< n
; i
++)
461 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
462 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
464 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
466 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
467 (void)Polygon(GetHdc(), cpoints
, n
);
468 SetPolyFillMode(GetHdc(),prev
);
474 for (i
= 0; i
< n
; i
++)
475 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
477 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
478 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
479 SetPolyFillMode(GetHdc(),prev
);
482 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
484 ::SetBkMode(GetHdc(), TRANSPARENT
);
485 ::SetTextColor(GetHdc(), old_textground
);
486 ::SetBkColor(GetHdc(), old_background
);
490 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
492 // Do things less efficiently if we have offsets
493 if (xoffset
!= 0 || yoffset
!= 0)
495 POINT
*cpoints
= new POINT
[n
];
497 for (i
= 0; i
< n
; i
++)
499 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
500 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
502 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
504 (void)Polyline(GetHdc(), cpoints
, n
);
510 for (i
= 0; i
< n
; i
++)
511 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
513 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
517 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
519 COLORREF colFgOld
= 0,
522 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
524 colFgOld
= ::GetTextColor(GetHdc());
525 colBgOld
= ::GetBkColor(GetHdc());
527 if ( m_textForegroundColour
.Ok() )
529 // just the oposite from what is expected see help on pattern brush
530 // 1 in mask becomes bk color
531 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
534 if ( m_textBackgroundColour
.Ok() )
536 // 0 in mask becomes text color
537 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
540 // VZ: IMHO this does strictly nothing here
541 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
545 wxCoord x2
= x
+ width
;
546 wxCoord y2
= y
+ height
;
548 // Windows draws the filled rectangles without outline (i.e. drawn with a
549 // transparent pen) one pixel smaller in both directions and we want them
550 // to have the same size regardless of which pen is used - adjust
551 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
557 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
559 CalcBoundingBox(x
, y
);
560 CalcBoundingBox(x2
, y2
);
562 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
564 // restore the colours we changed
565 ::SetBkMode(GetHdc(), TRANSPARENT
);
566 ::SetTextColor(GetHdc(), colFgOld
);
567 ::SetBkColor(GetHdc(), colBgOld
);
571 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
573 // Now, a negative radius value is interpreted to mean
574 // 'the proportion of the smallest X or Y dimension'
578 double smallest
= 0.0;
583 radius
= (- radius
* smallest
);
586 wxCoord x2
= (x
+width
);
587 wxCoord y2
= (y
+height
);
589 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
590 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
592 CalcBoundingBox(x
, y
);
593 CalcBoundingBox(x2
, y2
);
596 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
598 wxCoord x2
= (x
+width
);
599 wxCoord y2
= (y
+height
);
601 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
603 CalcBoundingBox(x
, y
);
604 CalcBoundingBox(x2
, y2
);
607 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
608 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
613 int rx1
= XLOG2DEV(x
+w
/2);
614 int ry1
= YLOG2DEV(y
+h
/2);
621 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
622 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
623 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
624 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
626 // draw pie with NULL_PEN first and then outline otherwise a line is
627 // drawn from the start and end points to the centre
628 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
631 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
636 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
637 rx1
, ry1
-1, rx2
, ry2
-1);
639 ::SelectObject(GetHdc(), orig_pen
);
640 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
643 CalcBoundingBox(x
, y
);
644 CalcBoundingBox(x2
, y2
);
647 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
649 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
651 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
653 CalcBoundingBox(x
, y
);
654 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
657 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
659 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
661 int width
= bmp
.GetWidth(),
662 height
= bmp
.GetHeight();
664 HBITMAP hbmpMask
= 0;
668 wxMask
*mask
= bmp
.GetMask();
670 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
674 // don't give assert here because this would break existing
675 // programs - just silently ignore useMask parameter
683 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
684 ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
686 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
688 bool ok
= ::MaskBlt(GetHdc(), x
, y
, width
, height
,
691 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
697 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
700 memDC
.SelectObject(bmp
);
702 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
704 memDC
.SelectObject(wxNullBitmap
);
707 else // no mask, just use BitBlt()
710 HDC memdc
= ::CreateCompatibleDC( cdc
);
711 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
713 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
715 COLORREF old_textground
= ::GetTextColor(GetHdc());
716 COLORREF old_background
= ::GetBkColor(GetHdc());
717 if (m_textForegroundColour
.Ok())
719 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
721 if (m_textBackgroundColour
.Ok())
723 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
726 ::SelectObject( memdc
, hbitmap
);
727 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
730 ::SetTextColor(GetHdc(), old_textground
);
731 ::SetBkColor(GetHdc(), old_background
);
735 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
737 DrawAnyText(text
, x
, y
);
739 // update the bounding box
740 CalcBoundingBox(x
, y
);
743 GetTextExtent(text
, &w
, &h
);
744 CalcBoundingBox(x
+ w
, y
+ h
);
747 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
749 // prepare for drawing the text
750 if ( m_textForegroundColour
.Ok() )
751 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
753 DWORD old_background
= 0;
754 if ( m_textBackgroundColour
.Ok() )
756 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
759 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
762 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
763 text
.c_str(), text
.length()) == 0 )
765 wxLogLastError("TextOut");
768 // restore the old parameters (text foreground colour may be left because
769 // it never is set to anything else, but background should remain
770 // transparent even if we just drew an opaque string)
771 if ( m_textBackgroundColour
.Ok() )
772 (void)SetBkColor(GetHdc(), old_background
);
774 SetBkMode(GetHdc(), TRANSPARENT
);
777 void wxDC::DoDrawRotatedText(const wxString
& text
,
778 wxCoord x
, wxCoord y
,
781 // we test that we have some font because otherwise we should still use the
782 // "else" part below to avoid that DrawRotatedText(angle = 180) and
783 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
784 // font for drawing rotated fonts unfortunately)
785 if ( (angle
== 0.0) && m_font
.Ok() )
787 DoDrawText(text
, x
, y
);
791 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
792 // can't have non zero orientation/escapement
793 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
794 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
796 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
798 wxLogLastError("GetObject(hfont)");
801 // GDI wants the angle in tenth of degree
802 long angle10
= (long)(angle
* 10);
803 lf
.lfEscapement
= angle10
;
804 lf
. lfOrientation
= angle10
;
806 hfont
= ::CreateFontIndirect(&lf
);
809 wxLogLastError("CreateFont");
813 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
815 DrawAnyText(text
, x
, y
);
817 (void)::SelectObject(GetHdc(), hfontOld
);
818 (void)::DeleteObject(hfont
);
821 // call the bounding box by adding all four vertices of the rectangle
822 // containing the text to it (simpler and probably not slower than
823 // determining which of them is really topmost/leftmost/...)
825 GetTextExtent(text
, &w
, &h
);
827 double rad
= DegToRad(angle
);
829 // "upper left" and "upper right"
830 CalcBoundingBox(x
, y
);
831 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
833 // "bottom left" and "bottom right"
834 x
+= (wxCoord
)(h
*sin(rad
));
835 y
+= (wxCoord
)(h
*cos(rad
));
836 CalcBoundingBox(x
, y
);
837 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
841 // ---------------------------------------------------------------------------
843 // ---------------------------------------------------------------------------
845 void wxDC::SetPalette(const wxPalette
& palette
)
847 // Set the old object temporarily, in case the assignment deletes an object
848 // that's not yet selected out.
851 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
859 // Setting a NULL colourmap is a way of restoring
860 // the original colourmap
863 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
870 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
872 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
874 m_oldPalette
= (WXHPALETTE
) oldPal
;
876 ::RealizePalette(GetHdc());
880 void wxDC::SetFont(const wxFont
& the_font
)
882 // Set the old object temporarily, in case the assignment deletes an object
883 // that's not yet selected out.
886 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
895 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
899 if (m_font
.Ok() && m_font
.GetResourceHandle())
901 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
902 if (f
== (HFONT
) NULL
)
904 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
907 m_oldFont
= (WXHFONT
) f
;
911 void wxDC::SetPen(const wxPen
& pen
)
913 // Set the old object temporarily, in case the assignment deletes an object
914 // that's not yet selected out.
917 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
926 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
932 if (m_pen
.GetResourceHandle())
934 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
936 m_oldPen
= (WXHPEN
) p
;
941 void wxDC::SetBrush(const wxBrush
& brush
)
943 // Set the old object temporarily, in case the assignment deletes an object
944 // that's not yet selected out.
947 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
956 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
962 if (m_brush
.GetResourceHandle())
965 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
967 m_oldBrush
= (WXHBRUSH
) b
;
972 void wxDC::SetBackground(const wxBrush
& brush
)
974 m_backgroundBrush
= brush
;
976 if (!m_backgroundBrush
.Ok())
981 bool customColours
= TRUE
;
982 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
983 // change background colours from the control-panel specified colours.
984 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
985 customColours
= FALSE
;
989 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
991 m_canvas
->SetTransparent(TRUE
);
995 // New behaviour, 10/2/99: setting the background brush of a DC
996 // doesn't affect the window background colour. However,
997 // I'm leaving in the transparency setting because it's needed by
998 // various controls (e.g. wxStaticText) to determine whether to draw
999 // transparently or not. TODO: maybe this should be a new function
1000 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1002 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1003 m_canvas
->SetTransparent(FALSE
);
1007 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1009 (void)SetBkColor(GetHdc(), new_color
);
1013 void wxDC::SetBackgroundMode(int mode
)
1015 m_backgroundMode
= mode
;
1017 // SetBackgroundColour now only refers to text background
1018 // and m_backgroundMode is used there
1021 if (m_backgroundMode == wxTRANSPARENT)
1022 ::SetBkMode(GetHdc(), TRANSPARENT);
1024 ::SetBkMode(GetHdc(), OPAQUE);
1028 void wxDC::SetLogicalFunction(int function
)
1030 m_logicalFunction
= function
;
1035 void wxDC::SetRop(WXHDC dc
)
1037 if ( !dc
|| m_logicalFunction
< 0 )
1042 switch (m_logicalFunction
)
1044 case wxCLEAR
: rop
= R2_BLACK
; break;
1045 case wxXOR
: rop
= R2_XORPEN
; break;
1046 case wxINVERT
: rop
= R2_NOT
; break;
1047 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1048 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1049 case wxCOPY
: rop
= R2_COPYPEN
; break;
1050 case wxAND
: rop
= R2_MASKPEN
; break;
1051 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1052 case wxNO_OP
: rop
= R2_NOP
; break;
1053 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1054 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1055 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1056 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1057 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1058 case wxOR
: rop
= R2_MERGEPEN
; break;
1059 case wxSET
: rop
= R2_WHITE
; break;
1062 wxFAIL_MSG( wxT("unsupported logical function") );
1066 SetROP2(GetHdc(), rop
);
1069 bool wxDC::StartDoc(const wxString
& message
)
1071 // We might be previewing, so return TRUE to let it continue.
1079 void wxDC::StartPage()
1083 void wxDC::EndPage()
1087 // ---------------------------------------------------------------------------
1089 // ---------------------------------------------------------------------------
1091 wxCoord
wxDC::GetCharHeight() const
1093 TEXTMETRIC lpTextMetric
;
1095 GetTextMetrics(GetHdc(), &lpTextMetric
);
1097 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1100 wxCoord
wxDC::GetCharWidth() const
1102 TEXTMETRIC lpTextMetric
;
1104 GetTextMetrics(GetHdc(), &lpTextMetric
);
1106 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1109 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1110 wxCoord
*descent
, wxCoord
*externalLeading
,
1111 wxFont
*theFont
) const
1113 wxFont
*fontToUse
= (wxFont
*) theFont
;
1115 fontToUse
= (wxFont
*) &m_font
;
1120 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1121 GetTextMetrics(GetHdc(), &tm
);
1123 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1124 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1125 if (descent
) *descent
= tm
.tmDescent
;
1126 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1129 void wxDC::SetMapMode(int mode
)
1131 m_mappingMode
= mode
;
1133 int pixel_width
= 0;
1134 int pixel_height
= 0;
1138 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1139 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1140 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1141 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1143 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1148 double mm2pixelsX
= pixel_width
/mm_width
;
1149 double mm2pixelsY
= pixel_height
/mm_height
;
1155 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1156 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1161 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1162 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1167 m_logicalScaleX
= mm2pixelsX
;
1168 m_logicalScaleY
= mm2pixelsY
;
1173 m_logicalScaleX
= (mm2pixelsX
/10.0);
1174 m_logicalScaleY
= (mm2pixelsY
/10.0);
1180 m_logicalScaleX
= 1.0;
1181 m_logicalScaleY
= 1.0;
1186 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1187 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1189 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1190 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1191 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1192 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1193 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1194 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1197 void wxDC::SetUserScale(double x
, double y
)
1202 SetMapMode(m_mappingMode
);
1205 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1207 m_signX
= xLeftRight
? 1 : -1;
1208 m_signY
= yBottomUp
? -1 : 1;
1210 SetMapMode(m_mappingMode
);
1213 void wxDC::SetSystemScale(double x
, double y
)
1218 SetMapMode(m_mappingMode
);
1221 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1223 m_logicalOriginX
= x
;
1224 m_logicalOriginY
= y
;
1226 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1229 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1231 m_deviceOriginX
= x
;
1232 m_deviceOriginY
= y
;
1234 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1237 // ---------------------------------------------------------------------------
1238 // coordinates transformations
1239 // ---------------------------------------------------------------------------
1241 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1243 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1246 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1248 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1251 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1253 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1256 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1258 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1261 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1263 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1266 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1268 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1271 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1273 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1276 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1278 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1281 // ---------------------------------------------------------------------------
1283 // ---------------------------------------------------------------------------
1285 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1286 wxCoord width
, wxCoord height
,
1287 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1288 int rop
, bool useMask
)
1290 wxMask
*mask
= NULL
;
1293 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1294 mask
= bmp
.GetMask();
1296 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1298 // don't give assert here because this would break existing
1299 // programs - just silently ignore useMask parameter
1304 COLORREF old_textground
= ::GetTextColor(GetHdc());
1305 COLORREF old_background
= ::GetBkColor(GetHdc());
1306 if (m_textForegroundColour
.Ok())
1308 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1310 if (m_textBackgroundColour
.Ok())
1312 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1315 DWORD dwRop
= SRCCOPY
;
1318 case wxXOR
: dwRop
= SRCINVERT
; break;
1319 case wxINVERT
: dwRop
= DSTINVERT
; break;
1320 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1321 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1322 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1323 case wxSET
: dwRop
= WHITENESS
; break;
1324 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1325 case wxAND
: dwRop
= SRCAND
; break;
1326 case wxOR
: dwRop
= SRCPAINT
; break;
1327 case wxEQUIV
: dwRop
= 0x00990066; break;
1328 case wxNAND
: dwRop
= 0x007700E6; break;
1329 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1330 case wxCOPY
: dwRop
= SRCCOPY
; break;
1331 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1332 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1333 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1335 wxFAIL_MSG( wxT("unsupported logical function") );
1344 // we want the part of the image corresponding to the mask to be
1345 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1346 // meaning of fg and bg is inverted which corresponds to wxWin notion
1347 // of the mask which is also contrary to the Windows one)
1348 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1349 GetHdcOf(*source
), xsrc
, ysrc
,
1350 (HBITMAP
)mask
->GetMaskBitmap(), 0, 0,
1351 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1356 // Blit bitmap with mask
1358 // create a temp buffer bitmap and DCs to access it and the mask
1359 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1360 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1361 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1362 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1363 ::SelectObject(dc_buffer
, buffer_bmap
);
1365 // copy dest to buffer
1366 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1367 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1369 wxLogLastError("BitBlt");
1372 // copy src to buffer using selected raster op
1373 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1374 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1376 wxLogLastError("BitBlt");
1379 // set masked area in buffer to BLACK (pixel value 0)
1380 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1381 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1382 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1383 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1385 wxLogLastError("BitBlt");
1388 // set unmasked area in dest to BLACK
1389 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1390 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1391 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1392 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1394 wxLogLastError("BitBlt");
1396 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1397 ::SetTextColor(GetHdc(), prevCol
);
1399 // OR buffer to dest
1400 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1401 (int)width
, (int)height
,
1402 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1405 wxLogLastError("BitBlt");
1408 // tidy up temporary DCs and bitmap
1409 ::SelectObject(dc_mask
, 0);
1410 ::DeleteDC(dc_mask
);
1411 ::SelectObject(dc_buffer
, 0);
1412 ::DeleteDC(dc_buffer
);
1413 ::DeleteObject(buffer_bmap
);
1416 else // no mask, just BitBlt() it
1418 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1419 (int)width
, (int)height
,
1420 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1423 wxLogLastError("BitBlt");
1426 ::SetTextColor(GetHdc(), old_textground
);
1427 ::SetBkColor(GetHdc(), old_background
);
1432 void wxDC::DoGetSize(int *w
, int *h
) const
1434 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1435 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1438 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1440 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1441 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1444 wxSize
wxDC::GetPPI() const
1446 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1447 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1449 return wxSize(x
, y
);
1452 // For use by wxWindows only, unless custom units are required.
1453 void wxDC::SetLogicalScale(double x
, double y
)
1455 m_logicalScaleX
= x
;
1456 m_logicalScaleY
= y
;
1459 #if WXWIN_COMPATIBILITY
1460 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1461 float *descent
, float *externalLeading
,
1462 wxFont
*theFont
, bool use16bit
) const
1464 wxCoord x1
, y1
, descent1
, externalLeading1
;
1465 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1468 *descent
= descent1
;
1469 if (externalLeading
)
1470 *externalLeading
= externalLeading1
;
1474 // ---------------------------------------------------------------------------
1475 // spline drawing code
1476 // ---------------------------------------------------------------------------
1480 class wxSpline
: public wxObject
1486 wxSpline(wxList
*list
);
1487 void DeletePoints();
1489 // Doesn't delete points
1493 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1495 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1496 double a3
, double b3
, double a4
, double b4
);
1497 void wx_clear_stack();
1498 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1499 double *y3
, double *x4
, double *y4
);
1500 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1501 double x4
, double y4
);
1502 static bool wx_spline_add_point(double x
, double y
);
1503 static void wx_spline_draw_point_array(wxDC
*dc
);
1504 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1506 void wxDC::DoDrawSpline(wxList
*list
)
1508 wxSpline
spline(list
);
1510 wx_draw_open_spline(this, &spline
);
1513 wxList wx_spline_point_list
;
1515 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1518 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1519 double x1
, y1
, x2
, y2
;
1521 wxNode
*node
= spline
->points
->First();
1522 p
= (wxPoint
*)node
->Data();
1527 node
= node
->Next();
1528 p
= (wxPoint
*)node
->Data();
1532 cx1
= (double)((x1
+ x2
) / 2);
1533 cy1
= (double)((y1
+ y2
) / 2);
1534 cx2
= (double)((cx1
+ x2
) / 2);
1535 cy2
= (double)((cy1
+ y2
) / 2);
1537 wx_spline_add_point(x1
, y1
);
1539 while ((node
= node
->Next()) != NULL
)
1541 p
= (wxPoint
*)node
->Data();
1546 cx4
= (double)(x1
+ x2
) / 2;
1547 cy4
= (double)(y1
+ y2
) / 2;
1548 cx3
= (double)(x1
+ cx4
) / 2;
1549 cy3
= (double)(y1
+ cy4
) / 2;
1551 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1555 cx2
= (double)(cx1
+ x2
) / 2;
1556 cy2
= (double)(cy1
+ y2
) / 2;
1559 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1560 wx_spline_add_point(x2
, y2
);
1562 wx_spline_draw_point_array(dc
);
1566 /********************* CURVES FOR SPLINES *****************************
1568 The following spline drawing routine is from
1570 "An Algorithm for High-Speed Curve Generation"
1571 by George Merrill Chaikin,
1572 Computer Graphics and Image Processing, 3, Academic Press,
1577 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1578 Computer Graphics and Image Processing, 4, Academic Press,
1581 ***********************************************************************/
1583 #define half(z1, z2) ((z1+z2)/2.0)
1586 /* iterative version */
1588 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1591 register double xmid
, ymid
;
1592 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1595 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1597 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1598 xmid
= (double)half(x2
, x3
);
1599 ymid
= (double)half(y2
, y3
);
1600 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1601 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1602 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1603 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1605 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1606 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1607 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1608 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1614 /* utilities used by spline drawing routines */
1617 typedef struct wx_spline_stack_struct
{
1618 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1622 #define SPLINE_STACK_DEPTH 20
1623 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1624 static Stack
*wx_stack_top
;
1625 static int wx_stack_count
;
1627 void wx_clear_stack()
1629 wx_stack_top
= wx_spline_stack
;
1633 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1635 wx_stack_top
->x1
= x1
;
1636 wx_stack_top
->y1
= y1
;
1637 wx_stack_top
->x2
= x2
;
1638 wx_stack_top
->y2
= y2
;
1639 wx_stack_top
->x3
= x3
;
1640 wx_stack_top
->y3
= y3
;
1641 wx_stack_top
->x4
= x4
;
1642 wx_stack_top
->y4
= y4
;
1647 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1648 double *x3
, double *y3
, double *x4
, double *y4
)
1650 if (wx_stack_count
== 0)
1654 *x1
= wx_stack_top
->x1
;
1655 *y1
= wx_stack_top
->y1
;
1656 *x2
= wx_stack_top
->x2
;
1657 *y2
= wx_stack_top
->y2
;
1658 *x3
= wx_stack_top
->x3
;
1659 *y3
= wx_stack_top
->y3
;
1660 *x4
= wx_stack_top
->x4
;
1661 *y4
= wx_stack_top
->y4
;
1665 static bool wx_spline_add_point(double x
, double y
)
1667 wxPoint
*point
= new wxPoint
;
1670 wx_spline_point_list
.Append((wxObject
*)point
);
1674 static void wx_spline_draw_point_array(wxDC
*dc
)
1676 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1677 wxNode
*node
= wx_spline_point_list
.First();
1680 wxPoint
*point
= (wxPoint
*)node
->Data();
1683 node
= wx_spline_point_list
.First();
1687 wxSpline::wxSpline(wxList
*list
)
1692 wxSpline::~wxSpline()
1696 void wxSpline::DeletePoints()
1698 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1700 wxPoint
*point
= (wxPoint
*)node
->Data();
1708 #endif // wxUSE_SPLINES