1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/dcprint.h"
49 #if wxUSE_COMMON_DIALOGS
50 #if wxUSE_NORLANDER_HEADERS
60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
62 // ---------------------------------------------------------------------------
64 // ---------------------------------------------------------------------------
66 static const int VIEWPORT_EXTENT
= 1000;
68 static const int MM_POINTS
= 9;
69 static const int MM_METRIC
= 10;
71 // usually this is defined in math.h
73 static const double M_PI
= 3.14159265358979323846;
76 // ---------------------------------------------------------------------------
78 // ---------------------------------------------------------------------------
80 // convert degrees to radians
81 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
83 // ===========================================================================
85 // ===========================================================================
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 // Default constructor
105 m_windowExtX
= VIEWPORT_EXTENT
;
106 m_windowExtY
= VIEWPORT_EXTENT
;
115 SelectOldObjects(m_hDC
);
117 if ( m_canvas
== NULL
)
118 ::DeleteDC(GetHdc());
120 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
126 // This will select current objects out of the DC,
127 // which is what you have to do before deleting the
129 void wxDC::SelectOldObjects(WXHDC dc
)
135 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
136 if (m_selectedBitmap
.Ok())
138 m_selectedBitmap
.SetSelectedInto(NULL
);
144 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
149 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
154 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
159 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
164 m_brush
= wxNullBrush
;
166 m_palette
= wxNullPalette
;
168 m_backgroundBrush
= wxNullBrush
;
169 m_selectedBitmap
= wxNullBitmap
;
172 // ---------------------------------------------------------------------------
174 // ---------------------------------------------------------------------------
176 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
181 m_clipX2
= (int)(cx
+ cw
);
182 m_clipY2
= (int)(cy
+ ch
);
184 DoClipping((WXHDC
) m_hDC
);
187 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
189 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
191 wxRect box
= region
.GetBox();
196 m_clipX2
= box
.x
+ box
.width
;
197 m_clipY2
= box
.y
+ box
.height
;
200 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
202 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
206 void wxDC::DoClipping(WXHDC dc
)
208 if (m_clipping
&& dc
)
210 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
211 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
215 void wxDC::DestroyClippingRegion()
217 if (m_clipping
&& m_hDC
)
219 // TODO: this should restore the previous clipping region,
220 // so that OnPaint processing works correctly, and the update clipping region
221 // doesn't get destroyed after the first DestroyClippingRegion.
222 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
223 SelectClipRgn(GetHdc(), rgn
);
229 // ---------------------------------------------------------------------------
230 // query capabilities
231 // ---------------------------------------------------------------------------
233 bool wxDC::CanDrawBitmap() const
238 bool wxDC::CanGetTextExtent() const
240 // What sort of display is it?
241 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
243 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
246 int wxDC::GetDepth() const
248 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
251 // ---------------------------------------------------------------------------
253 // ---------------------------------------------------------------------------
260 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
264 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
266 rect
.left
= 0; rect
.top
= 0;
267 rect
.right
= m_selectedBitmap
.GetWidth();
268 rect
.bottom
= m_selectedBitmap
.GetHeight();
271 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
273 DWORD colour
= GetBkColor(GetHdc());
274 HBRUSH brush
= CreateSolidBrush(colour
);
275 FillRect(GetHdc(), &rect
, brush
);
278 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
279 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
280 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
281 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
282 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
285 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
287 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
289 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
292 CalcBoundingBox(x
, y
);
295 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
297 // added by steve 29.12.94 (copied from DrawPoint)
298 // returns TRUE for pixels in the color of the current pen
299 // and FALSE for all other pixels colors
300 // if col is non-NULL return the color of the pixel
302 // get the color of the pixel
303 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
304 // get the color of the pen
305 COLORREF pencolor
= 0x00ffffff;
308 pencolor
= m_pen
.GetColour().GetPixel();
311 // return the color of the pixel
313 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
315 // check, if color of the pixels is the same as the color
316 // of the current pen
317 return(pixelcolor
==pencolor
);
320 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
322 wxCoord x1
= x
-VIEWPORT_EXTENT
;
323 wxCoord y1
= y
-VIEWPORT_EXTENT
;
324 wxCoord x2
= x
+VIEWPORT_EXTENT
;
325 wxCoord y2
= y
+VIEWPORT_EXTENT
;
327 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
328 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
330 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
331 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
333 CalcBoundingBox(x1
, y1
);
334 CalcBoundingBox(x2
, y2
);
337 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
339 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
340 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
342 /* MATTHEW: [6] New normalization */
343 #if WX_STANDARD_GRAPHICS
344 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
347 CalcBoundingBox(x1
, y1
);
348 CalcBoundingBox(x2
, y2
);
351 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
355 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
356 if (x1
==x2
&& x2
==y2
)
358 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
362 wxCoord xx1
= XLOG2DEV(x1
);
363 wxCoord yy1
= YLOG2DEV(y1
);
364 wxCoord xx2
= XLOG2DEV(x2
);
365 wxCoord yy2
= YLOG2DEV(y2
);
366 wxCoord xxc
= XLOG2DEV(xc
);
367 wxCoord yyc
= YLOG2DEV(yc
);
368 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
370 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
371 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
372 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
373 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
374 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
375 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
377 // Have to add 1 to bottom-right corner of rectangle
378 // to make semi-circles look right (crooked line otherwise).
379 // Unfortunately this is not a reliable method, depends
380 // on the size of shape.
381 // TODO: figure out why this happens!
382 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
386 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
389 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
390 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
393 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
395 COLORREF color
= 0x00ffffff;
398 color
= m_pen
.GetColour().GetPixel();
401 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
403 CalcBoundingBox(x
, y
);
406 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
408 // Do things less efficiently if we have offsets
409 if (xoffset
!= 0 || yoffset
!= 0)
411 POINT
*cpoints
= new POINT
[n
];
413 for (i
= 0; i
< n
; i
++)
415 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
416 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
418 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
420 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
421 (void)Polygon(GetHdc(), cpoints
, n
);
422 SetPolyFillMode(GetHdc(),prev
);
428 for (i
= 0; i
< n
; i
++)
429 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
431 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
432 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
433 SetPolyFillMode(GetHdc(),prev
);
437 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
439 // Do things less efficiently if we have offsets
440 if (xoffset
!= 0 || yoffset
!= 0)
442 POINT
*cpoints
= new POINT
[n
];
444 for (i
= 0; i
< n
; i
++)
446 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
447 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
449 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
451 (void)Polyline(GetHdc(), cpoints
, n
);
457 for (i
= 0; i
< n
; i
++)
458 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
460 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
464 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
466 wxCoord x2
= x
+ width
;
467 wxCoord y2
= y
+ height
;
469 /* MATTHEW: [6] new normalization */
470 #if WX_STANDARD_GRAPHICS
471 bool do_brush
, do_pen
;
473 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
474 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
477 HPEN orig_pen
= NULL
;
479 if (do_pen
|| !m_pen
.Ok())
480 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
482 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
483 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
485 if (do_pen
|| !m_pen
.Ok())
486 ::SelectObject(GetHdc() , orig_pen
);
489 HBRUSH orig_brush
= NULL
;
491 if (do_brush
|| !m_brush
.Ok())
492 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
494 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
495 XLOG2DEV(x2
), YLOG2DEV(y2
));
497 if (do_brush
|| !m_brush
.Ok())
498 ::SelectObject(GetHdc(), orig_brush
);
501 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
504 CalcBoundingBox(x
, y
);
505 CalcBoundingBox(x2
, y2
);
508 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
510 // Now, a negative radius value is interpreted to mean
511 // 'the proportion of the smallest X or Y dimension'
515 double smallest
= 0.0;
520 radius
= (- radius
* smallest
);
523 wxCoord x2
= (x
+width
);
524 wxCoord y2
= (y
+height
);
526 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
527 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
529 CalcBoundingBox(x
, y
);
530 CalcBoundingBox(x2
, y2
);
533 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
535 wxCoord x2
= (x
+width
);
536 wxCoord y2
= (y
+height
);
538 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
540 CalcBoundingBox(x
, y
);
541 CalcBoundingBox(x2
, y2
);
544 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
545 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
550 int rx1
= XLOG2DEV(x
+w
/2);
551 int ry1
= YLOG2DEV(y
+h
/2);
558 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
559 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
560 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
561 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
563 // draw pie with NULL_PEN first and then outline otherwise a line is
564 // drawn from the start and end points to the centre
565 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
568 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
573 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
574 rx1
, ry1
-1, rx2
, ry2
-1);
576 ::SelectObject(GetHdc(), orig_pen
);
577 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
580 CalcBoundingBox(x
, y
);
581 CalcBoundingBox(x2
, y2
);
584 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
586 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
588 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
590 CalcBoundingBox(x
, y
);
591 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
594 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
596 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
598 int width
= bmp
.GetWidth(),
599 height
= bmp
.GetHeight();
604 HDC memdc
= ::CreateCompatibleDC( cdc
);
605 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
607 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
609 COLORREF old_textground
= ::GetTextColor(GetHdc());
610 COLORREF old_background
= ::GetBkColor(GetHdc());
611 if (m_textForegroundColour
.Ok())
613 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
615 if (m_textBackgroundColour
.Ok())
617 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
620 ::SelectObject( memdc
, hbitmap
);
621 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
624 ::SetTextColor(GetHdc(), old_textground
);
625 ::SetBkColor(GetHdc(), old_background
);
629 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
631 memDC
.SelectObject(bmp
);
633 Blit(x
, y
, width
, height
, &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 // ---------------------------------------------------------------------------
1184 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1185 wxCoord width
, wxCoord height
,
1186 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1187 int rop
, bool useMask
)
1189 wxMask
*mask
= NULL
;
1192 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1193 mask
= bmp
.GetMask();
1195 wxCHECK_MSG( bmp
.Ok() && mask
, FALSE
,
1196 _T("can't blit with mask without mask") );
1199 COLORREF old_textground
= ::GetTextColor(GetHdc());
1200 COLORREF old_background
= ::GetBkColor(GetHdc());
1201 if (m_textForegroundColour
.Ok())
1203 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1205 if (m_textBackgroundColour
.Ok())
1207 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1210 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1211 rop
== wxCLEAR
? WHITENESS
:
1212 rop
== wxSET
? BLACKNESS
:
1213 rop
== wxINVERT
? DSTINVERT
:
1214 rop
== wxAND
? MERGECOPY
:
1215 rop
== wxOR
? MERGEPAINT
:
1216 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1217 rop
== wxXOR
? SRCINVERT
:
1218 rop
== wxOR_REVERSE
? MERGEPAINT
:
1219 rop
== wxAND_REVERSE
? SRCERASE
:
1220 rop
== wxSRC_OR
? SRCPAINT
:
1221 rop
== wxSRC_AND
? SRCAND
:
1229 if ( ::MaskBlt(GetHdc(), xdest
, ydest
,
1230 (int)width
, (int)height
,
1231 GetHdcOf(*source
), xsrc
, ysrc
,
1232 (HBITMAP
) mask
->GetMaskBitmap(),
1233 0, 0, MAKEROP4(SRCCOPY
, PATCOPY
)) != 0 )
1241 // Blit bitmap with mask
1243 // create a temp buffer bitmap and DCs to access it and the mask
1244 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1245 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1246 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1247 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1248 ::SelectObject(dc_buffer
, buffer_bmap
);
1250 // copy dest to buffer
1251 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1252 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1254 wxLogLastError("BitBlt");
1257 // copy src to buffer using selected raster op
1258 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1259 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1261 wxLogLastError("BitBlt");
1264 // set masked area in buffer to BLACK (pixel value 0)
1265 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1266 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1267 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1268 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1270 wxLogLastError("BitBlt");
1273 // set unmasked area in dest to BLACK
1274 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1275 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1276 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1277 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1279 wxLogLastError("BitBlt");
1281 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1282 ::SetTextColor(GetHdc(), prevCol
);
1284 // OR buffer to dest
1285 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1286 (int)width
, (int)height
,
1287 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1290 wxLogLastError("BitBlt");
1293 // tidy up temporary DCs and bitmap
1294 ::SelectObject(dc_mask
, 0);
1295 ::DeleteDC(dc_mask
);
1296 ::SelectObject(dc_buffer
, 0);
1297 ::DeleteDC(dc_buffer
);
1298 ::DeleteObject(buffer_bmap
);
1301 else // no mask, just BitBlt() it
1303 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1304 (int)width
, (int)height
,
1305 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1308 wxLogLastError("BitBlt");
1312 ::SetTextColor(GetHdc(), old_textground
);
1313 ::SetBkColor(GetHdc(), old_background
);
1318 void wxDC::DoGetSize(int *w
, int *h
) const
1320 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1321 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1324 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1326 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1327 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1330 wxSize
wxDC::GetPPI() const
1332 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1333 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1335 return wxSize(x
, y
);
1338 // For use by wxWindows only, unless custom units are required.
1339 void wxDC::SetLogicalScale(double x
, double y
)
1341 m_logicalScaleX
= x
;
1342 m_logicalScaleY
= y
;
1345 #if WXWIN_COMPATIBILITY
1346 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1347 float *descent
, float *externalLeading
,
1348 wxFont
*theFont
, bool use16bit
) const
1350 wxCoord x1
, y1
, descent1
, externalLeading1
;
1351 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1354 *descent
= descent1
;
1355 if (externalLeading
)
1356 *externalLeading
= externalLeading1
;
1360 // ---------------------------------------------------------------------------
1361 // spline drawing code
1362 // ---------------------------------------------------------------------------
1366 class wxSpline
: public wxObject
1372 wxSpline(wxList
*list
);
1373 void DeletePoints();
1375 // Doesn't delete points
1379 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1381 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1382 double a3
, double b3
, double a4
, double b4
);
1383 void wx_clear_stack();
1384 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1385 double *y3
, double *x4
, double *y4
);
1386 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1387 double x4
, double y4
);
1388 static bool wx_spline_add_point(double x
, double y
);
1389 static void wx_spline_draw_point_array(wxDC
*dc
);
1390 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1392 void wxDC::DoDrawSpline(wxList
*list
)
1394 wxSpline
spline(list
);
1396 wx_draw_open_spline(this, &spline
);
1399 wxList wx_spline_point_list
;
1401 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1404 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1405 double x1
, y1
, x2
, y2
;
1407 wxNode
*node
= spline
->points
->First();
1408 p
= (wxPoint
*)node
->Data();
1413 node
= node
->Next();
1414 p
= (wxPoint
*)node
->Data();
1418 cx1
= (double)((x1
+ x2
) / 2);
1419 cy1
= (double)((y1
+ y2
) / 2);
1420 cx2
= (double)((cx1
+ x2
) / 2);
1421 cy2
= (double)((cy1
+ y2
) / 2);
1423 wx_spline_add_point(x1
, y1
);
1425 while ((node
= node
->Next()) != NULL
)
1427 p
= (wxPoint
*)node
->Data();
1432 cx4
= (double)(x1
+ x2
) / 2;
1433 cy4
= (double)(y1
+ y2
) / 2;
1434 cx3
= (double)(x1
+ cx4
) / 2;
1435 cy3
= (double)(y1
+ cy4
) / 2;
1437 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1441 cx2
= (double)(cx1
+ x2
) / 2;
1442 cy2
= (double)(cy1
+ y2
) / 2;
1445 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1446 wx_spline_add_point(x2
, y2
);
1448 wx_spline_draw_point_array(dc
);
1452 /********************* CURVES FOR SPLINES *****************************
1454 The following spline drawing routine is from
1456 "An Algorithm for High-Speed Curve Generation"
1457 by George Merrill Chaikin,
1458 Computer Graphics and Image Processing, 3, Academic Press,
1463 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1464 Computer Graphics and Image Processing, 4, Academic Press,
1467 ***********************************************************************/
1469 #define half(z1, z2) ((z1+z2)/2.0)
1472 /* iterative version */
1474 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1477 register double xmid
, ymid
;
1478 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1481 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1483 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1484 xmid
= (double)half(x2
, x3
);
1485 ymid
= (double)half(y2
, y3
);
1486 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1487 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1488 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1489 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1491 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1492 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1493 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1494 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1500 /* utilities used by spline drawing routines */
1503 typedef struct wx_spline_stack_struct
{
1504 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1508 #define SPLINE_STACK_DEPTH 20
1509 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1510 static Stack
*wx_stack_top
;
1511 static int wx_stack_count
;
1513 void wx_clear_stack()
1515 wx_stack_top
= wx_spline_stack
;
1519 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1521 wx_stack_top
->x1
= x1
;
1522 wx_stack_top
->y1
= y1
;
1523 wx_stack_top
->x2
= x2
;
1524 wx_stack_top
->y2
= y2
;
1525 wx_stack_top
->x3
= x3
;
1526 wx_stack_top
->y3
= y3
;
1527 wx_stack_top
->x4
= x4
;
1528 wx_stack_top
->y4
= y4
;
1533 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1534 double *x3
, double *y3
, double *x4
, double *y4
)
1536 if (wx_stack_count
== 0)
1540 *x1
= wx_stack_top
->x1
;
1541 *y1
= wx_stack_top
->y1
;
1542 *x2
= wx_stack_top
->x2
;
1543 *y2
= wx_stack_top
->y2
;
1544 *x3
= wx_stack_top
->x3
;
1545 *y3
= wx_stack_top
->y3
;
1546 *x4
= wx_stack_top
->x4
;
1547 *y4
= wx_stack_top
->y4
;
1551 static bool wx_spline_add_point(double x
, double y
)
1553 wxPoint
*point
= new wxPoint
;
1556 wx_spline_point_list
.Append((wxObject
*)point
);
1560 static void wx_spline_draw_point_array(wxDC
*dc
)
1562 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1563 wxNode
*node
= wx_spline_point_list
.First();
1566 wxPoint
*point
= (wxPoint
*)node
->Data();
1569 node
= wx_spline_point_list
.First();
1573 wxSpline::wxSpline(wxList
*list
)
1578 wxSpline::~wxSpline()
1582 void wxSpline::DeletePoints()
1584 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1586 wxPoint
*point
= (wxPoint
*)node
->Data();
1594 #endif // wxUSE_SPLINES