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"
37 #if wxUSE_COMMON_DIALOGS
57 #if !USE_SHARED_LIBRARY
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
61 // Declarations local to this file
63 #define YSCALE(y) (yorigin - (y))
65 // #define wx_round(a) (int)((a)+.5)
67 // Default constructor
70 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
80 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
85 m_logicalScaleX
= 1.0;
86 m_logicalScaleY
= 1.0;
93 m_mappingMode
= MM_TEXT
;
98 m_windowExtX
= VIEWPORT_EXTENT
;
99 m_windowExtY
= VIEWPORT_EXTENT
;
100 m_logicalFunction
= -1;
102 m_backgroundBrush
= *wxWHITE_BRUSH
;
104 m_textForegroundColour
= *wxBLACK
;
105 m_textBackgroundColour
= *wxWHITE
;
107 m_colour
= wxColourDisplay();
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC((HDC
)m_hDC
);
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
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 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
178 m_clipX2
= (int)(cx
+ cw
);
179 m_clipY2
= (int)(cy
+ ch
);
181 DoClipping((WXHDC
) m_hDC
);
184 void wxDC::SetClippingRegion(const wxRegion
& region
)
186 if (!region
.GetHRGN())
189 wxRect box
= region
.GetBox();
194 m_clipX2
= box
.x
+ box
.width
;
195 m_clipY2
= box
.y
+ box
.height
;
198 SelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN());
200 ExtSelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN(), RGN_AND
);
204 void wxDC::DoClipping(WXHDC dc
)
206 if (m_clipping
&& dc
)
208 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
209 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
213 void wxDC::DestroyClippingRegion(void)
215 if (m_clipping
&& m_hDC
)
217 // TODO: this should restore the previous clipping region,
218 // so that OnPaint processing works correctly, and the update clipping region
219 // doesn't get destroyed after the first DestroyClippingRegion.
220 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
221 SelectClipRgn((HDC
) m_hDC
, rgn
);
227 bool wxDC::CanDrawBitmap(void) const
232 bool wxDC::CanGetTextExtent(void) const
234 // What sort of display is it?
235 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
239 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
246 void wxDC::SetPalette(const wxPalette
& palette
)
248 // Set the old object temporarily, in case the assignment deletes an object
249 // that's not yet selected out.
252 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
256 m_palette
= m_palette
;
260 // Setting a NULL colourmap is a way of restoring
261 // the original colourmap
264 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
271 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
273 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
275 m_oldPalette
= (WXHPALETTE
) oldPal
;
277 ::RealizePalette((HDC
) m_hDC
);
281 void wxDC::Clear(void)
285 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
286 else if (m_selectedBitmap
.Ok())
288 rect
.left
= 0; rect
.top
= 0;
289 rect
.right
= m_selectedBitmap
.GetWidth();
290 rect
.bottom
= m_selectedBitmap
.GetHeight();
292 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
294 DWORD colour
= GetBkColor((HDC
) m_hDC
);
295 HBRUSH brush
= CreateSolidBrush(colour
);
296 FillRect((HDC
) m_hDC
, &rect
, brush
);
299 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
300 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
301 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
302 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
303 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
306 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
308 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
310 style
==wxFLOOD_SURFACE
?
311 FLOODFILLSURFACE
:FLOODFILLBORDER
314 CalcBoundingBox(x
, y
);
317 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
319 // added by steve 29.12.94 (copied from DrawPoint)
320 // returns TRUE for pixels in the color of the current pen
321 // and FALSE for all other pixels colors
322 // if col is non-NULL return the color of the pixel
324 // get the color of the pixel
325 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
326 // get the color of the pen
327 COLORREF pencolor
= 0x00ffffff;
330 pencolor
= m_pen
.GetColour().GetPixel() ;
333 // return the color of the pixel
335 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
337 // check, if color of the pixels is the same as the color
338 // of the current pen
339 return(pixelcolor
==pencolor
);
342 void wxDC::CrossHair(long x
, long y
)
344 // We suppose that our screen is 2000x2000 max.
350 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
351 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
353 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
354 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
356 CalcBoundingBox(x1
, y1
);
357 CalcBoundingBox(x2
, y2
);
360 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
362 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
363 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
365 /* MATTHEW: [6] New normalization */
366 #if WX_STANDARD_GRAPHICS
367 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
370 CalcBoundingBox(x1
, y1
);
371 CalcBoundingBox(x2
, y2
);
374 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
378 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
379 if (x1
==x2
&& x2
==y2
)
381 DrawEllipse(xc
,yc
,(double)(radius
*2.0),(double)(radius
*2)) ;
385 long xx1
= XLOG2DEV(x1
) ;
386 long yy1
= YLOG2DEV(y1
) ;
387 long xx2
= XLOG2DEV(x2
) ;
388 long yy2
= YLOG2DEV(y2
) ;
389 long xxc
= XLOG2DEV(xc
) ;
390 long yyc
= YLOG2DEV(yc
) ;
391 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
393 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
394 long xxx1
= (long) (xxc
-ray
);
395 long yyy1
= (long) (yyc
-ray
);
396 long xxx2
= (long) (xxc
+ray
);
397 long yyy2
= (long) (yyc
+ray
);
398 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
400 // Have to add 1 to bottom-right corner of rectangle
401 // to make semi-circles look right (crooked line otherwise).
402 // Unfortunately this is not a reliable method, depends
403 // on the size of shape.
404 // TODO: figure out why this happens!
405 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
409 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
412 CalcBoundingBox((xc
-radius
), (yc
-radius
));
413 CalcBoundingBox((xc
+radius
), (yc
+radius
));
416 void wxDC::DrawPoint(long x
, long y
)
418 COLORREF color
= 0x00ffffff;
421 color
= m_pen
.GetColour().GetPixel() ;
424 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
426 CalcBoundingBox(x
, y
);
429 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
431 // Do things less efficiently if we have offsets
432 if (xoffset
!= 0 || yoffset
!= 0)
434 POINT
*cpoints
= new POINT
[n
];
436 for (i
= 0; i
< n
; i
++)
438 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
439 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
441 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
443 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
444 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
445 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
451 for (i
= 0; i
< n
; i
++)
452 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
454 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
455 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
456 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
460 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
462 // Do things less efficiently if we have offsets
463 if (xoffset
!= 0 || yoffset
!= 0)
465 POINT
*cpoints
= new POINT
[n
];
467 for (i
= 0; i
< n
; i
++)
469 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
470 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
472 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
474 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
480 for (i
= 0; i
< n
; i
++)
481 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
483 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
487 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
490 long y2
= y
+ height
;
492 /* MATTHEW: [6] new normalization */
493 #if WX_STANDARD_GRAPHICS
494 bool do_brush
, do_pen
;
496 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
497 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
500 HPEN orig_pen
= NULL
;
502 if (do_pen
|| !m_pen
.Ok())
503 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
505 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
506 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
508 if (do_pen
|| !m_pen
.Ok())
509 ::SelectObject((HDC
) m_hDC
, orig_pen
);
512 HBRUSH orig_brush
= NULL
;
514 if (do_brush
|| !m_brush
.Ok())
515 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
517 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
518 XLOG2DEV(x2
), YLOG2DEV(y2
));
520 if (do_brush
|| !m_brush
.Ok())
521 ::SelectObject((HDC
) m_hDC
, orig_brush
);
524 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
527 CalcBoundingBox(x
, y
);
528 CalcBoundingBox(x2
, y2
);
531 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
533 // Now, a negative radius value is interpreted to mean
534 // 'the proportion of the smallest X or Y dimension'
538 double smallest
= 0.0;
543 radius
= (- radius
* smallest
);
547 long y2
= (y
+height
);
549 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
550 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
552 CalcBoundingBox(x
, y
);
553 CalcBoundingBox(x2
, y2
);
556 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
559 long y2
= (y
+height
);
561 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
563 CalcBoundingBox(x
, y
);
564 CalcBoundingBox(x2
, y2
);
567 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
568 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
573 const double deg2rad
= 3.14159265359 / 180.0;
574 int rx1
= XLOG2DEV(x
+w
/2);
575 int ry1
= YLOG2DEV(y
+h
/2);
578 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
579 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
580 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
581 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
583 // draw pie with NULL_PEN first and then outline otherwise a line is
584 // drawn from the start and end points to the centre
585 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
588 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
593 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
594 rx1
, ry1
-1, rx2
, ry2
-1);
596 ::SelectObject((HDC
) m_hDC
, orig_pen
);
597 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
600 CalcBoundingBox(x
, y
);
601 CalcBoundingBox(x2
, y2
);
604 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
606 #if defined(__WIN32__)
607 ::DrawIconEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
608 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
610 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
613 CalcBoundingBox(x
, y
);
614 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
617 void wxDC::DrawBitmap( const wxBitmap
&bmp
, long x
, long y
, bool useMask
)
622 // If we're not drawing transparently, and not drawing to a printer,
623 // optimize this function to use Windows functions.
624 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
626 HDC cdc
= (HDC
)m_hDC
;
627 HDC memdc
= ::CreateCompatibleDC( cdc
);
628 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
629 ::SelectObject( memdc
, hbitmap
);
630 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
631 ::SelectObject( memdc
, 0 );
636 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
638 memDC
.SelectObject(bmp
);
640 /* Not sure if we need this. The mask should leave the
641 * masked areas as per the original background of this DC.
644 // There might be transparent areas, so make these
645 // the same colour as this DC
646 memDC.SetBackground(* GetBackground());
650 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
652 memDC
.SelectObject(wxNullBitmap
);
656 void wxDC::SetFont(const wxFont
& the_font
)
658 // Set the old object temporarily, in case the assignment deletes an object
659 // that's not yet selected out.
662 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
671 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
675 if (m_font
.Ok() && m_font
.GetResourceHandle())
677 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
680 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
683 m_oldFont
= (WXHFONT
) f
;
687 void wxDC::SetPen(const wxPen
& pen
)
689 // Set the old object temporarily, in case the assignment deletes an object
690 // that's not yet selected out.
693 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
702 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
708 if (m_pen
.GetResourceHandle())
710 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
712 m_oldPen
= (WXHPEN
) p
;
717 void wxDC::SetBrush(const wxBrush
& brush
)
719 // Set the old object temporarily, in case the assignment deletes an object
720 // that's not yet selected out.
723 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
732 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
738 if (m_brush
.GetResourceHandle())
741 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
743 m_oldBrush
= (WXHBRUSH
) b
;
748 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
750 // Should be unnecessary: SetFont should have done this already.
752 if (m_font
.Ok() && m_font
.GetResourceHandle())
754 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
756 m_oldFont
= (WXHFONT
) f
;
760 if (m_textForegroundColour
.Ok())
761 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
763 DWORD old_background
= 0;
764 if (m_textBackgroundColour
.Ok())
766 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
769 if (m_backgroundMode
== wxTRANSPARENT
)
770 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
772 SetBkMode((HDC
) m_hDC
, OPAQUE
);
774 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
776 if (m_textBackgroundColour
.Ok())
777 (void)SetBkColor((HDC
) m_hDC
, old_background
);
779 CalcBoundingBox(x
, y
);
782 GetTextExtent(text
, &w
, &h
);
783 CalcBoundingBox((x
+ w
), (y
+ h
));
786 void wxDC::SetBackground(const wxBrush
& brush
)
788 m_backgroundBrush
= brush
;
790 if (!m_backgroundBrush
.Ok())
795 bool customColours
= TRUE
;
796 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
797 // change background colours from the control-panel specified colours.
798 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
799 customColours
= FALSE
;
803 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
805 m_canvas
->m_backgroundTransparent
= TRUE
;
809 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
810 m_canvas
->m_backgroundTransparent
= FALSE
;
814 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
816 (void)SetBkColor((HDC
) m_hDC
, new_color
);
820 void wxDC::SetBackgroundMode(int mode
)
822 m_backgroundMode
= mode
;
824 if (m_backgroundMode
== wxTRANSPARENT
)
825 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
827 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
830 void wxDC::SetLogicalFunction(int function
)
832 m_logicalFunction
= function
;
834 SetRop((WXHDC
) m_hDC
);
837 void wxDC::SetRop(WXHDC dc
)
839 if (!dc
|| m_logicalFunction
< 0)
843 // These may be wrong
844 switch (m_logicalFunction
)
846 // case wxXOR: c_rop = R2_XORPEN; break;
847 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
848 case wxINVERT
: c_rop
= R2_NOT
; break;
849 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
850 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
851 case wxCLEAR
: c_rop
= R2_WHITE
; break;
852 case wxSET
: c_rop
= R2_BLACK
; break;
853 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
854 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
855 case wxAND
: c_rop
= R2_MASKPEN
; break;
856 case wxOR
: c_rop
= R2_MERGEPEN
; break;
857 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
862 c_rop
= R2_COPYPEN
; break;
864 SetROP2((HDC
) dc
, c_rop
);
867 bool wxDC::StartDoc(const wxString
& message
)
869 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
873 docinfo
.cbSize
= sizeof(DOCINFO
);
874 docinfo
.lpszDocName
= (const char *)message
;
876 if (m_filename
.IsEmpty())
877 docinfo
.lpszOutput
= NULL
;
879 docinfo
.lpszOutput
= (const char *)m_filename
;
881 #if defined(__WIN95__)
882 docinfo
.lpszDatatype
= NULL
;
891 ::StartDoc((HDC
) m_hDC
, &docinfo
);
894 ::StartDocW((HDC
) m_hDC
, &docinfo
);
896 ::StartDocA((HDC
) m_hDC
, &docinfo
);
903 DWORD lastError
= GetLastError();
904 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
911 void wxDC::EndDoc(void)
913 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
915 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
918 void wxDC::StartPage(void)
920 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
923 ::StartPage((HDC
) m_hDC
);
926 void wxDC::EndPage(void)
928 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
931 ::EndPage((HDC
) m_hDC
);
934 long wxDC::GetCharHeight(void) const
936 TEXTMETRIC lpTextMetric
;
938 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
940 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
943 long wxDC::GetCharWidth(void) const
945 TEXTMETRIC lpTextMetric
;
947 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
949 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
952 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
953 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
955 wxFont
*fontToUse
= (wxFont
*) theFont
;
957 fontToUse
= (wxFont
*) &m_font
;
962 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
963 GetTextMetrics((HDC
) m_hDC
, &tm
);
965 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
966 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
967 if (descent
) *descent
= tm
.tmDescent
;
968 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
971 void wxDC::SetMapMode(int mode
)
973 m_mappingMode
= mode
;
976 int pixel_height
= 0;
980 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
981 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
982 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
983 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
985 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
990 double mm2pixelsX
= pixel_width
/mm_width
;
991 double mm2pixelsY
= pixel_height
/mm_height
;
997 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
998 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1003 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1004 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1009 m_logicalScaleX
= mm2pixelsX
;
1010 m_logicalScaleY
= mm2pixelsY
;
1015 m_logicalScaleX
= (mm2pixelsX
/10.0);
1016 m_logicalScaleY
= (mm2pixelsY
/10.0);
1022 m_logicalScaleX
= 1.0;
1023 m_logicalScaleY
= 1.0;
1028 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1029 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1031 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1032 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1033 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1034 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1035 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1036 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1039 void wxDC::SetUserScale(double x
, double y
)
1044 SetMapMode(m_mappingMode
);
1047 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1049 m_signX
= xLeftRight
? 1 : -1;
1050 m_signY
= yBottomUp
? -1 : 1;
1052 SetMapMode(m_mappingMode
);
1055 void wxDC::SetSystemScale(double x
, double y
)
1060 SetMapMode(m_mappingMode
);
1063 void wxDC::SetLogicalOrigin(long x
, long y
)
1065 m_logicalOriginX
= x
;
1066 m_logicalOriginY
= y
;
1068 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1071 void wxDC::SetDeviceOrigin(long x
, long y
)
1073 m_deviceOriginX
= x
;
1074 m_deviceOriginY
= y
;
1076 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1079 long wxDC::DeviceToLogicalX(long x
) const
1081 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1084 long wxDC::DeviceToLogicalXRel(long x
) const
1086 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1089 long wxDC::DeviceToLogicalY(long y
) const
1091 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1094 long wxDC::DeviceToLogicalYRel(long y
) const
1096 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1099 long wxDC::LogicalToDeviceX(long x
) const
1101 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1104 long wxDC::LogicalToDeviceXRel(long x
) const
1106 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1109 long wxDC::LogicalToDeviceY(long y
) const
1111 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1114 long wxDC::LogicalToDeviceYRel(long y
) const
1116 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1119 // This group of functions may not do any conversion
1120 // if m_scaleGDI is TRUE, since the HDC does the
1121 // conversion automatically.
1123 long wxDC::ImplDeviceToLogicalX(long x
) const
1125 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1129 long wxDC::ImplDeviceToLogicalY(long y
) const
1131 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1135 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1137 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1141 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1143 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1147 long wxDC::ImplLogicalToDeviceX(long x
) const
1149 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1153 long wxDC::ImplLogicalToDeviceY(long y
) const
1155 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1159 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1161 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1165 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1167 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1171 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1172 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1174 long xdest1
= xdest
;
1175 long ydest1
= ydest
;
1179 // Chris Breeze 18/5/98: use text foreground/background colours
1180 // when blitting from 1-bit bitmaps
1181 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1182 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1183 if (m_textForegroundColour
.Ok())
1185 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1187 if (m_textBackgroundColour
.Ok())
1189 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1192 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1193 rop
== wxCLEAR
? WHITENESS
:
1194 rop
== wxSET
? BLACKNESS
:
1195 rop
== wxINVERT
? DSTINVERT
:
1196 rop
== wxAND
? MERGECOPY
:
1197 rop
== wxOR
? MERGEPAINT
:
1198 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1199 rop
== wxXOR
? SRCINVERT
:
1200 rop
== wxOR_REVERSE
? MERGEPAINT
:
1201 rop
== wxAND_REVERSE
? SRCERASE
:
1202 rop
== wxSRC_OR
? SRCPAINT
:
1203 rop
== wxSRC_AND
? SRCAND
:
1206 bool success
= TRUE
;
1207 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1211 // Not implemented under Win95 (or maybe a specific device?)
1212 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1213 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1223 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1224 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1225 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1226 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1227 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1228 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1229 ::SelectObject(dc_mask
, 0);
1230 ::DeleteDC(dc_mask
);
1232 // New code from Chris Breeze, 15/7/98
1233 // Blit bitmap with mask
1235 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1237 // If we are printing source colours are screen colours
1238 // not printer colours and so we need copy the bitmap
1241 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1242 HDC dc_src
= (HDC
) source
->m_hDC
;
1244 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1245 for (int x
= 0; x
< width
; x
++)
1247 for (int y
= 0; y
< height
; y
++)
1249 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1252 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1253 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1254 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1255 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1256 ::DeleteObject(brush
);
1260 ::SelectObject(dc_mask
, 0);
1261 ::DeleteDC(dc_mask
);
1265 // create a temp buffer bitmap and DCs to access it and the mask
1266 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1267 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1268 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1269 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1270 ::SelectObject(dc_buffer
, buffer_bmap
);
1272 // copy dest to buffer
1273 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1274 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1276 // copy src to buffer using selected raster op
1277 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1278 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1280 // set masked area in buffer to BLACK (pixel value 0)
1281 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1282 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1283 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1284 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1286 // set unmasked area in dest to BLACK
1287 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1288 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1289 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1290 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1291 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1292 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1294 // OR buffer to dest
1295 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1296 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1298 // tidy up temporary DCs and bitmap
1299 ::SelectObject(dc_mask
, 0);
1300 ::DeleteDC(dc_mask
);
1301 ::SelectObject(dc_buffer
, 0);
1302 ::DeleteDC(dc_buffer
);
1303 ::DeleteObject(buffer_bmap
);
1309 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1311 // If we are printing, source colours are screen colours
1312 // not printer colours and so we need copy the bitmap
1314 HDC dc_src
= (HDC
) source
->m_hDC
;
1316 for (int x
= 0; x
< width
; x
++)
1318 for (int y
= 0; y
< height
; y
++)
1320 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1321 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1322 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1323 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1324 ::DeleteObject(brush
);
1330 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1331 xsrc1
, ysrc1
, dwRop
) != 0);
1334 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1335 ::SetBkColor((HDC
)m_hDC
, old_background
);
1340 void wxDC::GetSize(int* width
, int* height
) const
1342 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1343 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1348 void wxDC::GetSizeMM(long *width
, long *height
) const
1350 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1351 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1356 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1358 int n
= list
->Number();
1359 wxPoint
*points
= new wxPoint
[n
];
1362 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1363 wxPoint
*point
= (wxPoint
*)node
->Data();
1364 points
[i
].x
= point
->x
;
1365 points
[i
++].y
= point
->y
;
1367 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1371 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1373 int n
= list
->Number();
1374 wxPoint
*points
= new wxPoint
[n
];
1377 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1378 wxPoint
*point
= (wxPoint
*)node
->Data();
1379 points
[i
].x
= point
->x
;
1380 points
[i
++].y
= point
->y
;
1382 DrawLines(n
, points
, xoffset
, yoffset
);
1386 void wxDC::SetTextForeground(const wxColour
& colour
)
1388 m_textForegroundColour
= colour
;
1391 void wxDC::SetTextBackground(const wxColour
& colour
)
1393 m_textBackgroundColour
= colour
;
1396 // For use by wxWindows only, unless custom units are required.
1397 void wxDC::SetLogicalScale(double x
, double y
)
1399 m_logicalScaleX
= x
;
1400 m_logicalScaleY
= y
;
1403 void wxDC::CalcBoundingBox(long x
, long y
)
1405 if (x
< m_minX
) m_minX
= x
;
1406 if (y
< m_minY
) m_minY
= y
;
1407 if (x
> m_maxX
) m_maxX
= x
;
1408 if (y
> m_maxY
) m_maxY
= y
;
1411 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1417 *w
= (m_clipX2
- m_clipX1
) ;
1418 *h
= (m_clipY2
- m_clipY1
) ;
1421 *x
= *y
= *w
= *h
= 0 ;
1424 #if WXWIN_COMPATIBILITY
1425 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1426 float *descent
, float *externalLeading
,
1427 wxFont
*theFont
, bool use16bit
) const
1429 long x1
, y1
, descent1
, externalLeading1
;
1430 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1433 *descent
= descent1
;
1434 if (externalLeading
)
1435 *externalLeading
= externalLeading1
;
1439 int wxDC::GetDepth(void) const
1441 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1446 // Make a 3-point spline
1447 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1449 wxList
*point_list
= new wxList
;
1451 wxPoint
*point1
= new wxPoint
;
1452 point1
->x
= x1
; point1
->y
= y1
;
1453 point_list
->Append((wxObject
*)point1
);
1455 wxPoint
*point2
= new wxPoint
;
1456 point2
->x
= x2
; point2
->y
= y2
;
1457 point_list
->Append((wxObject
*)point2
);
1459 wxPoint
*point3
= new wxPoint
;
1460 point3
->x
= x3
; point3
->y
= y3
;
1461 point_list
->Append((wxObject
*)point3
);
1463 DrawSpline(point_list
);
1465 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1466 wxPoint
*p
= (wxPoint
*)node
->Data();
1472 ////#define wx_round(a) (int)((a)+.5)
1473 //#define wx_round(a) (a)
1475 class wxSpline
: public wxObject
1481 wxSpline(wxList
*list
);
1482 void DeletePoints(void);
1484 // Doesn't delete points
1488 void wxDC::DrawSpline(int n
, wxPoint points
[])
1492 for (i
=0; i
< n
; i
++)
1493 list
.Append((wxObject
*)&points
[i
]);
1494 DrawSpline((wxList
*)&list
);
1497 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1499 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1500 double a3
, double b3
, double a4
, double b4
);
1501 void wx_clear_stack(void);
1502 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1503 double *y3
, double *x4
, double *y4
);
1504 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1505 double x4
, double y4
);
1506 static bool wx_spline_add_point(double x
, double y
);
1507 static void wx_spline_draw_point_array(wxDC
*dc
);
1508 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1510 void wxDC::DrawSpline(wxList
*list
)
1512 wxSpline
spline(list
);
1514 wx_draw_open_spline(this, &spline
);
1518 wxList wx_spline_point_list
;
1520 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1523 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1524 double x1
, y1
, x2
, y2
;
1526 wxNode
*node
= spline
->points
->First();
1527 p
= (wxPoint
*)node
->Data();
1532 node
= node
->Next();
1533 p
= (wxPoint
*)node
->Data();
1537 cx1
= (double)((x1
+ x2
) / 2);
1538 cy1
= (double)((y1
+ y2
) / 2);
1539 cx2
= (double)((cx1
+ x2
) / 2);
1540 cy2
= (double)((cy1
+ y2
) / 2);
1542 wx_spline_add_point(x1
, y1
);
1544 while ((node
= node
->Next()) != NULL
)
1546 p
= (wxPoint
*)node
->Data();
1551 cx4
= (double)(x1
+ x2
) / 2;
1552 cy4
= (double)(y1
+ y2
) / 2;
1553 cx3
= (double)(x1
+ cx4
) / 2;
1554 cy3
= (double)(y1
+ cy4
) / 2;
1556 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1560 cx2
= (double)(cx1
+ x2
) / 2;
1561 cy2
= (double)(cy1
+ y2
) / 2;
1564 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1565 wx_spline_add_point(x2
, y2
);
1567 wx_spline_draw_point_array(dc
);
1571 /********************* CURVES FOR SPLINES *****************************
1573 The following spline drawing routine is from
1575 "An Algorithm for High-Speed Curve Generation"
1576 by George Merrill Chaikin,
1577 Computer Graphics and Image Processing, 3, Academic Press,
1582 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1583 Computer Graphics and Image Processing, 4, Academic Press,
1586 ***********************************************************************/
1588 #define half(z1, z2) ((z1+z2)/2.0)
1591 /* iterative version */
1593 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1596 register double xmid
, ymid
;
1597 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1600 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1602 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1603 xmid
= (double)half(x2
, x3
);
1604 ymid
= (double)half(y2
, y3
);
1605 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1606 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1607 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1608 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1610 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1611 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1612 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1613 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1619 /* utilities used by spline drawing routines */
1622 typedef struct wx_spline_stack_struct
{
1623 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1627 #define SPLINE_STACK_DEPTH 20
1628 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1629 static Stack
*wx_stack_top
;
1630 static int wx_stack_count
;
1632 void wx_clear_stack(void)
1634 wx_stack_top
= wx_spline_stack
;
1638 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1640 wx_stack_top
->x1
= x1
;
1641 wx_stack_top
->y1
= y1
;
1642 wx_stack_top
->x2
= x2
;
1643 wx_stack_top
->y2
= y2
;
1644 wx_stack_top
->x3
= x3
;
1645 wx_stack_top
->y3
= y3
;
1646 wx_stack_top
->x4
= x4
;
1647 wx_stack_top
->y4
= y4
;
1652 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1653 double *x3
, double *y3
, double *x4
, double *y4
)
1655 if (wx_stack_count
== 0)
1659 *x1
= wx_stack_top
->x1
;
1660 *y1
= wx_stack_top
->y1
;
1661 *x2
= wx_stack_top
->x2
;
1662 *y2
= wx_stack_top
->y2
;
1663 *x3
= wx_stack_top
->x3
;
1664 *y3
= wx_stack_top
->y3
;
1665 *x4
= wx_stack_top
->x4
;
1666 *y4
= wx_stack_top
->y4
;
1670 static bool wx_spline_add_point(double x
, double y
)
1672 wxPoint
*point
= new wxPoint
;
1675 wx_spline_point_list
.Append((wxObject
*)point
);
1679 static void wx_spline_draw_point_array(wxDC
*dc
)
1681 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1682 wxNode
*node
= wx_spline_point_list
.First();
1685 wxPoint
*point
= (wxPoint
*)node
->Data();
1688 node
= wx_spline_point_list
.First();
1692 wxSpline::wxSpline(wxList
*list
)
1697 wxSpline::~wxSpline(void)
1701 void wxSpline::DeletePoints(void)
1703 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1705 wxPoint
*point
= (wxPoint
*)node
->Data();
1713 #endif // wxUSE_SPLINES