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 #if wxUSE_COMMON_DIALOGS
49 #if wxUSE_NORLANDER_HEADERS
59 #include "wx/msw/private.h"
61 #if !USE_SHARED_LIBRARY
62 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
65 // ---------------------------------------------------------------------------
67 // ---------------------------------------------------------------------------
69 static const int VIEWPORT_EXTENT
= 1000;
71 static const int MM_POINTS
= 9;
72 static const int MM_METRIC
= 10;
74 // usually this is defined in math.h
76 static const double M_PI
= 3.14159265358979323846;
79 // ---------------------------------------------------------------------------
81 // ---------------------------------------------------------------------------
83 // convert degrees to radians
84 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
86 // ===========================================================================
88 // ===========================================================================
90 // ---------------------------------------------------------------------------
92 // ---------------------------------------------------------------------------
94 // Default constructor
108 m_windowExtX
= VIEWPORT_EXTENT
;
109 m_windowExtY
= VIEWPORT_EXTENT
;
118 SelectOldObjects(m_hDC
);
120 if ( m_canvas
== NULL
)
121 ::DeleteDC(GetHdc());
123 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
129 // This will select current objects out of the DC,
130 // which is what you have to do before deleting the
132 void wxDC::SelectOldObjects(WXHDC dc
)
138 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
139 if (m_selectedBitmap
.Ok())
141 m_selectedBitmap
.SetSelectedInto(NULL
);
147 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
152 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
157 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
162 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
167 m_brush
= wxNullBrush
;
169 m_palette
= wxNullPalette
;
171 m_backgroundBrush
= wxNullBrush
;
172 m_selectedBitmap
= wxNullBitmap
;
175 // ---------------------------------------------------------------------------
177 // ---------------------------------------------------------------------------
179 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
184 m_clipX2
= (int)(cx
+ cw
);
185 m_clipY2
= (int)(cy
+ ch
);
187 DoClipping((WXHDC
) m_hDC
);
190 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
192 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
194 wxRect box
= region
.GetBox();
199 m_clipX2
= box
.x
+ box
.width
;
200 m_clipY2
= box
.y
+ box
.height
;
203 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
205 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
209 void wxDC::DoClipping(WXHDC dc
)
211 if (m_clipping
&& dc
)
213 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
214 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
218 void wxDC::DestroyClippingRegion()
220 if (m_clipping
&& m_hDC
)
222 // TODO: this should restore the previous clipping region,
223 // so that OnPaint processing works correctly, and the update clipping region
224 // doesn't get destroyed after the first DestroyClippingRegion.
225 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
226 SelectClipRgn(GetHdc(), rgn
);
232 // ---------------------------------------------------------------------------
233 // query capabilities
234 // ---------------------------------------------------------------------------
236 bool wxDC::CanDrawBitmap() const
241 bool wxDC::CanGetTextExtent() const
243 // What sort of display is it?
244 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
246 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
249 int wxDC::GetDepth() const
251 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
254 // ---------------------------------------------------------------------------
256 // ---------------------------------------------------------------------------
263 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
267 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
269 rect
.left
= 0; rect
.top
= 0;
270 rect
.right
= m_selectedBitmap
.GetWidth();
271 rect
.bottom
= m_selectedBitmap
.GetHeight();
274 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
276 DWORD colour
= GetBkColor(GetHdc());
277 HBRUSH brush
= CreateSolidBrush(colour
);
278 FillRect(GetHdc(), &rect
, brush
);
281 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
282 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
283 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
284 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
285 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
288 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
290 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
292 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
295 CalcBoundingBox(x
, y
);
298 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
300 // added by steve 29.12.94 (copied from DrawPoint)
301 // returns TRUE for pixels in the color of the current pen
302 // and FALSE for all other pixels colors
303 // if col is non-NULL return the color of the pixel
305 // get the color of the pixel
306 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
307 // get the color of the pen
308 COLORREF pencolor
= 0x00ffffff;
311 pencolor
= m_pen
.GetColour().GetPixel();
314 // return the color of the pixel
316 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
318 // check, if color of the pixels is the same as the color
319 // of the current pen
320 return(pixelcolor
==pencolor
);
323 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
325 wxCoord x1
= x
-VIEWPORT_EXTENT
;
326 wxCoord y1
= y
-VIEWPORT_EXTENT
;
327 wxCoord x2
= x
+VIEWPORT_EXTENT
;
328 wxCoord y2
= y
+VIEWPORT_EXTENT
;
330 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
331 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
333 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
334 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
336 CalcBoundingBox(x1
, y1
);
337 CalcBoundingBox(x2
, y2
);
340 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
342 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
343 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
345 /* MATTHEW: [6] New normalization */
346 #if WX_STANDARD_GRAPHICS
347 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
350 CalcBoundingBox(x1
, y1
);
351 CalcBoundingBox(x2
, y2
);
354 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
358 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
359 if (x1
==x2
&& x2
==y2
)
361 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
365 wxCoord xx1
= XLOG2DEV(x1
);
366 wxCoord yy1
= YLOG2DEV(y1
);
367 wxCoord xx2
= XLOG2DEV(x2
);
368 wxCoord yy2
= YLOG2DEV(y2
);
369 wxCoord xxc
= XLOG2DEV(xc
);
370 wxCoord yyc
= YLOG2DEV(yc
);
371 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
373 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
374 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
375 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
376 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
377 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
378 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
380 // Have to add 1 to bottom-right corner of rectangle
381 // to make semi-circles look right (crooked line otherwise).
382 // Unfortunately this is not a reliable method, depends
383 // on the size of shape.
384 // TODO: figure out why this happens!
385 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
389 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
392 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
393 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
396 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
398 COLORREF color
= 0x00ffffff;
401 color
= m_pen
.GetColour().GetPixel();
404 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
406 CalcBoundingBox(x
, y
);
409 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
411 // Do things less efficiently if we have offsets
412 if (xoffset
!= 0 || yoffset
!= 0)
414 POINT
*cpoints
= new POINT
[n
];
416 for (i
= 0; i
< n
; i
++)
418 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
419 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
421 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
423 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
424 (void)Polygon(GetHdc(), cpoints
, n
);
425 SetPolyFillMode(GetHdc(),prev
);
431 for (i
= 0; i
< n
; i
++)
432 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
434 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
435 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
436 SetPolyFillMode(GetHdc(),prev
);
440 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
442 // Do things less efficiently if we have offsets
443 if (xoffset
!= 0 || yoffset
!= 0)
445 POINT
*cpoints
= new POINT
[n
];
447 for (i
= 0; i
< n
; i
++)
449 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
450 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
452 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
454 (void)Polyline(GetHdc(), cpoints
, n
);
460 for (i
= 0; i
< n
; i
++)
461 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
463 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
467 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
469 wxCoord x2
= x
+ width
;
470 wxCoord y2
= y
+ height
;
472 /* MATTHEW: [6] new normalization */
473 #if WX_STANDARD_GRAPHICS
474 bool do_brush
, do_pen
;
476 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
477 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
480 HPEN orig_pen
= NULL
;
482 if (do_pen
|| !m_pen
.Ok())
483 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
485 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
486 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
488 if (do_pen
|| !m_pen
.Ok())
489 ::SelectObject(GetHdc() , orig_pen
);
492 HBRUSH orig_brush
= NULL
;
494 if (do_brush
|| !m_brush
.Ok())
495 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
497 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
498 XLOG2DEV(x2
), YLOG2DEV(y2
));
500 if (do_brush
|| !m_brush
.Ok())
501 ::SelectObject(GetHdc(), orig_brush
);
504 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
507 CalcBoundingBox(x
, y
);
508 CalcBoundingBox(x2
, y2
);
511 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
513 // Now, a negative radius value is interpreted to mean
514 // 'the proportion of the smallest X or Y dimension'
518 double smallest
= 0.0;
523 radius
= (- radius
* smallest
);
526 wxCoord x2
= (x
+width
);
527 wxCoord y2
= (y
+height
);
529 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
530 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
532 CalcBoundingBox(x
, y
);
533 CalcBoundingBox(x2
, y2
);
536 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
538 wxCoord x2
= (x
+width
);
539 wxCoord y2
= (y
+height
);
541 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
543 CalcBoundingBox(x
, y
);
544 CalcBoundingBox(x2
, y2
);
547 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
548 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
553 int rx1
= XLOG2DEV(x
+w
/2);
554 int ry1
= YLOG2DEV(y
+h
/2);
561 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
562 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
563 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
564 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
566 // draw pie with NULL_PEN first and then outline otherwise a line is
567 // drawn from the start and end points to the centre
568 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
571 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
576 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
577 rx1
, ry1
-1, rx2
, ry2
-1);
579 ::SelectObject(GetHdc(), orig_pen
);
580 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
583 CalcBoundingBox(x
, y
);
584 CalcBoundingBox(x2
, y2
);
587 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
589 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
590 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
591 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
593 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
596 CalcBoundingBox(x
, y
);
597 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
600 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
605 // If we're not drawing transparently, and not drawing to a printer,
606 // optimize this function to use Windows functions.
607 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
610 HDC memdc
= ::CreateCompatibleDC( cdc
);
611 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
613 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
615 ::SelectObject( memdc
, hbitmap
);
616 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
621 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
623 memDC
.SelectObject(bmp
);
625 /* Not sure if we need this. The mask should leave the
626 * masked areas as per the original background of this DC.
629 // There might be transparent areas, so make these
630 // the same colour as this DC
631 memDC.SetBackground(* GetBackground());
635 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
637 memDC
.SelectObject(wxNullBitmap
);
641 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
643 DrawAnyText(text
, x
, y
);
645 // update the bounding box
646 CalcBoundingBox(x
, y
);
649 GetTextExtent(text
, &w
, &h
);
650 CalcBoundingBox(x
+ w
, y
+ h
);
653 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
655 // prepare for drawing the text
656 if ( m_textForegroundColour
.Ok() )
657 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
659 DWORD old_background
= 0;
660 if ( m_textBackgroundColour
.Ok() )
662 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
665 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
668 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
669 text
.c_str(), text
.length()) != 0 )
671 wxLogLastError("TextOut");
674 // restore the old parameters (text foreground colour may be left because
675 // it never is set to anything else, but background should remain
676 // transparent even if we just drew an opaque string)
677 if ( m_textBackgroundColour
.Ok() )
678 (void)SetBkColor(GetHdc(), old_background
);
680 SetBkMode(GetHdc(), TRANSPARENT
);
683 void wxDC::DoDrawRotatedText(const wxString
& text
,
684 wxCoord x
, wxCoord y
,
689 DoDrawText(text
, x
, y
);
694 wxFillLogFont(&lf
, &m_font
);
696 // GDI wants the angle in tenth of degree
697 long angle10
= (long)(angle
* 10);
698 lf
.lfEscapement
= angle10
;
699 lf
. lfOrientation
= angle10
;
701 HFONT hfont
= ::CreateFontIndirect(&lf
);
704 wxLogLastError("CreateFont");
708 HFONT hfontOld
= ::SelectObject(GetHdc(), hfont
);
710 DrawAnyText(text
, x
, y
);
712 (void)::SelectObject(GetHdc(), hfontOld
);
715 // call the bounding box by adding all four vertices of the rectangle
716 // containing the text to it (simpler and probably not slower than
717 // determining which of them is really topmost/leftmost/...)
719 GetTextExtent(text
, &w
, &h
);
721 double rad
= DegToRad(angle
);
723 // "upper left" and "upper right"
724 CalcBoundingBox(x
, y
);
725 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
726 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
728 // "bottom left" and "bottom right"
729 x
+= (wxCoord
)(h
*sin(rad
));
730 y
+= (wxCoord
)(h
*cos(rad
));
731 CalcBoundingBox(x
, y
);
732 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
736 // ---------------------------------------------------------------------------
738 // ---------------------------------------------------------------------------
740 void wxDC::SetPalette(const wxPalette
& palette
)
742 // Set the old object temporarily, in case the assignment deletes an object
743 // that's not yet selected out.
746 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
754 // Setting a NULL colourmap is a way of restoring
755 // the original colourmap
758 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
765 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
767 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
769 m_oldPalette
= (WXHPALETTE
) oldPal
;
771 ::RealizePalette(GetHdc());
775 void wxDC::SetFont(const wxFont
& the_font
)
777 // Set the old object temporarily, in case the assignment deletes an object
778 // that's not yet selected out.
781 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
790 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
794 if (m_font
.Ok() && m_font
.GetResourceHandle())
796 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
797 if (f
== (HFONT
) NULL
)
799 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
802 m_oldFont
= (WXHFONT
) f
;
806 void wxDC::SetPen(const wxPen
& pen
)
808 // Set the old object temporarily, in case the assignment deletes an object
809 // that's not yet selected out.
812 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
821 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
827 if (m_pen
.GetResourceHandle())
829 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
831 m_oldPen
= (WXHPEN
) p
;
836 void wxDC::SetBrush(const wxBrush
& brush
)
838 // Set the old object temporarily, in case the assignment deletes an object
839 // that's not yet selected out.
842 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
851 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
857 if (m_brush
.GetResourceHandle())
860 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
862 m_oldBrush
= (WXHBRUSH
) b
;
867 void wxDC::SetBackground(const wxBrush
& brush
)
869 m_backgroundBrush
= brush
;
871 if (!m_backgroundBrush
.Ok())
876 bool customColours
= TRUE
;
877 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
878 // change background colours from the control-panel specified colours.
879 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
880 customColours
= FALSE
;
884 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
886 m_canvas
->SetTransparent(TRUE
);
890 // New behaviour, 10/2/99: setting the background brush of a DC
891 // doesn't affect the window background colour. However,
892 // I'm leaving in the transparency setting because it's needed by
893 // various controls (e.g. wxStaticText) to determine whether to draw
894 // transparently or not. TODO: maybe this should be a new function
895 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
897 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
898 m_canvas
->SetTransparent(FALSE
);
902 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
904 (void)SetBkColor(GetHdc(), new_color
);
908 void wxDC::SetBackgroundMode(int mode
)
910 m_backgroundMode
= mode
;
912 // SetBackgroundColour now only refers to text background
913 // and m_backgroundMode is used there
916 if (m_backgroundMode == wxTRANSPARENT)
917 ::SetBkMode(GetHdc(), TRANSPARENT);
919 ::SetBkMode(GetHdc(), OPAQUE);
923 void wxDC::SetLogicalFunction(int function
)
925 m_logicalFunction
= function
;
927 SetRop((WXHDC
) m_hDC
);
930 void wxDC::SetRop(WXHDC dc
)
932 if (!dc
|| m_logicalFunction
< 0)
936 // These may be wrong
937 switch (m_logicalFunction
)
939 // case wxXOR: c_rop = R2_XORPEN; break;
940 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
941 case wxINVERT
: c_rop
= R2_NOT
; break;
942 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
943 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
944 case wxCLEAR
: c_rop
= R2_WHITE
; break;
945 case wxSET
: c_rop
= R2_BLACK
; break;
946 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
947 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
948 case wxAND
: c_rop
= R2_MASKPEN
; break;
949 case wxOR
: c_rop
= R2_MERGEPEN
; break;
950 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
955 c_rop
= R2_COPYPEN
; break;
957 SetROP2((HDC
) dc
, c_rop
);
960 bool wxDC::StartDoc(const wxString
& message
)
962 // We might be previewing, so return TRUE to let it continue.
970 void wxDC::StartPage()
978 // ---------------------------------------------------------------------------
980 // ---------------------------------------------------------------------------
982 wxCoord
wxDC::GetCharHeight() const
984 TEXTMETRIC lpTextMetric
;
986 GetTextMetrics(GetHdc(), &lpTextMetric
);
988 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
991 wxCoord
wxDC::GetCharWidth() const
993 TEXTMETRIC lpTextMetric
;
995 GetTextMetrics(GetHdc(), &lpTextMetric
);
997 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1000 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1001 wxCoord
*descent
, wxCoord
*externalLeading
,
1002 wxFont
*theFont
) const
1004 wxFont
*fontToUse
= (wxFont
*) theFont
;
1006 fontToUse
= (wxFont
*) &m_font
;
1011 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1012 GetTextMetrics(GetHdc(), &tm
);
1014 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1015 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1016 if (descent
) *descent
= tm
.tmDescent
;
1017 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1020 void wxDC::SetMapMode(int mode
)
1022 m_mappingMode
= mode
;
1024 int pixel_width
= 0;
1025 int pixel_height
= 0;
1029 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1030 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1031 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1032 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1034 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1039 double mm2pixelsX
= pixel_width
/mm_width
;
1040 double mm2pixelsY
= pixel_height
/mm_height
;
1046 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1047 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1052 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1053 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1058 m_logicalScaleX
= mm2pixelsX
;
1059 m_logicalScaleY
= mm2pixelsY
;
1064 m_logicalScaleX
= (mm2pixelsX
/10.0);
1065 m_logicalScaleY
= (mm2pixelsY
/10.0);
1071 m_logicalScaleX
= 1.0;
1072 m_logicalScaleY
= 1.0;
1077 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1078 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1080 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1081 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1082 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1083 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1084 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1085 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1088 void wxDC::SetUserScale(double x
, double y
)
1093 SetMapMode(m_mappingMode
);
1096 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1098 m_signX
= xLeftRight
? 1 : -1;
1099 m_signY
= yBottomUp
? -1 : 1;
1101 SetMapMode(m_mappingMode
);
1104 void wxDC::SetSystemScale(double x
, double y
)
1109 SetMapMode(m_mappingMode
);
1112 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1114 m_logicalOriginX
= x
;
1115 m_logicalOriginY
= y
;
1117 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1120 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1122 m_deviceOriginX
= x
;
1123 m_deviceOriginY
= y
;
1125 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1128 // ---------------------------------------------------------------------------
1129 // coordinates transformations
1130 // ---------------------------------------------------------------------------
1132 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1134 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1137 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1139 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1142 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1144 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1147 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1149 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1152 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1154 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1157 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1159 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1162 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1164 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1167 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1169 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1172 // ---------------------------------------------------------------------------
1174 // ---------------------------------------------------------------------------
1175 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1176 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int rop
, bool useMask
)
1178 wxCoord xdest1
= xdest
;
1179 wxCoord ydest1
= ydest
;
1180 wxCoord xsrc1
= xsrc
;
1181 wxCoord ysrc1
= ysrc
;
1183 // Chris Breeze 18/5/98: use text foreground/background colours
1184 // when blitting from 1-bit bitmaps
1185 COLORREF old_textground
= ::GetTextColor(GetHdc());
1186 COLORREF old_background
= ::GetBkColor(GetHdc());
1187 if (m_textForegroundColour
.Ok())
1189 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1191 if (m_textBackgroundColour
.Ok())
1193 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1196 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1197 rop
== wxCLEAR
? WHITENESS
:
1198 rop
== wxSET
? BLACKNESS
:
1199 rop
== wxINVERT
? DSTINVERT
:
1200 rop
== wxAND
? MERGECOPY
:
1201 rop
== wxOR
? MERGEPAINT
:
1202 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1203 rop
== wxXOR
? SRCINVERT
:
1204 rop
== wxOR_REVERSE
? MERGEPAINT
:
1205 rop
== wxAND_REVERSE
? SRCERASE
:
1206 rop
== wxSRC_OR
? SRCPAINT
:
1207 rop
== wxSRC_AND
? SRCAND
:
1210 bool success
= TRUE
;
1211 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1215 // Not implemented under Win95 (or maybe a specific device?)
1216 if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1217 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1227 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1228 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1229 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1230 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1231 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1232 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1233 ::SelectObject(dc_mask
, 0);
1234 ::DeleteDC(dc_mask
);
1236 // New code from Chris Breeze, 15/7/98
1237 // Blit bitmap with mask
1239 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1241 // If we are printing source colours are screen colours
1242 // not printer colours and so we need copy the bitmap
1245 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1246 HDC dc_src
= (HDC
) source
->m_hDC
;
1248 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1249 for (int x
= 0; x
< width
; x
++)
1251 for (int y
= 0; y
< height
; y
++)
1253 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1256 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1257 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1258 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1259 ::FillRect(GetHdc(), &rect
, brush
);
1260 ::DeleteObject(brush
);
1264 ::SelectObject(dc_mask
, 0);
1265 ::DeleteDC(dc_mask
);
1269 // create a temp buffer bitmap and DCs to access it and the mask
1270 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1271 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1272 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1273 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1274 ::SelectObject(dc_buffer
, buffer_bmap
);
1276 // copy dest to buffer
1277 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1278 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1280 // copy src to buffer using selected raster op
1281 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1282 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1284 // set masked area in buffer to BLACK (pixel value 0)
1285 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1286 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1287 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1288 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1290 // set unmasked area in dest to BLACK
1291 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1292 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1293 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1294 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1295 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1296 ::SetTextColor(GetHdc(), prevCol
);
1298 // OR buffer to dest
1299 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1300 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1302 // tidy up temporary DCs and bitmap
1303 ::SelectObject(dc_mask
, 0);
1304 ::DeleteDC(dc_mask
);
1305 ::SelectObject(dc_buffer
, 0);
1306 ::DeleteDC(dc_buffer
);
1307 ::DeleteObject(buffer_bmap
);
1313 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1315 // If we are printing, source colours are screen colours
1316 // not printer colours and so we need copy the bitmap
1318 HDC dc_src
= (HDC
) source
->m_hDC
;
1320 for (int x
= 0; x
< width
; x
++)
1322 for (int y
= 0; y
< height
; y
++)
1324 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1325 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1326 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1327 ::FillRect(GetHdc(), &rect
, brush
);
1328 ::DeleteObject(brush
);
1334 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1335 xsrc1
, ysrc1
, dwRop
) != 0);
1338 ::SetTextColor(GetHdc(), old_textground
);
1339 ::SetBkColor(GetHdc(), old_background
);
1344 void wxDC::DoGetSize(int *w
, int *h
) const
1346 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1347 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1350 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1352 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1353 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1356 wxSize
wxDC::GetPPI() const
1358 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1359 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1361 return wxSize(x
, y
);
1364 // For use by wxWindows only, unless custom units are required.
1365 void wxDC::SetLogicalScale(double x
, double y
)
1367 m_logicalScaleX
= x
;
1368 m_logicalScaleY
= y
;
1371 #if WXWIN_COMPATIBILITY
1372 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1373 float *descent
, float *externalLeading
,
1374 wxFont
*theFont
, bool use16bit
) const
1376 wxCoord x1
, y1
, descent1
, externalLeading1
;
1377 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1380 *descent
= descent1
;
1381 if (externalLeading
)
1382 *externalLeading
= externalLeading1
;
1386 // ---------------------------------------------------------------------------
1387 // spline drawing code
1388 // ---------------------------------------------------------------------------
1392 class wxSpline
: public wxObject
1398 wxSpline(wxList
*list
);
1399 void DeletePoints();
1401 // Doesn't delete points
1405 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1407 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1408 double a3
, double b3
, double a4
, double b4
);
1409 void wx_clear_stack();
1410 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1411 double *y3
, double *x4
, double *y4
);
1412 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1413 double x4
, double y4
);
1414 static bool wx_spline_add_point(double x
, double y
);
1415 static void wx_spline_draw_point_array(wxDC
*dc
);
1416 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1418 void wxDC::DoDrawSpline(wxList
*list
)
1420 wxSpline
spline(list
);
1422 wx_draw_open_spline(this, &spline
);
1425 wxList wx_spline_point_list
;
1427 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1430 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1431 double x1
, y1
, x2
, y2
;
1433 wxNode
*node
= spline
->points
->First();
1434 p
= (wxPoint
*)node
->Data();
1439 node
= node
->Next();
1440 p
= (wxPoint
*)node
->Data();
1444 cx1
= (double)((x1
+ x2
) / 2);
1445 cy1
= (double)((y1
+ y2
) / 2);
1446 cx2
= (double)((cx1
+ x2
) / 2);
1447 cy2
= (double)((cy1
+ y2
) / 2);
1449 wx_spline_add_point(x1
, y1
);
1451 while ((node
= node
->Next()) != NULL
)
1453 p
= (wxPoint
*)node
->Data();
1458 cx4
= (double)(x1
+ x2
) / 2;
1459 cy4
= (double)(y1
+ y2
) / 2;
1460 cx3
= (double)(x1
+ cx4
) / 2;
1461 cy3
= (double)(y1
+ cy4
) / 2;
1463 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1467 cx2
= (double)(cx1
+ x2
) / 2;
1468 cy2
= (double)(cy1
+ y2
) / 2;
1471 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1472 wx_spline_add_point(x2
, y2
);
1474 wx_spline_draw_point_array(dc
);
1478 /********************* CURVES FOR SPLINES *****************************
1480 The following spline drawing routine is from
1482 "An Algorithm for High-Speed Curve Generation"
1483 by George Merrill Chaikin,
1484 Computer Graphics and Image Processing, 3, Academic Press,
1489 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1490 Computer Graphics and Image Processing, 4, Academic Press,
1493 ***********************************************************************/
1495 #define half(z1, z2) ((z1+z2)/2.0)
1498 /* iterative version */
1500 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1503 register double xmid
, ymid
;
1504 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1507 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1509 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1510 xmid
= (double)half(x2
, x3
);
1511 ymid
= (double)half(y2
, y3
);
1512 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1513 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1514 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1515 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1517 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1518 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1519 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1520 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1526 /* utilities used by spline drawing routines */
1529 typedef struct wx_spline_stack_struct
{
1530 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1534 #define SPLINE_STACK_DEPTH 20
1535 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1536 static Stack
*wx_stack_top
;
1537 static int wx_stack_count
;
1539 void wx_clear_stack()
1541 wx_stack_top
= wx_spline_stack
;
1545 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1547 wx_stack_top
->x1
= x1
;
1548 wx_stack_top
->y1
= y1
;
1549 wx_stack_top
->x2
= x2
;
1550 wx_stack_top
->y2
= y2
;
1551 wx_stack_top
->x3
= x3
;
1552 wx_stack_top
->y3
= y3
;
1553 wx_stack_top
->x4
= x4
;
1554 wx_stack_top
->y4
= y4
;
1559 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1560 double *x3
, double *y3
, double *x4
, double *y4
)
1562 if (wx_stack_count
== 0)
1566 *x1
= wx_stack_top
->x1
;
1567 *y1
= wx_stack_top
->y1
;
1568 *x2
= wx_stack_top
->x2
;
1569 *y2
= wx_stack_top
->y2
;
1570 *x3
= wx_stack_top
->x3
;
1571 *y3
= wx_stack_top
->y3
;
1572 *x4
= wx_stack_top
->x4
;
1573 *y4
= wx_stack_top
->y4
;
1577 static bool wx_spline_add_point(double x
, double y
)
1579 wxPoint
*point
= new wxPoint
;
1582 wx_spline_point_list
.Append((wxObject
*)point
);
1586 static void wx_spline_draw_point_array(wxDC
*dc
)
1588 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1589 wxNode
*node
= wx_spline_point_list
.First();
1592 wxPoint
*point
= (wxPoint
*)node
->Data();
1595 node
= wx_spline_point_list
.First();
1599 wxSpline::wxSpline(wxList
*list
)
1604 wxSpline::~wxSpline()
1608 void wxSpline::DeletePoints()
1610 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1612 wxPoint
*point
= (wxPoint
*)node
->Data();
1620 #endif // wxUSE_SPLINES