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(),
1233 // New code from Chris Breeze, 15/7/98
1234 // Blit bitmap with mask
1236 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1238 // If we are printing source colours are screen colours
1239 // not printer colours and so we need copy the bitmap
1242 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1243 HDC dc_src
= (HDC
) source
->m_hDC
;
1245 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1246 for (int x
= 0; x
< width
; x
++)
1248 for (int y
= 0; y
< height
; y
++)
1250 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1253 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1254 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1255 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1256 ::FillRect(GetHdc(), &rect
, brush
);
1257 ::DeleteObject(brush
);
1261 ::SelectObject(dc_mask
, 0);
1262 ::DeleteDC(dc_mask
);
1266 // create a temp buffer bitmap and DCs to access it and the mask
1267 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1268 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1269 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1270 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1271 ::SelectObject(dc_buffer
, buffer_bmap
);
1273 // copy dest to buffer
1274 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1275 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1277 // copy src to buffer using selected raster op
1278 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1279 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1281 // set masked area in buffer to BLACK (pixel value 0)
1282 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1283 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1284 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1285 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1287 // set unmasked area in dest to BLACK
1288 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1289 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1290 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1291 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1292 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1293 ::SetTextColor(GetHdc(), prevCol
);
1295 // OR buffer to dest
1296 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1297 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1299 // tidy up temporary DCs and bitmap
1300 ::SelectObject(dc_mask
, 0);
1301 ::DeleteDC(dc_mask
);
1302 ::SelectObject(dc_buffer
, 0);
1303 ::DeleteDC(dc_buffer
);
1304 ::DeleteObject(buffer_bmap
);
1310 // If we are printing, source colours are screen colours
1311 // not printer colours and so we need copy the bitmap
1313 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1315 HDC dc_src
= (HDC
) source
->m_hDC
;
1317 for (int y
= 0; y
< height
; y
++)
1319 // This is Stefan Csomor's optimisation, where
1320 // identical adjacent pixels are drawn together.
1321 // We still need a faster way of drawing bitmaps,
1322 // perhaps converting to a DIB first and using SetDIBitsToDevice.
1323 for (int x
= 0; x
< width
; x
++)
1325 COLORREF col
= ::GetPixel(dc_src
, x
, y
) ;
1326 HBRUSH brush
= ::CreateSolidBrush( col
);
1328 rect
.left
= xdest1
+ x
;
1329 rect
.top
= ydest1
+ y
;
1330 while( (x
+ 1 < width
) && (::GetPixel(dc_src
, x
+ 1, y
) == col
) )
1334 rect
.right
= xdest1
+ x
+ 1;
1335 rect
.bottom
= rect
.top
+ 1;
1336 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1337 ::DeleteObject(brush
);
1341 HDC dc_src = (HDC) source->m_hDC;
1343 for (int x = 0; x < width; x++)
1345 for (int y = 0; y < height; y++)
1347 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
1348 rect.left = xdest1 + x; rect.right = rect.left + 1;
1349 rect.top = ydest1 + y; rect.bottom = rect.top + 1;
1350 ::FillRect(GetHdc(), &rect, brush);
1351 ::DeleteObject(brush);
1358 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1359 xsrc1
, ysrc1
, dwRop
) != 0);
1362 ::SetTextColor(GetHdc(), old_textground
);
1363 ::SetBkColor(GetHdc(), old_background
);
1368 void wxDC::DoGetSize(int *w
, int *h
) const
1370 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1371 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1374 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1376 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1377 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1380 wxSize
wxDC::GetPPI() const
1382 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1383 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1385 return wxSize(x
, y
);
1388 // For use by wxWindows only, unless custom units are required.
1389 void wxDC::SetLogicalScale(double x
, double y
)
1391 m_logicalScaleX
= x
;
1392 m_logicalScaleY
= y
;
1395 #if WXWIN_COMPATIBILITY
1396 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1397 float *descent
, float *externalLeading
,
1398 wxFont
*theFont
, bool use16bit
) const
1400 wxCoord x1
, y1
, descent1
, externalLeading1
;
1401 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1404 *descent
= descent1
;
1405 if (externalLeading
)
1406 *externalLeading
= externalLeading1
;
1410 // ---------------------------------------------------------------------------
1411 // spline drawing code
1412 // ---------------------------------------------------------------------------
1416 class wxSpline
: public wxObject
1422 wxSpline(wxList
*list
);
1423 void DeletePoints();
1425 // Doesn't delete points
1429 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1431 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1432 double a3
, double b3
, double a4
, double b4
);
1433 void wx_clear_stack();
1434 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1435 double *y3
, double *x4
, double *y4
);
1436 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1437 double x4
, double y4
);
1438 static bool wx_spline_add_point(double x
, double y
);
1439 static void wx_spline_draw_point_array(wxDC
*dc
);
1440 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1442 void wxDC::DoDrawSpline(wxList
*list
)
1444 wxSpline
spline(list
);
1446 wx_draw_open_spline(this, &spline
);
1449 wxList wx_spline_point_list
;
1451 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1454 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1455 double x1
, y1
, x2
, y2
;
1457 wxNode
*node
= spline
->points
->First();
1458 p
= (wxPoint
*)node
->Data();
1463 node
= node
->Next();
1464 p
= (wxPoint
*)node
->Data();
1468 cx1
= (double)((x1
+ x2
) / 2);
1469 cy1
= (double)((y1
+ y2
) / 2);
1470 cx2
= (double)((cx1
+ x2
) / 2);
1471 cy2
= (double)((cy1
+ y2
) / 2);
1473 wx_spline_add_point(x1
, y1
);
1475 while ((node
= node
->Next()) != NULL
)
1477 p
= (wxPoint
*)node
->Data();
1482 cx4
= (double)(x1
+ x2
) / 2;
1483 cy4
= (double)(y1
+ y2
) / 2;
1484 cx3
= (double)(x1
+ cx4
) / 2;
1485 cy3
= (double)(y1
+ cy4
) / 2;
1487 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1491 cx2
= (double)(cx1
+ x2
) / 2;
1492 cy2
= (double)(cy1
+ y2
) / 2;
1495 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1496 wx_spline_add_point(x2
, y2
);
1498 wx_spline_draw_point_array(dc
);
1502 /********************* CURVES FOR SPLINES *****************************
1504 The following spline drawing routine is from
1506 "An Algorithm for High-Speed Curve Generation"
1507 by George Merrill Chaikin,
1508 Computer Graphics and Image Processing, 3, Academic Press,
1513 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1514 Computer Graphics and Image Processing, 4, Academic Press,
1517 ***********************************************************************/
1519 #define half(z1, z2) ((z1+z2)/2.0)
1522 /* iterative version */
1524 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1527 register double xmid
, ymid
;
1528 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1531 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1533 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1534 xmid
= (double)half(x2
, x3
);
1535 ymid
= (double)half(y2
, y3
);
1536 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1537 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1538 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1539 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1541 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1542 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1543 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1544 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1550 /* utilities used by spline drawing routines */
1553 typedef struct wx_spline_stack_struct
{
1554 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1558 #define SPLINE_STACK_DEPTH 20
1559 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1560 static Stack
*wx_stack_top
;
1561 static int wx_stack_count
;
1563 void wx_clear_stack()
1565 wx_stack_top
= wx_spline_stack
;
1569 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1571 wx_stack_top
->x1
= x1
;
1572 wx_stack_top
->y1
= y1
;
1573 wx_stack_top
->x2
= x2
;
1574 wx_stack_top
->y2
= y2
;
1575 wx_stack_top
->x3
= x3
;
1576 wx_stack_top
->y3
= y3
;
1577 wx_stack_top
->x4
= x4
;
1578 wx_stack_top
->y4
= y4
;
1583 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1584 double *x3
, double *y3
, double *x4
, double *y4
)
1586 if (wx_stack_count
== 0)
1590 *x1
= wx_stack_top
->x1
;
1591 *y1
= wx_stack_top
->y1
;
1592 *x2
= wx_stack_top
->x2
;
1593 *y2
= wx_stack_top
->y2
;
1594 *x3
= wx_stack_top
->x3
;
1595 *y3
= wx_stack_top
->y3
;
1596 *x4
= wx_stack_top
->x4
;
1597 *y4
= wx_stack_top
->y4
;
1601 static bool wx_spline_add_point(double x
, double y
)
1603 wxPoint
*point
= new wxPoint
;
1606 wx_spline_point_list
.Append((wxObject
*)point
);
1610 static void wx_spline_draw_point_array(wxDC
*dc
)
1612 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1613 wxNode
*node
= wx_spline_point_list
.First();
1616 wxPoint
*point
= (wxPoint
*)node
->Data();
1619 node
= wx_spline_point_list
.First();
1623 wxSpline::wxSpline(wxList
*list
)
1628 wxSpline::~wxSpline()
1632 void wxSpline::DeletePoints()
1634 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1636 wxPoint
*point
= (wxPoint
*)node
->Data();
1644 #endif // wxUSE_SPLINES