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 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 // ---------------------------------------------------------------------------
79 // ---------------------------------------------------------------------------
81 // convert degrees to radians
82 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
84 // ===========================================================================
86 // ===========================================================================
88 // ---------------------------------------------------------------------------
90 // ---------------------------------------------------------------------------
92 // Default constructor
106 m_windowExtX
= VIEWPORT_EXTENT
;
107 m_windowExtY
= VIEWPORT_EXTENT
;
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC(GetHdc());
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
127 // This will select current objects out of the DC,
128 // which is what you have to do before deleting the
130 void wxDC::SelectOldObjects(WXHDC dc
)
136 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
137 if (m_selectedBitmap
.Ok())
139 m_selectedBitmap
.SetSelectedInto(NULL
);
145 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
150 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
155 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
160 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
165 m_brush
= wxNullBrush
;
167 m_palette
= wxNullPalette
;
169 m_backgroundBrush
= wxNullBrush
;
170 m_selectedBitmap
= wxNullBitmap
;
173 // ---------------------------------------------------------------------------
175 // ---------------------------------------------------------------------------
177 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
182 m_clipX2
= (int)(cx
+ cw
);
183 m_clipY2
= (int)(cy
+ ch
);
185 DoClipping((WXHDC
) m_hDC
);
188 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
190 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
192 wxRect box
= region
.GetBox();
197 m_clipX2
= box
.x
+ box
.width
;
198 m_clipY2
= box
.y
+ box
.height
;
201 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
203 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
207 void wxDC::DoClipping(WXHDC dc
)
209 if (m_clipping
&& dc
)
211 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
212 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
216 void wxDC::DestroyClippingRegion()
218 if (m_clipping
&& m_hDC
)
220 // TODO: this should restore the previous clipping region,
221 // so that OnPaint processing works correctly, and the update clipping region
222 // doesn't get destroyed after the first DestroyClippingRegion.
223 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
224 SelectClipRgn(GetHdc(), rgn
);
230 // ---------------------------------------------------------------------------
231 // query capabilities
232 // ---------------------------------------------------------------------------
234 bool wxDC::CanDrawBitmap() const
239 bool wxDC::CanGetTextExtent() const
241 // What sort of display is it?
242 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
244 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
247 int wxDC::GetDepth() const
249 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
252 // ---------------------------------------------------------------------------
254 // ---------------------------------------------------------------------------
261 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
265 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
267 rect
.left
= 0; rect
.top
= 0;
268 rect
.right
= m_selectedBitmap
.GetWidth();
269 rect
.bottom
= m_selectedBitmap
.GetHeight();
272 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
274 DWORD colour
= GetBkColor(GetHdc());
275 HBRUSH brush
= CreateSolidBrush(colour
);
276 FillRect(GetHdc(), &rect
, brush
);
279 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
280 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
281 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
282 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
283 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
286 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
288 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
290 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
293 CalcBoundingBox(x
, y
);
296 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
298 // added by steve 29.12.94 (copied from DrawPoint)
299 // returns TRUE for pixels in the color of the current pen
300 // and FALSE for all other pixels colors
301 // if col is non-NULL return the color of the pixel
303 // get the color of the pixel
304 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
305 // get the color of the pen
306 COLORREF pencolor
= 0x00ffffff;
309 pencolor
= m_pen
.GetColour().GetPixel();
312 // return the color of the pixel
314 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
316 // check, if color of the pixels is the same as the color
317 // of the current pen
318 return(pixelcolor
==pencolor
);
321 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
323 wxCoord x1
= x
-VIEWPORT_EXTENT
;
324 wxCoord y1
= y
-VIEWPORT_EXTENT
;
325 wxCoord x2
= x
+VIEWPORT_EXTENT
;
326 wxCoord y2
= y
+VIEWPORT_EXTENT
;
328 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
329 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
331 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
332 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
334 CalcBoundingBox(x1
, y1
);
335 CalcBoundingBox(x2
, y2
);
338 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
340 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
341 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
343 /* MATTHEW: [6] New normalization */
344 #if WX_STANDARD_GRAPHICS
345 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
348 CalcBoundingBox(x1
, y1
);
349 CalcBoundingBox(x2
, y2
);
352 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
356 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
357 if (x1
==x2
&& x2
==y2
)
359 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
363 wxCoord xx1
= XLOG2DEV(x1
);
364 wxCoord yy1
= YLOG2DEV(y1
);
365 wxCoord xx2
= XLOG2DEV(x2
);
366 wxCoord yy2
= YLOG2DEV(y2
);
367 wxCoord xxc
= XLOG2DEV(xc
);
368 wxCoord yyc
= YLOG2DEV(yc
);
369 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
371 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
372 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
373 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
374 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
375 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
376 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
378 // Have to add 1 to bottom-right corner of rectangle
379 // to make semi-circles look right (crooked line otherwise).
380 // Unfortunately this is not a reliable method, depends
381 // on the size of shape.
382 // TODO: figure out why this happens!
383 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
387 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
390 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
391 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
394 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
396 COLORREF color
= 0x00ffffff;
399 color
= m_pen
.GetColour().GetPixel();
402 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
404 CalcBoundingBox(x
, y
);
407 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
409 // Do things less efficiently if we have offsets
410 if (xoffset
!= 0 || yoffset
!= 0)
412 POINT
*cpoints
= new POINT
[n
];
414 for (i
= 0; i
< n
; i
++)
416 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
417 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
419 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
421 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
422 (void)Polygon(GetHdc(), cpoints
, n
);
423 SetPolyFillMode(GetHdc(),prev
);
429 for (i
= 0; i
< n
; i
++)
430 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
432 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
433 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
434 SetPolyFillMode(GetHdc(),prev
);
438 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
440 // Do things less efficiently if we have offsets
441 if (xoffset
!= 0 || yoffset
!= 0)
443 POINT
*cpoints
= new POINT
[n
];
445 for (i
= 0; i
< n
; i
++)
447 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
448 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
450 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
452 (void)Polyline(GetHdc(), cpoints
, n
);
458 for (i
= 0; i
< n
; i
++)
459 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
461 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
465 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
467 wxCoord x2
= x
+ width
;
468 wxCoord y2
= y
+ height
;
470 /* MATTHEW: [6] new normalization */
471 #if WX_STANDARD_GRAPHICS
472 bool do_brush
, do_pen
;
474 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
475 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
478 HPEN orig_pen
= NULL
;
480 if (do_pen
|| !m_pen
.Ok())
481 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
483 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
484 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
486 if (do_pen
|| !m_pen
.Ok())
487 ::SelectObject(GetHdc() , orig_pen
);
490 HBRUSH orig_brush
= NULL
;
492 if (do_brush
|| !m_brush
.Ok())
493 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
495 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
496 XLOG2DEV(x2
), YLOG2DEV(y2
));
498 if (do_brush
|| !m_brush
.Ok())
499 ::SelectObject(GetHdc(), orig_brush
);
502 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
505 CalcBoundingBox(x
, y
);
506 CalcBoundingBox(x2
, y2
);
509 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
511 // Now, a negative radius value is interpreted to mean
512 // 'the proportion of the smallest X or Y dimension'
516 double smallest
= 0.0;
521 radius
= (- radius
* smallest
);
524 wxCoord x2
= (x
+width
);
525 wxCoord y2
= (y
+height
);
527 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
528 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
530 CalcBoundingBox(x
, y
);
531 CalcBoundingBox(x2
, y2
);
534 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
536 wxCoord x2
= (x
+width
);
537 wxCoord y2
= (y
+height
);
539 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
541 CalcBoundingBox(x
, y
);
542 CalcBoundingBox(x2
, y2
);
545 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
546 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
551 int rx1
= XLOG2DEV(x
+w
/2);
552 int ry1
= YLOG2DEV(y
+h
/2);
559 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
560 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
561 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
562 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
564 // draw pie with NULL_PEN first and then outline otherwise a line is
565 // drawn from the start and end points to the centre
566 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
569 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
574 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
575 rx1
, ry1
-1, rx2
, ry2
-1);
577 ::SelectObject(GetHdc(), orig_pen
);
578 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
581 CalcBoundingBox(x
, y
);
582 CalcBoundingBox(x2
, y2
);
585 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
587 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
588 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
589 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
591 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
594 CalcBoundingBox(x
, y
);
595 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
598 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
603 // If we're not drawing transparently, and not drawing to a printer,
604 // optimize this function to use Windows functions.
605 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
608 HDC memdc
= ::CreateCompatibleDC( cdc
);
609 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
611 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
613 ::SelectObject( memdc
, hbitmap
);
614 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
619 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
621 memDC
.SelectObject(bmp
);
623 /* Not sure if we need this. The mask should leave the
624 * masked areas as per the original background of this DC.
627 // There might be transparent areas, so make these
628 // the same colour as this DC
629 memDC.SetBackground(* GetBackground());
633 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
635 memDC
.SelectObject(wxNullBitmap
);
639 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
641 DrawAnyText(text
, x
, y
);
643 // update the bounding box
644 CalcBoundingBox(x
, y
);
647 GetTextExtent(text
, &w
, &h
);
648 CalcBoundingBox(x
+ w
, y
+ h
);
651 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
653 // prepare for drawing the text
654 if ( m_textForegroundColour
.Ok() )
655 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
657 DWORD old_background
= 0;
658 if ( m_textBackgroundColour
.Ok() )
660 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
663 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
666 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
667 text
.c_str(), text
.length()) == 0 )
669 wxLogLastError("TextOut");
672 // restore the old parameters (text foreground colour may be left because
673 // it never is set to anything else, but background should remain
674 // transparent even if we just drew an opaque string)
675 if ( m_textBackgroundColour
.Ok() )
676 (void)SetBkColor(GetHdc(), old_background
);
678 SetBkMode(GetHdc(), TRANSPARENT
);
681 void wxDC::DoDrawRotatedText(const wxString
& text
,
682 wxCoord x
, wxCoord y
,
685 // we test that we have some font because otherwise we should still use the
686 // "else" part below to avoid that DrawRotatedText(angle = 180) and
687 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
688 // font for drawing rotated fonts unfortunately)
689 if ( (angle
== 0.0) && m_font
.Ok() )
691 DoDrawText(text
, x
, y
);
695 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
696 // can't have non zero orientation/escapement
697 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
698 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
700 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
702 wxLogLastError("GetObject(hfont)");
705 // GDI wants the angle in tenth of degree
706 long angle10
= (long)(angle
* 10);
707 lf
.lfEscapement
= angle10
;
708 lf
. lfOrientation
= angle10
;
710 hfont
= ::CreateFontIndirect(&lf
);
713 wxLogLastError("CreateFont");
717 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
719 DrawAnyText(text
, x
, y
);
721 (void)::SelectObject(GetHdc(), hfontOld
);
724 // call the bounding box by adding all four vertices of the rectangle
725 // containing the text to it (simpler and probably not slower than
726 // determining which of them is really topmost/leftmost/...)
728 GetTextExtent(text
, &w
, &h
);
730 double rad
= DegToRad(angle
);
732 // "upper left" and "upper right"
733 CalcBoundingBox(x
, y
);
734 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
736 // "bottom left" and "bottom right"
737 x
+= (wxCoord
)(h
*sin(rad
));
738 y
+= (wxCoord
)(h
*cos(rad
));
739 CalcBoundingBox(x
, y
);
740 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
744 // ---------------------------------------------------------------------------
746 // ---------------------------------------------------------------------------
748 void wxDC::SetPalette(const wxPalette
& palette
)
750 // Set the old object temporarily, in case the assignment deletes an object
751 // that's not yet selected out.
754 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
762 // Setting a NULL colourmap is a way of restoring
763 // the original colourmap
766 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
773 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
775 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
777 m_oldPalette
= (WXHPALETTE
) oldPal
;
779 ::RealizePalette(GetHdc());
783 void wxDC::SetFont(const wxFont
& the_font
)
785 // Set the old object temporarily, in case the assignment deletes an object
786 // that's not yet selected out.
789 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
798 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
802 if (m_font
.Ok() && m_font
.GetResourceHandle())
804 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
805 if (f
== (HFONT
) NULL
)
807 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
810 m_oldFont
= (WXHFONT
) f
;
814 void wxDC::SetPen(const wxPen
& pen
)
816 // Set the old object temporarily, in case the assignment deletes an object
817 // that's not yet selected out.
820 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
829 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
835 if (m_pen
.GetResourceHandle())
837 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
839 m_oldPen
= (WXHPEN
) p
;
844 void wxDC::SetBrush(const wxBrush
& brush
)
846 // Set the old object temporarily, in case the assignment deletes an object
847 // that's not yet selected out.
850 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
859 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
865 if (m_brush
.GetResourceHandle())
868 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
870 m_oldBrush
= (WXHBRUSH
) b
;
875 void wxDC::SetBackground(const wxBrush
& brush
)
877 m_backgroundBrush
= brush
;
879 if (!m_backgroundBrush
.Ok())
884 bool customColours
= TRUE
;
885 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
886 // change background colours from the control-panel specified colours.
887 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
888 customColours
= FALSE
;
892 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
894 m_canvas
->SetTransparent(TRUE
);
898 // New behaviour, 10/2/99: setting the background brush of a DC
899 // doesn't affect the window background colour. However,
900 // I'm leaving in the transparency setting because it's needed by
901 // various controls (e.g. wxStaticText) to determine whether to draw
902 // transparently or not. TODO: maybe this should be a new function
903 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
905 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
906 m_canvas
->SetTransparent(FALSE
);
910 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
912 (void)SetBkColor(GetHdc(), new_color
);
916 void wxDC::SetBackgroundMode(int mode
)
918 m_backgroundMode
= mode
;
920 // SetBackgroundColour now only refers to text background
921 // and m_backgroundMode is used there
924 if (m_backgroundMode == wxTRANSPARENT)
925 ::SetBkMode(GetHdc(), TRANSPARENT);
927 ::SetBkMode(GetHdc(), OPAQUE);
931 void wxDC::SetLogicalFunction(int function
)
933 m_logicalFunction
= function
;
935 SetRop((WXHDC
) m_hDC
);
938 void wxDC::SetRop(WXHDC dc
)
940 if (!dc
|| m_logicalFunction
< 0)
944 // These may be wrong
945 switch (m_logicalFunction
)
947 // case wxXOR: c_rop = R2_XORPEN; break;
948 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
949 case wxINVERT
: c_rop
= R2_NOT
; break;
950 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
951 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
952 case wxCLEAR
: c_rop
= R2_WHITE
; break;
953 case wxSET
: c_rop
= R2_BLACK
; break;
954 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
955 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
956 case wxAND
: c_rop
= R2_MASKPEN
; break;
957 case wxOR
: c_rop
= R2_MERGEPEN
; break;
958 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
963 c_rop
= R2_COPYPEN
; break;
965 SetROP2((HDC
) dc
, c_rop
);
968 bool wxDC::StartDoc(const wxString
& message
)
970 // We might be previewing, so return TRUE to let it continue.
978 void wxDC::StartPage()
986 // ---------------------------------------------------------------------------
988 // ---------------------------------------------------------------------------
990 wxCoord
wxDC::GetCharHeight() const
992 TEXTMETRIC lpTextMetric
;
994 GetTextMetrics(GetHdc(), &lpTextMetric
);
996 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
999 wxCoord
wxDC::GetCharWidth() const
1001 TEXTMETRIC lpTextMetric
;
1003 GetTextMetrics(GetHdc(), &lpTextMetric
);
1005 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1008 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1009 wxCoord
*descent
, wxCoord
*externalLeading
,
1010 wxFont
*theFont
) const
1012 wxFont
*fontToUse
= (wxFont
*) theFont
;
1014 fontToUse
= (wxFont
*) &m_font
;
1019 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1020 GetTextMetrics(GetHdc(), &tm
);
1022 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1023 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1024 if (descent
) *descent
= tm
.tmDescent
;
1025 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1028 void wxDC::SetMapMode(int mode
)
1030 m_mappingMode
= mode
;
1032 int pixel_width
= 0;
1033 int pixel_height
= 0;
1037 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1038 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1039 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1040 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1042 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1047 double mm2pixelsX
= pixel_width
/mm_width
;
1048 double mm2pixelsY
= pixel_height
/mm_height
;
1054 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1055 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1060 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1061 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1066 m_logicalScaleX
= mm2pixelsX
;
1067 m_logicalScaleY
= mm2pixelsY
;
1072 m_logicalScaleX
= (mm2pixelsX
/10.0);
1073 m_logicalScaleY
= (mm2pixelsY
/10.0);
1079 m_logicalScaleX
= 1.0;
1080 m_logicalScaleY
= 1.0;
1085 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1086 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1088 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1089 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1090 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1091 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1092 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1093 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1096 void wxDC::SetUserScale(double x
, double y
)
1101 SetMapMode(m_mappingMode
);
1104 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1106 m_signX
= xLeftRight
? 1 : -1;
1107 m_signY
= yBottomUp
? -1 : 1;
1109 SetMapMode(m_mappingMode
);
1112 void wxDC::SetSystemScale(double x
, double y
)
1117 SetMapMode(m_mappingMode
);
1120 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1122 m_logicalOriginX
= x
;
1123 m_logicalOriginY
= y
;
1125 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1128 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1130 m_deviceOriginX
= x
;
1131 m_deviceOriginY
= y
;
1133 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1136 // ---------------------------------------------------------------------------
1137 // coordinates transformations
1138 // ---------------------------------------------------------------------------
1140 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1142 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1145 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1147 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1150 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1152 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1155 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1157 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1160 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1162 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1165 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1167 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1170 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1172 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1175 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1177 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1180 // ---------------------------------------------------------------------------
1182 // ---------------------------------------------------------------------------
1183 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1184 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int rop
, bool useMask
)
1186 wxCoord xdest1
= xdest
;
1187 wxCoord ydest1
= ydest
;
1188 wxCoord xsrc1
= xsrc
;
1189 wxCoord ysrc1
= ysrc
;
1191 // Chris Breeze 18/5/98: use text foreground/background colours
1192 // when blitting from 1-bit bitmaps
1193 COLORREF old_textground
= ::GetTextColor(GetHdc());
1194 COLORREF old_background
= ::GetBkColor(GetHdc());
1195 if (m_textForegroundColour
.Ok())
1197 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1199 if (m_textBackgroundColour
.Ok())
1201 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1204 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1205 rop
== wxCLEAR
? WHITENESS
:
1206 rop
== wxSET
? BLACKNESS
:
1207 rop
== wxINVERT
? DSTINVERT
:
1208 rop
== wxAND
? MERGECOPY
:
1209 rop
== wxOR
? MERGEPAINT
:
1210 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1211 rop
== wxXOR
? SRCINVERT
:
1212 rop
== wxOR_REVERSE
? MERGEPAINT
:
1213 rop
== wxAND_REVERSE
? SRCERASE
:
1214 rop
== wxSRC_OR
? SRCPAINT
:
1215 rop
== wxSRC_AND
? SRCAND
:
1218 bool success
= TRUE
;
1219 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1223 // Not implemented under Win95 (or maybe a specific device?)
1224 if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1225 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1235 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1236 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1237 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1238 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1239 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1240 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1241 ::SelectObject(dc_mask
, 0);
1242 ::DeleteDC(dc_mask
);
1244 // New code from Chris Breeze, 15/7/98
1245 // Blit bitmap with mask
1247 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1249 // If we are printing source colours are screen colours
1250 // not printer colours and so we need copy the bitmap
1253 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1254 HDC dc_src
= (HDC
) source
->m_hDC
;
1256 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1257 for (int x
= 0; x
< width
; x
++)
1259 for (int y
= 0; y
< height
; y
++)
1261 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1264 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1265 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1266 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1267 ::FillRect(GetHdc(), &rect
, brush
);
1268 ::DeleteObject(brush
);
1272 ::SelectObject(dc_mask
, 0);
1273 ::DeleteDC(dc_mask
);
1277 // create a temp buffer bitmap and DCs to access it and the mask
1278 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1279 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1280 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1281 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1282 ::SelectObject(dc_buffer
, buffer_bmap
);
1284 // copy dest to buffer
1285 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1286 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1288 // copy src to buffer using selected raster op
1289 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1290 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1292 // set masked area in buffer to BLACK (pixel value 0)
1293 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1294 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1295 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1296 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1298 // set unmasked area in dest to BLACK
1299 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1300 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1301 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1302 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1303 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1304 ::SetTextColor(GetHdc(), prevCol
);
1306 // OR buffer to dest
1307 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1308 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1310 // tidy up temporary DCs and bitmap
1311 ::SelectObject(dc_mask
, 0);
1312 ::DeleteDC(dc_mask
);
1313 ::SelectObject(dc_buffer
, 0);
1314 ::DeleteDC(dc_buffer
);
1315 ::DeleteObject(buffer_bmap
);
1321 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1323 // If we are printing, source colours are screen colours
1324 // not printer colours and so we need copy the bitmap
1326 HDC dc_src
= (HDC
) source
->m_hDC
;
1328 for (int x
= 0; x
< width
; x
++)
1330 for (int y
= 0; y
< height
; y
++)
1332 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1333 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1334 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1335 ::FillRect(GetHdc(), &rect
, brush
);
1336 ::DeleteObject(brush
);
1342 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1343 xsrc1
, ysrc1
, dwRop
) != 0);
1346 ::SetTextColor(GetHdc(), old_textground
);
1347 ::SetBkColor(GetHdc(), old_background
);
1352 void wxDC::DoGetSize(int *w
, int *h
) const
1354 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1355 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1358 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1360 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1361 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1364 wxSize
wxDC::GetPPI() const
1366 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1367 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1369 return wxSize(x
, y
);
1372 // For use by wxWindows only, unless custom units are required.
1373 void wxDC::SetLogicalScale(double x
, double y
)
1375 m_logicalScaleX
= x
;
1376 m_logicalScaleY
= y
;
1379 #if WXWIN_COMPATIBILITY
1380 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1381 float *descent
, float *externalLeading
,
1382 wxFont
*theFont
, bool use16bit
) const
1384 wxCoord x1
, y1
, descent1
, externalLeading1
;
1385 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1388 *descent
= descent1
;
1389 if (externalLeading
)
1390 *externalLeading
= externalLeading1
;
1394 // ---------------------------------------------------------------------------
1395 // spline drawing code
1396 // ---------------------------------------------------------------------------
1400 class wxSpline
: public wxObject
1406 wxSpline(wxList
*list
);
1407 void DeletePoints();
1409 // Doesn't delete points
1413 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1415 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1416 double a3
, double b3
, double a4
, double b4
);
1417 void wx_clear_stack();
1418 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1419 double *y3
, double *x4
, double *y4
);
1420 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1421 double x4
, double y4
);
1422 static bool wx_spline_add_point(double x
, double y
);
1423 static void wx_spline_draw_point_array(wxDC
*dc
);
1424 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1426 void wxDC::DoDrawSpline(wxList
*list
)
1428 wxSpline
spline(list
);
1430 wx_draw_open_spline(this, &spline
);
1433 wxList wx_spline_point_list
;
1435 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1438 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1439 double x1
, y1
, x2
, y2
;
1441 wxNode
*node
= spline
->points
->First();
1442 p
= (wxPoint
*)node
->Data();
1447 node
= node
->Next();
1448 p
= (wxPoint
*)node
->Data();
1452 cx1
= (double)((x1
+ x2
) / 2);
1453 cy1
= (double)((y1
+ y2
) / 2);
1454 cx2
= (double)((cx1
+ x2
) / 2);
1455 cy2
= (double)((cy1
+ y2
) / 2);
1457 wx_spline_add_point(x1
, y1
);
1459 while ((node
= node
->Next()) != NULL
)
1461 p
= (wxPoint
*)node
->Data();
1466 cx4
= (double)(x1
+ x2
) / 2;
1467 cy4
= (double)(y1
+ y2
) / 2;
1468 cx3
= (double)(x1
+ cx4
) / 2;
1469 cy3
= (double)(y1
+ cy4
) / 2;
1471 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1475 cx2
= (double)(cx1
+ x2
) / 2;
1476 cy2
= (double)(cy1
+ y2
) / 2;
1479 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1480 wx_spline_add_point(x2
, y2
);
1482 wx_spline_draw_point_array(dc
);
1486 /********************* CURVES FOR SPLINES *****************************
1488 The following spline drawing routine is from
1490 "An Algorithm for High-Speed Curve Generation"
1491 by George Merrill Chaikin,
1492 Computer Graphics and Image Processing, 3, Academic Press,
1497 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1498 Computer Graphics and Image Processing, 4, Academic Press,
1501 ***********************************************************************/
1503 #define half(z1, z2) ((z1+z2)/2.0)
1506 /* iterative version */
1508 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1511 register double xmid
, ymid
;
1512 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1515 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1517 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1518 xmid
= (double)half(x2
, x3
);
1519 ymid
= (double)half(y2
, y3
);
1520 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1521 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1522 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1523 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1525 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1526 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1527 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1528 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1534 /* utilities used by spline drawing routines */
1537 typedef struct wx_spline_stack_struct
{
1538 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1542 #define SPLINE_STACK_DEPTH 20
1543 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1544 static Stack
*wx_stack_top
;
1545 static int wx_stack_count
;
1547 void wx_clear_stack()
1549 wx_stack_top
= wx_spline_stack
;
1553 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1555 wx_stack_top
->x1
= x1
;
1556 wx_stack_top
->y1
= y1
;
1557 wx_stack_top
->x2
= x2
;
1558 wx_stack_top
->y2
= y2
;
1559 wx_stack_top
->x3
= x3
;
1560 wx_stack_top
->y3
= y3
;
1561 wx_stack_top
->x4
= x4
;
1562 wx_stack_top
->y4
= y4
;
1567 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1568 double *x3
, double *y3
, double *x4
, double *y4
)
1570 if (wx_stack_count
== 0)
1574 *x1
= wx_stack_top
->x1
;
1575 *y1
= wx_stack_top
->y1
;
1576 *x2
= wx_stack_top
->x2
;
1577 *y2
= wx_stack_top
->y2
;
1578 *x3
= wx_stack_top
->x3
;
1579 *y3
= wx_stack_top
->y3
;
1580 *x4
= wx_stack_top
->x4
;
1581 *y4
= wx_stack_top
->y4
;
1585 static bool wx_spline_add_point(double x
, double y
)
1587 wxPoint
*point
= new wxPoint
;
1590 wx_spline_point_list
.Append((wxObject
*)point
);
1594 static void wx_spline_draw_point_array(wxDC
*dc
)
1596 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1597 wxNode
*node
= wx_spline_point_list
.First();
1600 wxPoint
*point
= (wxPoint
*)node
->Data();
1603 node
= wx_spline_point_list
.First();
1607 wxSpline::wxSpline(wxList
*list
)
1612 wxSpline::~wxSpline()
1616 void wxSpline::DeletePoints()
1618 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1620 wxPoint
*point
= (wxPoint
*)node
->Data();
1628 #endif // wxUSE_SPLINES