1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dc.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/dialog.h"
31 #include "wx/dcprint.h"
32 #include "wx/msw/private.h"
38 #if wxUSE_COMMON_DIALOGS
58 #if !USE_SHARED_LIBRARY
59 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
62 // Declarations local to this file
64 #define YSCALE(y) (yorigin - (y))
66 // #define wx_round(a) (int)((a)+.5)
68 // Default constructor
71 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
81 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
86 m_logicalScaleX
= 1.0;
87 m_logicalScaleY
= 1.0;
94 m_mappingMode
= MM_TEXT
;
99 m_windowExtX
= VIEWPORT_EXTENT
;
100 m_windowExtY
= VIEWPORT_EXTENT
;
101 m_logicalFunction
= -1;
103 m_backgroundBrush
= *wxWHITE_BRUSH
;
105 m_textForegroundColour
= *wxBLACK
;
106 m_textBackgroundColour
= *wxWHITE
;
108 m_colour
= wxColourDisplay();
117 SelectOldObjects(m_hDC
);
119 if ( m_canvas
== NULL
)
120 ::DeleteDC((HDC
)m_hDC
);
122 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
128 // This will select current objects out of the DC,
129 // which is what you have to do before deleting the
131 void wxDC::SelectOldObjects(WXHDC dc
)
134 wxDebugMsg("wxDC::SelectOldObjects %X\n", this);
141 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HBITMAP %X\n", m_oldBitmap
);
143 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
144 if (m_selectedBitmap
.Ok())
146 m_selectedBitmap
.SetSelectedInto(NULL
);
153 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HPEN %X\n", m_oldPen
);
155 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
161 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HBRUSH %X\n", m_oldBrush
);
163 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
169 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HFONT %X\n", m_oldFont
);
171 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
177 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HPALETTE %X\n", m_oldPalette
);
179 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
182 wxDebugMsg("wxDC::SelectOldObjects: Done.\n");
187 m_brush
= wxNullBrush
;
189 m_palette
= wxNullPalette
;
191 m_backgroundBrush
= wxNullBrush
;
192 m_selectedBitmap
= wxNullBitmap
;
195 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
200 m_clipX2
= (int)(cx
+ cw
);
201 m_clipY2
= (int)(cy
+ ch
);
203 DoClipping((WXHDC
) m_hDC
);
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(void)
217 if (m_clipping
&& m_hDC
)
219 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
221 wxDebugMsg("wxDC::DestroyClippingRegion: Selecting HRGN %X\n", rgn
);
223 SelectClipRgn((HDC
) m_hDC
, rgn
);
225 wxDebugMsg("wxDC::DestroyClippingRegion: Deleting HRGN %X\n", rgn
);
232 bool wxDC::CanDrawBitmap(void) const
237 bool wxDC::CanGetTextExtent(void) const
239 // What sort of display is it?
240 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
244 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
251 void wxDC::SetPalette(const wxPalette
& palette
)
253 // Set the old object temporarily, in case the assignment deletes an object
254 // that's not yet selected out.
257 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
261 m_palette
= m_palette
;
265 // Setting a NULL colourmap is a way of restoring
266 // the original colourmap
269 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
271 wxDebugMsg("wxDC::SetPalette: set old palette %X\n", m_oldPalette
);
279 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
281 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
283 m_oldPalette
= (WXHPALETTE
) oldPal
;
286 wxDebugMsg("wxDC::SetPalette %X: selected palette %X\n", this, m_palette
.GetHPALETTE());
288 wxDebugMsg("wxDC::SetPalette: oldPal was palette %X\n", oldPal
);
290 wxDebugMsg("wxDC::SetPalette: m_oldPalette is palette %X\n", m_oldPalette
);
292 ::RealizePalette((HDC
) m_hDC
);
296 void wxDC::Clear(void)
300 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
301 else if (m_selectedBitmap
.Ok())
303 rect
.left
= 0; rect
.top
= 0;
304 rect
.right
= m_selectedBitmap
.GetWidth();
305 rect
.bottom
= m_selectedBitmap
.GetHeight();
307 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
309 DWORD colour
= GetBkColor((HDC
) m_hDC
);
310 HBRUSH brush
= CreateSolidBrush(colour
);
311 FillRect((HDC
) m_hDC
, &rect
, brush
);
314 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
315 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
316 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
317 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
318 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
321 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
323 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
325 style
==wxFLOOD_SURFACE
?
326 FLOODFILLSURFACE
:FLOODFILLBORDER
329 CalcBoundingBox(x
, y
);
332 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
334 // added by steve 29.12.94 (copied from DrawPoint)
335 // returns TRUE for pixels in the color of the current pen
336 // and FALSE for all other pixels colors
337 // if col is non-NULL return the color of the pixel
339 // get the color of the pixel
340 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
341 // get the color of the pen
342 COLORREF pencolor
= 0x00ffffff;
345 pencolor
= m_pen
.GetColour().GetPixel() ;
348 // return the color of the pixel
350 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
352 // check, if color of the pixels is the same as the color
353 // of the current pen
354 return(pixelcolor
==pencolor
);
357 void wxDC::CrossHair(long x
, long y
)
359 // We suppose that our screen is 2000x2000 max.
365 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
366 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
368 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
369 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
371 CalcBoundingBox(x1
, y1
);
372 CalcBoundingBox(x2
, y2
);
375 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
377 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
378 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
380 /* MATTHEW: [6] New normalization */
381 #if WX_STANDARD_GRAPHICS
382 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
385 CalcBoundingBox(x1
, y1
);
386 CalcBoundingBox(x2
, y2
);
389 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
393 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
394 if (x1
==x2
&& x2
==y2
)
396 DrawEllipse(xc
,yc
,(double)(radius
*2.0),(double)(radius
*2)) ;
400 long xx1
= XLOG2DEV(x1
) ;
401 long yy1
= YLOG2DEV(y1
) ;
402 long xx2
= XLOG2DEV(x2
) ;
403 long yy2
= YLOG2DEV(y2
) ;
404 long xxc
= XLOG2DEV(xc
) ;
405 long yyc
= YLOG2DEV(yc
) ;
406 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
408 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
409 long xxx1
= (long) (xxc
-ray
);
410 long yyy1
= (long) (yyc
-ray
);
411 long xxx2
= (long) (xxc
+ray
);
412 long yyy2
= (long) (yyc
+ray
);
413 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
415 // Have to add 1 to bottom-right corner of rectangle
416 // to make semi-circles look right (crooked line otherwise).
417 // Unfortunately this is not a reliable method, depends
418 // on the size of shape.
419 // TODO: figure out why this happens!
420 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
424 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
427 CalcBoundingBox((xc
-radius
), (yc
-radius
));
428 CalcBoundingBox((xc
+radius
), (yc
+radius
));
431 void wxDC::DrawPoint(long x
, long y
)
433 COLORREF color
= 0x00ffffff;
436 color
= m_pen
.GetColour().GetPixel() ;
439 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
441 CalcBoundingBox(x
, y
);
444 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
446 // Do things less efficiently if we have offsets
447 if (xoffset
!= 0 || yoffset
!= 0)
449 POINT
*cpoints
= new POINT
[n
];
451 for (i
= 0; i
< n
; i
++)
453 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
454 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
456 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
458 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
459 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
460 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
466 for (i
= 0; i
< n
; i
++)
467 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
469 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
470 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
471 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
475 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
477 // Do things less efficiently if we have offsets
478 if (xoffset
!= 0 || yoffset
!= 0)
480 POINT
*cpoints
= new POINT
[n
];
482 for (i
= 0; i
< n
; i
++)
484 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
485 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
487 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
489 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
495 for (i
= 0; i
< n
; i
++)
496 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
498 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
502 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
505 long y2
= y
+ height
;
507 /* MATTHEW: [6] new normalization */
508 #if WX_STANDARD_GRAPHICS
509 bool do_brush
, do_pen
;
511 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
512 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
515 HPEN orig_pen
= NULL
;
517 if (do_pen
|| !m_pen
.Ok())
518 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
520 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
521 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
523 if (do_pen
|| !m_pen
.Ok())
524 ::SelectObject((HDC
) m_hDC
, orig_pen
);
527 HBRUSH orig_brush
= NULL
;
529 if (do_brush
|| !m_brush
.Ok())
530 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
532 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
533 XLOG2DEV(x2
), YLOG2DEV(y2
));
535 if (do_brush
|| !m_brush
.Ok())
536 ::SelectObject((HDC
) m_hDC
, orig_brush
);
539 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
542 CalcBoundingBox(x
, y
);
543 CalcBoundingBox(x2
, y2
);
546 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
548 // Now, a negative radius value is interpreted to mean
549 // 'the proportion of the smallest X or Y dimension'
553 double smallest
= 0.0;
558 radius
= (- radius
* smallest
);
562 long y2
= (y
+height
);
564 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
565 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
567 CalcBoundingBox(x
, y
);
568 CalcBoundingBox(x2
, y2
);
571 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
574 long y2
= (y
+height
);
576 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
578 CalcBoundingBox(x
, y
);
579 CalcBoundingBox(x2
, y2
);
582 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
583 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
588 const double deg2rad
= 3.14159265359 / 180.0;
589 int rx1
= XLOG2DEV(x
+w
/2);
590 int ry1
= YLOG2DEV(y
+h
/2);
593 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
594 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
595 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
596 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
598 // draw pie with NULL_PEN first and then outline otherwise a line is
599 // drawn from the start and end points to the centre
600 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
603 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
608 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
609 rx1
, ry1
-1, rx2
, ry2
-1);
611 ::SelectObject((HDC
) m_hDC
, orig_pen
);
612 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
615 CalcBoundingBox(x
, y
);
616 CalcBoundingBox(x2
, y2
);
619 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
621 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
622 CalcBoundingBox(x
, y
);
623 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
626 void wxDC::SetFont(const wxFont
& the_font
)
628 // Set the old object temporarily, in case the assignment deletes an object
629 // that's not yet selected out.
632 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
641 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
645 if (m_font
.Ok() && m_font
.GetResourceHandle())
648 wxDebugMsg("wxDC::SetFont: Selecting HFONT %X\n", m_font
.GetResourceHandle());
650 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
653 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
656 m_oldFont
= (WXHFONT
) f
;
660 void wxDC::SetPen(const wxPen
& pen
)
662 // Set the old object temporarily, in case the assignment deletes an object
663 // that's not yet selected out.
666 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
675 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
681 if (m_pen
.GetResourceHandle())
683 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
685 m_oldPen
= (WXHPEN
) p
;
690 void wxDC::SetBrush(const wxBrush
& brush
)
692 // Set the old object temporarily, in case the assignment deletes an object
693 // that's not yet selected out.
696 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
705 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
711 if (m_brush
.GetResourceHandle())
714 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
716 m_oldBrush
= (WXHBRUSH
) b
;
721 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
723 // Should be unnecessary: SetFont should have done this already.
725 if (m_font
.Ok() && m_font
.GetResourceHandle())
728 wxDebugMsg("wxDC::DrawText: Selecting HFONT %X\n", m_font
.GetResourceHandle());
730 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
732 m_oldFont
= (WXHFONT
) f
;
736 if (m_textForegroundColour
.Ok())
737 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
739 DWORD old_background
;
740 if (m_textBackgroundColour
.Ok())
742 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
745 if (m_backgroundMode
== wxTRANSPARENT
)
746 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
748 SetBkMode((HDC
) m_hDC
, OPAQUE
);
750 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
752 if (m_textBackgroundColour
.Ok())
753 (void)SetBkColor((HDC
) m_hDC
, old_background
);
755 CalcBoundingBox(x
, y
);
758 GetTextExtent(text
, &w
, &h
);
759 CalcBoundingBox((x
+ w
), (y
+ h
));
762 void wxDC::SetBackground(const wxBrush
& brush
)
764 m_backgroundBrush
= brush
;
766 if (!m_backgroundBrush
.Ok())
771 bool customColours
= TRUE
;
772 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
773 // change background colours from the control-panel specified colours.
774 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
775 customColours
= FALSE
;
779 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
781 m_canvas
->m_backgroundTransparent
= TRUE
;
785 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
786 m_canvas
->m_backgroundTransparent
= FALSE
;
790 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
792 (void)SetBkColor((HDC
) m_hDC
, new_color
);
796 void wxDC::SetBackgroundMode(int mode
)
798 m_backgroundMode
= mode
;
800 if (m_backgroundMode
== wxTRANSPARENT
)
801 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
803 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
806 void wxDC::SetLogicalFunction(int function
)
808 m_logicalFunction
= function
;
810 SetRop((WXHDC
) m_hDC
);
813 void wxDC::SetRop(WXHDC dc
)
815 if (!dc
|| m_logicalFunction
< 0)
819 // These may be wrong
820 switch (m_logicalFunction
)
822 // case wxXOR: c_rop = R2_XORPEN; break;
823 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
824 case wxINVERT
: c_rop
= R2_NOT
; break;
825 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
826 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
827 case wxCLEAR
: c_rop
= R2_WHITE
; break;
828 case wxSET
: c_rop
= R2_BLACK
; break;
829 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
830 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
831 case wxAND
: c_rop
= R2_MASKPEN
; break;
832 case wxOR
: c_rop
= R2_MERGEPEN
; break;
833 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
838 c_rop
= R2_COPYPEN
; break;
840 SetROP2((HDC
) dc
, c_rop
);
843 bool wxDC::StartDoc(const wxString
& message
)
845 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
849 docinfo
.cbSize
= sizeof(DOCINFO
);
850 docinfo
.lpszDocName
= (const char *)message
;
852 if (m_filename
.IsEmpty())
853 docinfo
.lpszOutput
= NULL
;
855 docinfo
.lpszOutput
= (const char *)m_filename
;
857 #if defined(__WIN95__)
858 docinfo
.lpszDatatype
= NULL
;
867 ::StartDoc((HDC
) m_hDC
, &docinfo
);
870 ::StartDocW((HDC
) m_hDC
, &docinfo
);
872 ::StartDocA((HDC
) m_hDC
, &docinfo
);
878 DWORD lastError
= GetLastError();
879 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
884 void wxDC::EndDoc(void)
886 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
888 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
891 void wxDC::StartPage(void)
893 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
896 ::StartPage((HDC
) m_hDC
);
899 void wxDC::EndPage(void)
901 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
904 ::EndPage((HDC
) m_hDC
);
907 long wxDC::GetCharHeight(void) const
909 TEXTMETRIC lpTextMetric
;
911 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
913 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
916 long wxDC::GetCharWidth(void) const
918 TEXTMETRIC lpTextMetric
;
920 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
922 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
925 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
926 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
928 wxFont
*fontToUse
= (wxFont
*) theFont
;
930 fontToUse
= (wxFont
*) &m_font
;
935 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
936 GetTextMetrics((HDC
) m_hDC
, &tm
);
938 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
939 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
940 if (descent
) *descent
= tm
.tmDescent
;
941 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
944 void wxDC::SetMapMode(int mode
)
946 m_mappingMode
= mode
;
949 int pixel_height
= 0;
953 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
954 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
955 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
956 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
958 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
963 double mm2pixelsX
= pixel_width
/mm_width
;
964 double mm2pixelsY
= pixel_height
/mm_height
;
970 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
971 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
976 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
977 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
982 m_logicalScaleX
= mm2pixelsX
;
983 m_logicalScaleY
= mm2pixelsY
;
988 m_logicalScaleX
= (mm2pixelsX
/10.0);
989 m_logicalScaleY
= (mm2pixelsY
/10.0);
995 m_logicalScaleX
= 1.0;
996 m_logicalScaleY
= 1.0;
1001 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1002 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1004 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1005 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1006 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1007 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1008 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1009 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1012 void wxDC::SetUserScale(double x
, double y
)
1017 SetMapMode(m_mappingMode
);
1020 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1022 m_signX
= xLeftRight
? 1 : -1;
1023 m_signY
= yBottomUp
? -1 : 1;
1025 SetMapMode(m_mappingMode
);
1028 void wxDC::SetSystemScale(double x
, double y
)
1033 SetMapMode(m_mappingMode
);
1036 void wxDC::SetLogicalOrigin(long x
, long y
)
1038 m_logicalOriginX
= x
;
1039 m_logicalOriginY
= y
;
1041 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1044 void wxDC::SetDeviceOrigin(long x
, long y
)
1046 m_deviceOriginX
= x
;
1047 m_deviceOriginY
= y
;
1049 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1052 long wxDC::DeviceToLogicalX(long x
) const
1054 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1057 long wxDC::DeviceToLogicalXRel(long x
) const
1059 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1062 long wxDC::DeviceToLogicalY(long y
) const
1064 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1067 long wxDC::DeviceToLogicalYRel(long y
) const
1069 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1072 long wxDC::LogicalToDeviceX(long x
) const
1074 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1077 long wxDC::LogicalToDeviceXRel(long x
) const
1079 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1082 long wxDC::LogicalToDeviceY(long y
) const
1084 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1087 long wxDC::LogicalToDeviceYRel(long y
) const
1089 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1092 // This group of functions may not do any conversion
1093 // if m_scaleGDI is TRUE, since the HDC does the
1094 // conversion automatically.
1096 long wxDC::ImplDeviceToLogicalX(long x
) const
1098 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1102 long wxDC::ImplDeviceToLogicalY(long y
) const
1104 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1108 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1110 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1114 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1116 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1120 long wxDC::ImplLogicalToDeviceX(long x
) const
1122 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1126 long wxDC::ImplLogicalToDeviceY(long y
) const
1128 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1132 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1134 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1138 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1140 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1144 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1145 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1147 long xdest1
= xdest
;
1148 long ydest1
= ydest
;
1152 // Chris Breeze 18/5/98: use text foreground/background colours
1153 // when blitting from 1-bit bitmaps
1154 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1155 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1156 if (m_textForegroundColour
.Ok())
1158 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1160 if (m_textBackgroundColour
.Ok())
1162 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1165 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1166 rop
== wxCLEAR
? WHITENESS
:
1167 rop
== wxSET
? BLACKNESS
:
1168 rop
== wxINVERT
? DSTINVERT
:
1169 rop
== wxAND
? MERGECOPY
:
1170 rop
== wxOR
? MERGEPAINT
:
1171 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1172 rop
== wxXOR
? SRCINVERT
:
1173 rop
== wxOR_REVERSE
? MERGEPAINT
:
1174 rop
== wxAND_REVERSE
? SRCERASE
:
1175 rop
== wxSRC_OR
? SRCPAINT
:
1176 rop
== wxSRC_AND
? SRCAND
:
1180 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1184 // Not implemented under Win95 (or maybe a specific device?)
1185 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1186 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1196 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1197 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1198 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1199 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1200 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1201 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1202 ::SelectObject(dc_mask
, 0);
1203 ::DeleteDC(dc_mask
);
1205 // New code from Chris Breeze, 15/7/98
1206 // Blit bitmap with mask
1208 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1210 // If we are printing source colours are screen colours
1211 // not printer colours and so we need copy the bitmap
1214 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1215 HDC dc_src
= (HDC
) source
->m_hDC
;
1217 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1218 for (int x
= 0; x
< width
; x
++)
1220 for (int y
= 0; y
< height
; y
++)
1222 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1225 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1226 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1227 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1228 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1229 ::DeleteObject(brush
);
1233 ::SelectObject(dc_mask
, 0);
1234 ::DeleteDC(dc_mask
);
1238 // create a temp buffer bitmap and DCs to access it and the mask
1239 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1240 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1241 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1242 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1243 ::SelectObject(dc_buffer
, buffer_bmap
);
1245 // copy dest to buffer
1246 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1247 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1249 // copy src to buffer using selected raster op
1250 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1251 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1253 // set masked area in buffer to BLACK (pixel value 0)
1254 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1255 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1256 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1257 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1259 // set unmasked area in dest to BLACK
1260 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1261 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1262 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1263 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1264 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1265 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1267 // OR buffer to dest
1268 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1269 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1271 // tidy up temporary DCs and bitmap
1272 ::SelectObject(dc_mask
, 0);
1273 ::DeleteDC(dc_mask
);
1274 ::SelectObject(dc_buffer
, 0);
1275 ::DeleteDC(dc_buffer
);
1276 ::DeleteObject(buffer_bmap
);
1282 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1284 // If we are printing source colours are screen colours
1285 // not printer colours and so we need copy the bitmap
1287 HDC dc_src
= (HDC
) source
->m_hDC
;
1289 for (int x
= 0; x
< width
; x
++)
1291 for (int y
= 0; y
< height
; y
++)
1293 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1294 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1295 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1296 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1297 ::DeleteObject(brush
);
1303 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1304 xsrc1
, ysrc1
, dwRop
) != 0);
1307 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1308 ::SetBkColor((HDC
)m_hDC
, old_background
);
1313 void wxDC::GetSize(int* width
, int* height
) const
1315 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1316 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1321 void wxDC::GetSizeMM(long *width
, long *height
) const
1323 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1324 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1329 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1331 int n
= list
->Number();
1332 wxPoint
*points
= new wxPoint
[n
];
1335 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1336 wxPoint
*point
= (wxPoint
*)node
->Data();
1337 points
[i
].x
= point
->x
;
1338 points
[i
++].y
= point
->y
;
1340 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1344 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1346 int n
= list
->Number();
1347 wxPoint
*points
= new wxPoint
[n
];
1350 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1351 wxPoint
*point
= (wxPoint
*)node
->Data();
1352 points
[i
].x
= point
->x
;
1353 points
[i
++].y
= point
->y
;
1355 DrawLines(n
, points
, xoffset
, yoffset
);
1359 void wxDC::SetTextForeground(const wxColour
& colour
)
1361 m_textForegroundColour
= colour
;
1364 void wxDC::SetTextBackground(const wxColour
& colour
)
1366 m_textBackgroundColour
= colour
;
1369 // For use by wxWindows only, unless custom units are required.
1370 void wxDC::SetLogicalScale(double x
, double y
)
1372 m_logicalScaleX
= x
;
1373 m_logicalScaleY
= y
;
1376 void wxDC::CalcBoundingBox(long x
, long y
)
1378 if (x
< m_minX
) m_minX
= x
;
1379 if (y
< m_minY
) m_minY
= y
;
1380 if (x
> m_maxX
) m_maxX
= x
;
1381 if (y
> m_maxY
) m_maxY
= y
;
1384 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1390 *w
= (m_clipX2
- m_clipX1
) ;
1391 *h
= (m_clipY2
- m_clipY1
) ;
1394 *x
= *y
= *w
= *h
= 0 ;
1397 #if WXWIN_COMPATIBILITY
1398 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1399 float *descent
, float *externalLeading
,
1400 wxFont
*theFont
, bool use16bit
) const
1402 long x1
, y1
, descent1
, externalLeading1
;
1403 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1406 *descent
= descent1
;
1407 if (externalLeading
)
1408 *externalLeading
= externalLeading1
;
1412 int wxDC::GetDepth(void) const
1414 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1419 // Make a 3-point spline
1420 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1422 wxList
*point_list
= new wxList
;
1424 wxPoint
*point1
= new wxPoint
;
1425 point1
->x
= x1
; point1
->y
= y1
;
1426 point_list
->Append((wxObject
*)point1
);
1428 wxPoint
*point2
= new wxPoint
;
1429 point2
->x
= x2
; point2
->y
= y2
;
1430 point_list
->Append((wxObject
*)point2
);
1432 wxPoint
*point3
= new wxPoint
;
1433 point3
->x
= x3
; point3
->y
= y3
;
1434 point_list
->Append((wxObject
*)point3
);
1436 DrawSpline(point_list
);
1438 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1439 wxPoint
*p
= (wxPoint
*)node
->Data();
1445 ////#define wx_round(a) (int)((a)+.5)
1446 //#define wx_round(a) (a)
1448 class wxSpline
: public wxObject
1454 wxSpline(wxList
*list
);
1455 void DeletePoints(void);
1457 // Doesn't delete points
1461 void wxDC::DrawSpline(int n
, wxPoint points
[])
1465 for (i
=0; i
< n
; i
++)
1466 list
.Append((wxObject
*)&points
[i
]);
1467 DrawSpline((wxList
*)&list
);
1470 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1472 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1473 double a3
, double b3
, double a4
, double b4
);
1474 void wx_clear_stack(void);
1475 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1476 double *y3
, double *x4
, double *y4
);
1477 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1478 double x4
, double y4
);
1479 static bool wx_spline_add_point(double x
, double y
);
1480 static void wx_spline_draw_point_array(wxDC
*dc
);
1481 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1483 void wxDC::DrawSpline(wxList
*list
)
1485 wxSpline
spline(list
);
1487 wx_draw_open_spline(this, &spline
);
1491 wxList wx_spline_point_list
;
1493 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1496 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1497 double x1
, y1
, x2
, y2
;
1499 wxNode
*node
= spline
->points
->First();
1500 p
= (wxPoint
*)node
->Data();
1505 node
= node
->Next();
1506 p
= (wxPoint
*)node
->Data();
1510 cx1
= (double)((x1
+ x2
) / 2);
1511 cy1
= (double)((y1
+ y2
) / 2);
1512 cx2
= (double)((cx1
+ x2
) / 2);
1513 cy2
= (double)((cy1
+ y2
) / 2);
1515 wx_spline_add_point(x1
, y1
);
1517 while ((node
= node
->Next()) != NULL
)
1519 p
= (wxPoint
*)node
->Data();
1524 cx4
= (double)(x1
+ x2
) / 2;
1525 cy4
= (double)(y1
+ y2
) / 2;
1526 cx3
= (double)(x1
+ cx4
) / 2;
1527 cy3
= (double)(y1
+ cy4
) / 2;
1529 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1533 cx2
= (double)(cx1
+ x2
) / 2;
1534 cy2
= (double)(cy1
+ y2
) / 2;
1537 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1538 wx_spline_add_point(x2
, y2
);
1540 wx_spline_draw_point_array(dc
);
1544 /********************* CURVES FOR SPLINES *****************************
1546 The following spline drawing routine is from
1548 "An Algorithm for High-Speed Curve Generation"
1549 by George Merrill Chaikin,
1550 Computer Graphics and Image Processing, 3, Academic Press,
1555 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1556 Computer Graphics and Image Processing, 4, Academic Press,
1559 ***********************************************************************/
1561 #define half(z1, z2) ((z1+z2)/2.0)
1564 /* iterative version */
1566 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1569 register double xmid
, ymid
;
1570 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1573 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1575 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1576 xmid
= (double)half(x2
, x3
);
1577 ymid
= (double)half(y2
, y3
);
1578 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1579 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1580 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1581 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1583 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1584 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1585 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1586 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1592 /* utilities used by spline drawing routines */
1595 typedef struct wx_spline_stack_struct
{
1596 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1600 #define SPLINE_STACK_DEPTH 20
1601 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1602 static Stack
*wx_stack_top
;
1603 static int wx_stack_count
;
1605 void wx_clear_stack(void)
1607 wx_stack_top
= wx_spline_stack
;
1611 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1613 wx_stack_top
->x1
= x1
;
1614 wx_stack_top
->y1
= y1
;
1615 wx_stack_top
->x2
= x2
;
1616 wx_stack_top
->y2
= y2
;
1617 wx_stack_top
->x3
= x3
;
1618 wx_stack_top
->y3
= y3
;
1619 wx_stack_top
->x4
= x4
;
1620 wx_stack_top
->y4
= y4
;
1625 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1626 double *x3
, double *y3
, double *x4
, double *y4
)
1628 if (wx_stack_count
== 0)
1632 *x1
= wx_stack_top
->x1
;
1633 *y1
= wx_stack_top
->y1
;
1634 *x2
= wx_stack_top
->x2
;
1635 *y2
= wx_stack_top
->y2
;
1636 *x3
= wx_stack_top
->x3
;
1637 *y3
= wx_stack_top
->y3
;
1638 *x4
= wx_stack_top
->x4
;
1639 *y4
= wx_stack_top
->y4
;
1643 static bool wx_spline_add_point(double x
, double y
)
1645 wxPoint
*point
= new wxPoint
;
1648 wx_spline_point_list
.Append((wxObject
*)point
);
1652 static void wx_spline_draw_point_array(wxDC
*dc
)
1654 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1655 wxNode
*node
= wx_spline_point_list
.First();
1658 wxPoint
*point
= (wxPoint
*)node
->Data();
1661 node
= wx_spline_point_list
.First();
1665 wxSpline::wxSpline(wxList
*list
)
1670 wxSpline::~wxSpline(void)
1674 void wxSpline::DeletePoints(void)
1676 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1678 wxPoint
*point
= (wxPoint
*)node
->Data();
1686 #endif // wxUSE_SPLINES