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"
26 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/dcprint.h"
49 #if wxUSE_COMMON_DIALOGS
50 #if wxUSE_NORLANDER_HEADERS
60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
62 // ---------------------------------------------------------------------------
64 // ---------------------------------------------------------------------------
66 static const int VIEWPORT_EXTENT
= 1000;
68 static const int MM_POINTS
= 9;
69 static const int MM_METRIC
= 10;
71 // usually this is defined in math.h
73 static const double M_PI
= 3.14159265358979323846;
76 // ---------------------------------------------------------------------------
78 // ---------------------------------------------------------------------------
80 // convert degrees to radians
81 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
83 // ===========================================================================
85 // ===========================================================================
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 // Default constructor
105 m_windowExtX
= VIEWPORT_EXTENT
;
106 m_windowExtY
= VIEWPORT_EXTENT
;
115 SelectOldObjects(m_hDC
);
117 if ( m_canvas
== NULL
)
118 ::DeleteDC(GetHdc());
120 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
126 // This will select current objects out of the DC,
127 // which is what you have to do before deleting the
129 void wxDC::SelectOldObjects(WXHDC dc
)
135 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
136 if (m_selectedBitmap
.Ok())
138 m_selectedBitmap
.SetSelectedInto(NULL
);
144 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
149 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
154 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
159 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
164 m_brush
= wxNullBrush
;
166 m_palette
= wxNullPalette
;
168 m_backgroundBrush
= wxNullBrush
;
169 m_selectedBitmap
= wxNullBitmap
;
172 // ---------------------------------------------------------------------------
174 // ---------------------------------------------------------------------------
176 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
181 m_clipX2
= (int)(cx
+ cw
);
182 m_clipY2
= (int)(cy
+ ch
);
184 DoClipping((WXHDC
) m_hDC
);
187 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
189 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
191 wxRect box
= region
.GetBox();
196 m_clipX2
= box
.x
+ box
.width
;
197 m_clipY2
= box
.y
+ box
.height
;
200 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
202 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
206 void wxDC::DoClipping(WXHDC dc
)
208 if (m_clipping
&& dc
)
210 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
211 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
215 void wxDC::DestroyClippingRegion()
217 if (m_clipping
&& m_hDC
)
219 // TODO: this should restore the previous clipping region,
220 // so that OnPaint processing works correctly, and the update clipping region
221 // doesn't get destroyed after the first DestroyClippingRegion.
222 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
223 SelectClipRgn(GetHdc(), rgn
);
229 // ---------------------------------------------------------------------------
230 // query capabilities
231 // ---------------------------------------------------------------------------
233 bool wxDC::CanDrawBitmap() const
238 bool wxDC::CanGetTextExtent() const
240 // What sort of display is it?
241 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
243 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
246 int wxDC::GetDepth() const
248 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
251 // ---------------------------------------------------------------------------
253 // ---------------------------------------------------------------------------
260 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
264 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
266 rect
.left
= 0; rect
.top
= 0;
267 rect
.right
= m_selectedBitmap
.GetWidth();
268 rect
.bottom
= m_selectedBitmap
.GetHeight();
271 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
273 DWORD colour
= GetBkColor(GetHdc());
274 HBRUSH brush
= CreateSolidBrush(colour
);
275 FillRect(GetHdc(), &rect
, brush
);
278 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
279 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
280 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
281 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
282 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
285 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
287 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
289 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
292 CalcBoundingBox(x
, y
);
295 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
297 // added by steve 29.12.94 (copied from DrawPoint)
298 // returns TRUE for pixels in the color of the current pen
299 // and FALSE for all other pixels colors
300 // if col is non-NULL return the color of the pixel
302 // get the color of the pixel
303 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
304 // get the color of the pen
305 COLORREF pencolor
= 0x00ffffff;
308 pencolor
= m_pen
.GetColour().GetPixel();
311 // return the color of the pixel
313 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
315 // check, if color of the pixels is the same as the color
316 // of the current pen
317 return(pixelcolor
==pencolor
);
320 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
322 wxCoord x1
= x
-VIEWPORT_EXTENT
;
323 wxCoord y1
= y
-VIEWPORT_EXTENT
;
324 wxCoord x2
= x
+VIEWPORT_EXTENT
;
325 wxCoord y2
= y
+VIEWPORT_EXTENT
;
327 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
328 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
330 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
331 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
333 CalcBoundingBox(x1
, y1
);
334 CalcBoundingBox(x2
, y2
);
337 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
339 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
340 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
342 /* MATTHEW: [6] New normalization */
343 #if WX_STANDARD_GRAPHICS
344 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
347 CalcBoundingBox(x1
, y1
);
348 CalcBoundingBox(x2
, y2
);
351 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
355 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
356 if (x1
==x2
&& x2
==y2
)
358 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
362 wxCoord xx1
= XLOG2DEV(x1
);
363 wxCoord yy1
= YLOG2DEV(y1
);
364 wxCoord xx2
= XLOG2DEV(x2
);
365 wxCoord yy2
= YLOG2DEV(y2
);
366 wxCoord xxc
= XLOG2DEV(xc
);
367 wxCoord yyc
= YLOG2DEV(yc
);
368 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
370 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
371 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
372 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
373 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
374 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
375 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
377 // Have to add 1 to bottom-right corner of rectangle
378 // to make semi-circles look right (crooked line otherwise).
379 // Unfortunately this is not a reliable method, depends
380 // on the size of shape.
381 // TODO: figure out why this happens!
382 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
386 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
389 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
390 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
393 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
395 COLORREF color
= 0x00ffffff;
398 color
= m_pen
.GetColour().GetPixel();
401 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
403 CalcBoundingBox(x
, y
);
406 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
408 COLORREF old_textground
= ::GetTextColor(GetHdc());
409 COLORREF old_background
= ::GetBkColor(GetHdc());
410 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
413 if (m_textForegroundColour
.Ok())
414 { //just the oposite from what is expected see help on pattern brush
415 // 1 in mask becomes bk color
416 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
418 if (m_textBackgroundColour
.Ok())
419 { //just the oposite from what is expected
420 // 0 in mask becomes text color
421 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
424 if (m_backgroundMode
== wxTRANSPARENT
)
425 SetBkMode(GetHdc(), TRANSPARENT
);
427 SetBkMode(GetHdc(), OPAQUE
);
430 // Do things less efficiently if we have offsets
431 if (xoffset
!= 0 || yoffset
!= 0)
433 POINT
*cpoints
= new POINT
[n
];
435 for (i
= 0; i
< n
; i
++)
437 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
438 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
440 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
442 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
443 (void)Polygon(GetHdc(), cpoints
, n
);
444 SetPolyFillMode(GetHdc(),prev
);
450 for (i
= 0; i
< n
; i
++)
451 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
453 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
454 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
455 SetPolyFillMode(GetHdc(),prev
);
458 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
460 ::SetBkMode(GetHdc(), TRANSPARENT
);
461 ::SetTextColor(GetHdc(), old_textground
);
462 ::SetBkColor(GetHdc(), old_background
);
466 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
468 // Do things less efficiently if we have offsets
469 if (xoffset
!= 0 || yoffset
!= 0)
471 POINT
*cpoints
= new POINT
[n
];
473 for (i
= 0; i
< n
; i
++)
475 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
476 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
478 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
480 (void)Polyline(GetHdc(), cpoints
, n
);
486 for (i
= 0; i
< n
; i
++)
487 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
489 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
493 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
495 COLORREF old_textground
= ::GetTextColor(GetHdc());
496 COLORREF old_background
= ::GetBkColor(GetHdc());
497 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
500 if (m_textForegroundColour
.Ok())
501 { //just the oposite from what is expected see help on pattern brush
502 // 1 in mask becomes bk color
503 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
505 if (m_textBackgroundColour
.Ok())
506 { //just the oposite from what is expected
507 // 0 in mask becomes text color
508 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
511 if (m_backgroundMode
== wxTRANSPARENT
)
512 SetBkMode(GetHdc(), TRANSPARENT
);
514 SetBkMode(GetHdc(), OPAQUE
);
517 wxCoord x2
= x
+ width
;
518 wxCoord y2
= y
+ height
;
520 /* MATTHEW: [6] new normalization */
521 #if WX_STANDARD_GRAPHICS
522 bool do_brush
, do_pen
;
524 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
525 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
528 HPEN orig_pen
= NULL
;
530 if (do_pen
|| !m_pen
.Ok())
531 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
533 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
534 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
536 if (do_pen
|| !m_pen
.Ok())
537 ::SelectObject(GetHdc() , orig_pen
);
540 HBRUSH orig_brush
= NULL
;
542 if (do_brush
|| !m_brush
.Ok())
543 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
545 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
546 XLOG2DEV(x2
), YLOG2DEV(y2
));
548 if (do_brush
|| !m_brush
.Ok())
549 ::SelectObject(GetHdc(), orig_brush
);
552 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
555 CalcBoundingBox(x
, y
);
556 CalcBoundingBox(x2
, y2
);
558 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
560 ::SetBkMode(GetHdc(), TRANSPARENT
);
561 ::SetTextColor(GetHdc(), old_textground
);
562 ::SetBkColor(GetHdc(), old_background
);
566 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
568 // Now, a negative radius value is interpreted to mean
569 // 'the proportion of the smallest X or Y dimension'
573 double smallest
= 0.0;
578 radius
= (- radius
* smallest
);
581 wxCoord x2
= (x
+width
);
582 wxCoord y2
= (y
+height
);
584 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
585 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
587 CalcBoundingBox(x
, y
);
588 CalcBoundingBox(x2
, y2
);
591 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
593 wxCoord x2
= (x
+width
);
594 wxCoord y2
= (y
+height
);
596 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
598 CalcBoundingBox(x
, y
);
599 CalcBoundingBox(x2
, y2
);
602 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
603 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
608 int rx1
= XLOG2DEV(x
+w
/2);
609 int ry1
= YLOG2DEV(y
+h
/2);
616 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
617 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
618 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
619 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
621 // draw pie with NULL_PEN first and then outline otherwise a line is
622 // drawn from the start and end points to the centre
623 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
626 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
631 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
632 rx1
, ry1
-1, rx2
, ry2
-1);
634 ::SelectObject(GetHdc(), orig_pen
);
635 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
638 CalcBoundingBox(x
, y
);
639 CalcBoundingBox(x2
, y2
);
642 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
644 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
646 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
648 CalcBoundingBox(x
, y
);
649 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
652 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
654 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
656 int width
= bmp
.GetWidth(),
657 height
= bmp
.GetHeight();
662 HDC memdc
= ::CreateCompatibleDC( cdc
);
663 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
665 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
667 COLORREF old_textground
= ::GetTextColor(GetHdc());
668 COLORREF old_background
= ::GetBkColor(GetHdc());
669 if (m_textForegroundColour
.Ok())
671 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
673 if (m_textBackgroundColour
.Ok())
675 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
678 ::SelectObject( memdc
, hbitmap
);
679 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
682 ::SetTextColor(GetHdc(), old_textground
);
683 ::SetBkColor(GetHdc(), old_background
);
687 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
689 memDC
.SelectObject(bmp
);
691 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
693 memDC
.SelectObject(wxNullBitmap
);
697 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
699 DrawAnyText(text
, x
, y
);
701 // update the bounding box
702 CalcBoundingBox(x
, y
);
705 GetTextExtent(text
, &w
, &h
);
706 CalcBoundingBox(x
+ w
, y
+ h
);
709 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
711 // prepare for drawing the text
712 if ( m_textForegroundColour
.Ok() )
713 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
715 DWORD old_background
= 0;
716 if ( m_textBackgroundColour
.Ok() )
718 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
721 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
724 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
725 text
.c_str(), text
.length()) == 0 )
727 wxLogLastError("TextOut");
730 // restore the old parameters (text foreground colour may be left because
731 // it never is set to anything else, but background should remain
732 // transparent even if we just drew an opaque string)
733 if ( m_textBackgroundColour
.Ok() )
734 (void)SetBkColor(GetHdc(), old_background
);
736 SetBkMode(GetHdc(), TRANSPARENT
);
739 void wxDC::DoDrawRotatedText(const wxString
& text
,
740 wxCoord x
, wxCoord y
,
743 // we test that we have some font because otherwise we should still use the
744 // "else" part below to avoid that DrawRotatedText(angle = 180) and
745 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
746 // font for drawing rotated fonts unfortunately)
747 if ( (angle
== 0.0) && m_font
.Ok() )
749 DoDrawText(text
, x
, y
);
753 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
754 // can't have non zero orientation/escapement
755 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
756 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
758 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
760 wxLogLastError("GetObject(hfont)");
763 // GDI wants the angle in tenth of degree
764 long angle10
= (long)(angle
* 10);
765 lf
.lfEscapement
= angle10
;
766 lf
. lfOrientation
= angle10
;
768 hfont
= ::CreateFontIndirect(&lf
);
771 wxLogLastError("CreateFont");
775 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
777 DrawAnyText(text
, x
, y
);
779 (void)::SelectObject(GetHdc(), hfontOld
);
782 // call the bounding box by adding all four vertices of the rectangle
783 // containing the text to it (simpler and probably not slower than
784 // determining which of them is really topmost/leftmost/...)
786 GetTextExtent(text
, &w
, &h
);
788 double rad
= DegToRad(angle
);
790 // "upper left" and "upper right"
791 CalcBoundingBox(x
, y
);
792 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
794 // "bottom left" and "bottom right"
795 x
+= (wxCoord
)(h
*sin(rad
));
796 y
+= (wxCoord
)(h
*cos(rad
));
797 CalcBoundingBox(x
, y
);
798 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
802 // ---------------------------------------------------------------------------
804 // ---------------------------------------------------------------------------
806 void wxDC::SetPalette(const wxPalette
& palette
)
808 // Set the old object temporarily, in case the assignment deletes an object
809 // that's not yet selected out.
812 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
820 // Setting a NULL colourmap is a way of restoring
821 // the original colourmap
824 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
831 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
833 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
835 m_oldPalette
= (WXHPALETTE
) oldPal
;
837 ::RealizePalette(GetHdc());
841 void wxDC::SetFont(const wxFont
& the_font
)
843 // Set the old object temporarily, in case the assignment deletes an object
844 // that's not yet selected out.
847 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
856 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
860 if (m_font
.Ok() && m_font
.GetResourceHandle())
862 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
863 if (f
== (HFONT
) NULL
)
865 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
868 m_oldFont
= (WXHFONT
) f
;
872 void wxDC::SetPen(const wxPen
& pen
)
874 // Set the old object temporarily, in case the assignment deletes an object
875 // that's not yet selected out.
878 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
887 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
893 if (m_pen
.GetResourceHandle())
895 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
897 m_oldPen
= (WXHPEN
) p
;
902 void wxDC::SetBrush(const wxBrush
& brush
)
904 // Set the old object temporarily, in case the assignment deletes an object
905 // that's not yet selected out.
908 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
917 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
923 if (m_brush
.GetResourceHandle())
926 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
928 m_oldBrush
= (WXHBRUSH
) b
;
933 void wxDC::SetBackground(const wxBrush
& brush
)
935 m_backgroundBrush
= brush
;
937 if (!m_backgroundBrush
.Ok())
942 bool customColours
= TRUE
;
943 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
944 // change background colours from the control-panel specified colours.
945 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
946 customColours
= FALSE
;
950 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
952 m_canvas
->SetTransparent(TRUE
);
956 // New behaviour, 10/2/99: setting the background brush of a DC
957 // doesn't affect the window background colour. However,
958 // I'm leaving in the transparency setting because it's needed by
959 // various controls (e.g. wxStaticText) to determine whether to draw
960 // transparently or not. TODO: maybe this should be a new function
961 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
963 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
964 m_canvas
->SetTransparent(FALSE
);
968 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
970 (void)SetBkColor(GetHdc(), new_color
);
974 void wxDC::SetBackgroundMode(int mode
)
976 m_backgroundMode
= mode
;
978 // SetBackgroundColour now only refers to text background
979 // and m_backgroundMode is used there
982 if (m_backgroundMode == wxTRANSPARENT)
983 ::SetBkMode(GetHdc(), TRANSPARENT);
985 ::SetBkMode(GetHdc(), OPAQUE);
989 void wxDC::SetLogicalFunction(int function
)
991 m_logicalFunction
= function
;
993 SetRop((WXHDC
) m_hDC
);
996 void wxDC::SetRop(WXHDC dc
)
998 if (!dc
|| m_logicalFunction
< 0)
1002 // These may be wrong
1003 switch (m_logicalFunction
)
1005 // case wxXOR: c_rop = R2_XORPEN; break;
1006 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
1007 case wxINVERT
: c_rop
= R2_NOT
; break;
1008 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
1009 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
1010 case wxCLEAR
: c_rop
= R2_WHITE
; break;
1011 case wxSET
: c_rop
= R2_BLACK
; break;
1012 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
1013 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
1014 case wxAND
: c_rop
= R2_MASKPEN
; break;
1015 case wxOR
: c_rop
= R2_MERGEPEN
; break;
1016 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
1021 c_rop
= R2_COPYPEN
; break;
1023 SetROP2((HDC
) dc
, c_rop
);
1026 bool wxDC::StartDoc(const wxString
& message
)
1028 // We might be previewing, so return TRUE to let it continue.
1036 void wxDC::StartPage()
1040 void wxDC::EndPage()
1044 // ---------------------------------------------------------------------------
1046 // ---------------------------------------------------------------------------
1048 wxCoord
wxDC::GetCharHeight() const
1050 TEXTMETRIC lpTextMetric
;
1052 GetTextMetrics(GetHdc(), &lpTextMetric
);
1054 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1057 wxCoord
wxDC::GetCharWidth() const
1059 TEXTMETRIC lpTextMetric
;
1061 GetTextMetrics(GetHdc(), &lpTextMetric
);
1063 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1066 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1067 wxCoord
*descent
, wxCoord
*externalLeading
,
1068 wxFont
*theFont
) const
1070 wxFont
*fontToUse
= (wxFont
*) theFont
;
1072 fontToUse
= (wxFont
*) &m_font
;
1077 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1078 GetTextMetrics(GetHdc(), &tm
);
1080 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1081 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1082 if (descent
) *descent
= tm
.tmDescent
;
1083 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1086 void wxDC::SetMapMode(int mode
)
1088 m_mappingMode
= mode
;
1090 int pixel_width
= 0;
1091 int pixel_height
= 0;
1095 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1096 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1097 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1098 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1100 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1105 double mm2pixelsX
= pixel_width
/mm_width
;
1106 double mm2pixelsY
= pixel_height
/mm_height
;
1112 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1113 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1118 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1119 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1124 m_logicalScaleX
= mm2pixelsX
;
1125 m_logicalScaleY
= mm2pixelsY
;
1130 m_logicalScaleX
= (mm2pixelsX
/10.0);
1131 m_logicalScaleY
= (mm2pixelsY
/10.0);
1137 m_logicalScaleX
= 1.0;
1138 m_logicalScaleY
= 1.0;
1143 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1144 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1146 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1147 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1148 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1149 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1150 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1151 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1154 void wxDC::SetUserScale(double x
, double y
)
1159 SetMapMode(m_mappingMode
);
1162 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1164 m_signX
= xLeftRight
? 1 : -1;
1165 m_signY
= yBottomUp
? -1 : 1;
1167 SetMapMode(m_mappingMode
);
1170 void wxDC::SetSystemScale(double x
, double y
)
1175 SetMapMode(m_mappingMode
);
1178 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1180 m_logicalOriginX
= x
;
1181 m_logicalOriginY
= y
;
1183 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1186 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1188 m_deviceOriginX
= x
;
1189 m_deviceOriginY
= y
;
1191 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1194 // ---------------------------------------------------------------------------
1195 // coordinates transformations
1196 // ---------------------------------------------------------------------------
1198 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1200 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1203 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1205 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1208 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1210 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1213 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1215 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1218 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1220 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1223 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1225 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1228 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1230 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1233 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1235 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1238 // ---------------------------------------------------------------------------
1240 // ---------------------------------------------------------------------------
1242 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1243 wxCoord width
, wxCoord height
,
1244 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1245 int rop
, bool useMask
)
1247 wxMask
*mask
= NULL
;
1250 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1251 mask
= bmp
.GetMask();
1253 wxCHECK_MSG( bmp
.Ok() && mask
, FALSE
,
1254 _T("can't blit with mask without mask") );
1257 COLORREF old_textground
= ::GetTextColor(GetHdc());
1258 COLORREF old_background
= ::GetBkColor(GetHdc());
1259 if (m_textForegroundColour
.Ok())
1261 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1263 if (m_textBackgroundColour
.Ok())
1265 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1268 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1269 rop
== wxCLEAR
? WHITENESS
:
1270 rop
== wxSET
? BLACKNESS
:
1271 rop
== wxINVERT
? DSTINVERT
:
1272 rop
== wxAND
? MERGECOPY
:
1273 rop
== wxOR
? MERGEPAINT
:
1274 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1275 rop
== wxXOR
? SRCINVERT
:
1276 rop
== wxOR_REVERSE
? MERGEPAINT
:
1277 rop
== wxAND_REVERSE
? SRCERASE
:
1278 rop
== wxSRC_OR
? SRCPAINT
:
1279 rop
== wxSRC_AND
? SRCAND
:
1287 if ( ::MaskBlt(GetHdc(), xdest
, ydest
,
1288 (int)width
, (int)height
,
1289 GetHdcOf(*source
), xsrc
, ysrc
,
1290 (HBITMAP
) mask
->GetMaskBitmap(),
1291 0, 0, MAKEROP4(SRCCOPY
, PATCOPY
)) != 0 )
1299 // Blit bitmap with mask
1301 // create a temp buffer bitmap and DCs to access it and the mask
1302 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1303 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1304 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1305 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1306 ::SelectObject(dc_buffer
, buffer_bmap
);
1308 // copy dest to buffer
1309 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1310 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1312 wxLogLastError("BitBlt");
1315 // copy src to buffer using selected raster op
1316 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1317 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1319 wxLogLastError("BitBlt");
1322 // set masked area in buffer to BLACK (pixel value 0)
1323 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1324 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1325 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1326 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1328 wxLogLastError("BitBlt");
1331 // set unmasked area in dest to BLACK
1332 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1333 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1334 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1335 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1337 wxLogLastError("BitBlt");
1339 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1340 ::SetTextColor(GetHdc(), prevCol
);
1342 // OR buffer to dest
1343 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1344 (int)width
, (int)height
,
1345 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1348 wxLogLastError("BitBlt");
1351 // tidy up temporary DCs and bitmap
1352 ::SelectObject(dc_mask
, 0);
1353 ::DeleteDC(dc_mask
);
1354 ::SelectObject(dc_buffer
, 0);
1355 ::DeleteDC(dc_buffer
);
1356 ::DeleteObject(buffer_bmap
);
1359 else // no mask, just BitBlt() it
1361 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1362 (int)width
, (int)height
,
1363 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1366 wxLogLastError("BitBlt");
1370 ::SetTextColor(GetHdc(), old_textground
);
1371 ::SetBkColor(GetHdc(), old_background
);
1376 void wxDC::DoGetSize(int *w
, int *h
) const
1378 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1379 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1382 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1384 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1385 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1388 wxSize
wxDC::GetPPI() const
1390 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1391 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1393 return wxSize(x
, y
);
1396 // For use by wxWindows only, unless custom units are required.
1397 void wxDC::SetLogicalScale(double x
, double y
)
1399 m_logicalScaleX
= x
;
1400 m_logicalScaleY
= y
;
1403 #if WXWIN_COMPATIBILITY
1404 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1405 float *descent
, float *externalLeading
,
1406 wxFont
*theFont
, bool use16bit
) const
1408 wxCoord x1
, y1
, descent1
, externalLeading1
;
1409 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1412 *descent
= descent1
;
1413 if (externalLeading
)
1414 *externalLeading
= externalLeading1
;
1418 // ---------------------------------------------------------------------------
1419 // spline drawing code
1420 // ---------------------------------------------------------------------------
1424 class wxSpline
: public wxObject
1430 wxSpline(wxList
*list
);
1431 void DeletePoints();
1433 // Doesn't delete points
1437 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1439 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1440 double a3
, double b3
, double a4
, double b4
);
1441 void wx_clear_stack();
1442 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1443 double *y3
, double *x4
, double *y4
);
1444 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1445 double x4
, double y4
);
1446 static bool wx_spline_add_point(double x
, double y
);
1447 static void wx_spline_draw_point_array(wxDC
*dc
);
1448 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1450 void wxDC::DoDrawSpline(wxList
*list
)
1452 wxSpline
spline(list
);
1454 wx_draw_open_spline(this, &spline
);
1457 wxList wx_spline_point_list
;
1459 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1462 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1463 double x1
, y1
, x2
, y2
;
1465 wxNode
*node
= spline
->points
->First();
1466 p
= (wxPoint
*)node
->Data();
1471 node
= node
->Next();
1472 p
= (wxPoint
*)node
->Data();
1476 cx1
= (double)((x1
+ x2
) / 2);
1477 cy1
= (double)((y1
+ y2
) / 2);
1478 cx2
= (double)((cx1
+ x2
) / 2);
1479 cy2
= (double)((cy1
+ y2
) / 2);
1481 wx_spline_add_point(x1
, y1
);
1483 while ((node
= node
->Next()) != NULL
)
1485 p
= (wxPoint
*)node
->Data();
1490 cx4
= (double)(x1
+ x2
) / 2;
1491 cy4
= (double)(y1
+ y2
) / 2;
1492 cx3
= (double)(x1
+ cx4
) / 2;
1493 cy3
= (double)(y1
+ cy4
) / 2;
1495 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1499 cx2
= (double)(cx1
+ x2
) / 2;
1500 cy2
= (double)(cy1
+ y2
) / 2;
1503 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1504 wx_spline_add_point(x2
, y2
);
1506 wx_spline_draw_point_array(dc
);
1510 /********************* CURVES FOR SPLINES *****************************
1512 The following spline drawing routine is from
1514 "An Algorithm for High-Speed Curve Generation"
1515 by George Merrill Chaikin,
1516 Computer Graphics and Image Processing, 3, Academic Press,
1521 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1522 Computer Graphics and Image Processing, 4, Academic Press,
1525 ***********************************************************************/
1527 #define half(z1, z2) ((z1+z2)/2.0)
1530 /* iterative version */
1532 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1535 register double xmid
, ymid
;
1536 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1539 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1541 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1542 xmid
= (double)half(x2
, x3
);
1543 ymid
= (double)half(y2
, y3
);
1544 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1545 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1546 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1547 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1549 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1550 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1551 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1552 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1558 /* utilities used by spline drawing routines */
1561 typedef struct wx_spline_stack_struct
{
1562 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1566 #define SPLINE_STACK_DEPTH 20
1567 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1568 static Stack
*wx_stack_top
;
1569 static int wx_stack_count
;
1571 void wx_clear_stack()
1573 wx_stack_top
= wx_spline_stack
;
1577 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1579 wx_stack_top
->x1
= x1
;
1580 wx_stack_top
->y1
= y1
;
1581 wx_stack_top
->x2
= x2
;
1582 wx_stack_top
->y2
= y2
;
1583 wx_stack_top
->x3
= x3
;
1584 wx_stack_top
->y3
= y3
;
1585 wx_stack_top
->x4
= x4
;
1586 wx_stack_top
->y4
= y4
;
1591 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1592 double *x3
, double *y3
, double *x4
, double *y4
)
1594 if (wx_stack_count
== 0)
1598 *x1
= wx_stack_top
->x1
;
1599 *y1
= wx_stack_top
->y1
;
1600 *x2
= wx_stack_top
->x2
;
1601 *y2
= wx_stack_top
->y2
;
1602 *x3
= wx_stack_top
->x3
;
1603 *y3
= wx_stack_top
->y3
;
1604 *x4
= wx_stack_top
->x4
;
1605 *y4
= wx_stack_top
->y4
;
1609 static bool wx_spline_add_point(double x
, double y
)
1611 wxPoint
*point
= new wxPoint
;
1614 wx_spline_point_list
.Append((wxObject
*)point
);
1618 static void wx_spline_draw_point_array(wxDC
*dc
)
1620 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1621 wxNode
*node
= wx_spline_point_list
.First();
1624 wxPoint
*point
= (wxPoint
*)node
->Data();
1627 node
= wx_spline_point_list
.First();
1631 wxSpline::wxSpline(wxList
*list
)
1636 wxSpline::~wxSpline()
1640 void wxSpline::DeletePoints()
1642 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1644 wxPoint
*point
= (wxPoint
*)node
->Data();
1652 #endif // wxUSE_SPLINES