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"
29 #include "wx/bitmap.h"
30 #include "wx/dcmemory.h"
33 #include "wx/dcprint.h"
34 #include "wx/msw/private.h"
39 #if wxUSE_COMMON_DIALOGS
59 #if !USE_SHARED_LIBRARY
60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
63 // Declarations local to this file
65 #define YSCALE(y) (yorigin - (y))
67 // #define wx_round(a) (int)((a)+.5)
69 // Default constructor
72 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
82 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
87 m_logicalScaleX
= 1.0;
88 m_logicalScaleY
= 1.0;
95 m_mappingMode
= wxMM_TEXT
;
100 m_windowExtX
= VIEWPORT_EXTENT
;
101 m_windowExtY
= VIEWPORT_EXTENT
;
102 m_logicalFunction
= -1;
104 m_backgroundBrush
= *wxWHITE_BRUSH
;
106 m_textForegroundColour
= *wxBLACK
;
107 m_textBackgroundColour
= *wxWHITE
;
109 m_colour
= wxColourDisplay();
118 SelectOldObjects(m_hDC
);
120 if ( m_canvas
== NULL
)
121 ::DeleteDC((HDC
)m_hDC
);
123 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
129 // This will select current objects out of the DC,
130 // which is what you have to do before deleting the
132 void wxDC::SelectOldObjects(WXHDC dc
)
138 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
139 if (m_selectedBitmap
.Ok())
141 m_selectedBitmap
.SetSelectedInto(NULL
);
147 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
152 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
157 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
162 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
167 m_brush
= wxNullBrush
;
169 m_palette
= wxNullPalette
;
171 m_backgroundBrush
= wxNullBrush
;
172 m_selectedBitmap
= wxNullBitmap
;
175 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
180 m_clipX2
= (int)(cx
+ cw
);
181 m_clipY2
= (int)(cy
+ ch
);
183 DoClipping((WXHDC
) m_hDC
);
186 void wxDC::SetClippingRegion(const wxRegion
& region
)
188 if (!region
.GetHRGN())
191 wxRect box
= region
.GetBox();
196 m_clipX2
= box
.x
+ box
.width
;
197 m_clipY2
= box
.y
+ box
.height
;
200 SelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN());
202 ExtSelectClipRgn((HDC
) m_hDC
, (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(void)
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((HDC
) m_hDC
, rgn
);
229 bool wxDC::CanDrawBitmap(void) const
234 bool wxDC::CanGetTextExtent(void) const
236 // What sort of display is it?
237 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
241 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
248 void wxDC::SetPalette(const wxPalette
& palette
)
250 // Set the old object temporarily, in case the assignment deletes an object
251 // that's not yet selected out.
254 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
262 // Setting a NULL colourmap is a way of restoring
263 // the original colourmap
266 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
273 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
275 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
277 m_oldPalette
= (WXHPALETTE
) oldPal
;
279 ::RealizePalette((HDC
) m_hDC
);
283 void wxDC::Clear(void)
287 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
288 else if (m_selectedBitmap
.Ok())
290 rect
.left
= 0; rect
.top
= 0;
291 rect
.right
= m_selectedBitmap
.GetWidth();
292 rect
.bottom
= m_selectedBitmap
.GetHeight();
294 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
296 DWORD colour
= GetBkColor((HDC
) m_hDC
);
297 HBRUSH brush
= CreateSolidBrush(colour
);
298 FillRect((HDC
) m_hDC
, &rect
, brush
);
301 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
302 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
303 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
304 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
305 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
308 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
310 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
312 style
==wxFLOOD_SURFACE
?
313 FLOODFILLSURFACE
:FLOODFILLBORDER
316 CalcBoundingBox(x
, y
);
319 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
321 // added by steve 29.12.94 (copied from DrawPoint)
322 // returns TRUE for pixels in the color of the current pen
323 // and FALSE for all other pixels colors
324 // if col is non-NULL return the color of the pixel
326 // get the color of the pixel
327 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
328 // get the color of the pen
329 COLORREF pencolor
= 0x00ffffff;
332 pencolor
= m_pen
.GetColour().GetPixel() ;
335 // return the color of the pixel
337 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
339 // check, if color of the pixels is the same as the color
340 // of the current pen
341 return(pixelcolor
==pencolor
);
344 void wxDC::CrossHair(long x
, long y
)
346 // We suppose that our screen is 2000x2000 max.
352 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
353 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
355 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
356 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
358 CalcBoundingBox(x1
, y1
);
359 CalcBoundingBox(x2
, y2
);
362 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
364 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
365 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
367 /* MATTHEW: [6] New normalization */
368 #if WX_STANDARD_GRAPHICS
369 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
372 CalcBoundingBox(x1
, y1
);
373 CalcBoundingBox(x2
, y2
);
376 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
380 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
381 if (x1
==x2
&& x2
==y2
)
383 DrawEllipse(xc
,yc
,(long)(radius
*2.0),(long)(radius
*2.0)) ;
387 long xx1
= XLOG2DEV(x1
) ;
388 long yy1
= YLOG2DEV(y1
) ;
389 long xx2
= XLOG2DEV(x2
) ;
390 long yy2
= YLOG2DEV(y2
) ;
391 long xxc
= XLOG2DEV(xc
) ;
392 long yyc
= YLOG2DEV(yc
) ;
393 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
395 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
396 long xxx1
= (long) (xxc
-ray
);
397 long yyy1
= (long) (yyc
-ray
);
398 long xxx2
= (long) (xxc
+ray
);
399 long yyy2
= (long) (yyc
+ray
);
400 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
402 // Have to add 1 to bottom-right corner of rectangle
403 // to make semi-circles look right (crooked line otherwise).
404 // Unfortunately this is not a reliable method, depends
405 // on the size of shape.
406 // TODO: figure out why this happens!
407 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
411 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
414 CalcBoundingBox((xc
-radius
), (yc
-radius
));
415 CalcBoundingBox((xc
+radius
), (yc
+radius
));
418 void wxDC::DrawPoint(long x
, long y
)
420 COLORREF color
= 0x00ffffff;
423 color
= m_pen
.GetColour().GetPixel() ;
426 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
428 CalcBoundingBox(x
, y
);
431 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
433 // Do things less efficiently if we have offsets
434 if (xoffset
!= 0 || yoffset
!= 0)
436 POINT
*cpoints
= new POINT
[n
];
438 for (i
= 0; i
< n
; i
++)
440 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
441 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
443 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
445 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
446 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
447 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
453 for (i
= 0; i
< n
; i
++)
454 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
456 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
457 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
458 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
462 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
464 // Do things less efficiently if we have offsets
465 if (xoffset
!= 0 || yoffset
!= 0)
467 POINT
*cpoints
= new POINT
[n
];
469 for (i
= 0; i
< n
; i
++)
471 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
472 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
474 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
476 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
482 for (i
= 0; i
< n
; i
++)
483 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
485 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
489 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
492 long y2
= y
+ height
;
494 /* MATTHEW: [6] new normalization */
495 #if WX_STANDARD_GRAPHICS
496 bool do_brush
, do_pen
;
498 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
499 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
502 HPEN orig_pen
= NULL
;
504 if (do_pen
|| !m_pen
.Ok())
505 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
507 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
508 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
510 if (do_pen
|| !m_pen
.Ok())
511 ::SelectObject((HDC
) m_hDC
, orig_pen
);
514 HBRUSH orig_brush
= NULL
;
516 if (do_brush
|| !m_brush
.Ok())
517 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
519 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
520 XLOG2DEV(x2
), YLOG2DEV(y2
));
522 if (do_brush
|| !m_brush
.Ok())
523 ::SelectObject((HDC
) m_hDC
, orig_brush
);
526 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
529 CalcBoundingBox(x
, y
);
530 CalcBoundingBox(x2
, y2
);
533 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
535 // Now, a negative radius value is interpreted to mean
536 // 'the proportion of the smallest X or Y dimension'
540 double smallest
= 0.0;
545 radius
= (- radius
* smallest
);
549 long y2
= (y
+height
);
551 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
552 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
554 CalcBoundingBox(x
, y
);
555 CalcBoundingBox(x2
, y2
);
558 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
561 long y2
= (y
+height
);
563 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
565 CalcBoundingBox(x
, y
);
566 CalcBoundingBox(x2
, y2
);
569 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
570 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
575 const double deg2rad
= 3.14159265359 / 180.0;
576 int rx1
= XLOG2DEV(x
+w
/2);
577 int ry1
= YLOG2DEV(y
+h
/2);
580 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
581 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
582 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
583 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
585 // draw pie with NULL_PEN first and then outline otherwise a line is
586 // drawn from the start and end points to the centre
587 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
590 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
595 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
596 rx1
, ry1
-1, rx2
, ry2
-1);
598 ::SelectObject((HDC
) m_hDC
, orig_pen
);
599 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
602 CalcBoundingBox(x
, y
);
603 CalcBoundingBox(x2
, y2
);
606 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
608 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
609 ::DrawIconEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
610 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
612 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
615 CalcBoundingBox(x
, y
);
616 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
619 void wxDC::DrawBitmap( const wxBitmap
&bmp
, long x
, long y
, bool useMask
)
624 // If we're not drawing transparently, and not drawing to a printer,
625 // optimize this function to use Windows functions.
626 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
628 HDC cdc
= (HDC
)m_hDC
;
629 HDC memdc
= ::CreateCompatibleDC( cdc
);
630 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
631 ::SelectObject( memdc
, hbitmap
);
632 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
633 ::SelectObject( memdc
, 0 );
638 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
640 memDC
.SelectObject(bmp
);
642 /* Not sure if we need this. The mask should leave the
643 * masked areas as per the original background of this DC.
646 // There might be transparent areas, so make these
647 // the same colour as this DC
648 memDC.SetBackground(* GetBackground());
652 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
654 memDC
.SelectObject(wxNullBitmap
);
658 void wxDC::SetFont(const wxFont
& the_font
)
660 // Set the old object temporarily, in case the assignment deletes an object
661 // that's not yet selected out.
664 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
673 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
677 if (m_font
.Ok() && m_font
.GetResourceHandle())
679 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
680 if (f
== (HFONT
) NULL
)
682 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
685 m_oldFont
= (WXHFONT
) f
;
689 void wxDC::SetPen(const wxPen
& pen
)
691 // Set the old object temporarily, in case the assignment deletes an object
692 // that's not yet selected out.
695 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
704 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
710 if (m_pen
.GetResourceHandle())
712 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
714 m_oldPen
= (WXHPEN
) p
;
719 void wxDC::SetBrush(const wxBrush
& brush
)
721 // Set the old object temporarily, in case the assignment deletes an object
722 // that's not yet selected out.
725 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
734 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
740 if (m_brush
.GetResourceHandle())
743 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
745 m_oldBrush
= (WXHBRUSH
) b
;
750 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
752 // Should be unnecessary: SetFont should have done this already.
754 if (m_font
.Ok() && m_font
.GetResourceHandle())
756 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
758 m_oldFont
= (WXHFONT
) f
;
762 if (m_textForegroundColour
.Ok())
763 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
765 DWORD old_background
= 0;
766 if (m_textBackgroundColour
.Ok())
768 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
771 if (m_backgroundMode
== wxTRANSPARENT
)
772 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
774 SetBkMode((HDC
) m_hDC
, OPAQUE
);
776 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
778 if (m_textBackgroundColour
.Ok())
779 (void)SetBkColor((HDC
) m_hDC
, old_background
);
781 CalcBoundingBox(x
, y
);
784 GetTextExtent(text
, &w
, &h
);
785 CalcBoundingBox((x
+ w
), (y
+ h
));
788 void wxDC::SetBackground(const wxBrush
& brush
)
790 m_backgroundBrush
= brush
;
792 if (!m_backgroundBrush
.Ok())
797 bool customColours
= TRUE
;
798 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
799 // change background colours from the control-panel specified colours.
800 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
801 customColours
= FALSE
;
805 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
807 m_canvas
->m_backgroundTransparent
= TRUE
;
811 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
812 m_canvas
->m_backgroundTransparent
= FALSE
;
816 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
818 (void)SetBkColor((HDC
) m_hDC
, new_color
);
822 void wxDC::SetBackgroundMode(int mode
)
824 m_backgroundMode
= mode
;
826 if (m_backgroundMode
== wxTRANSPARENT
)
827 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
829 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
832 void wxDC::SetLogicalFunction(int function
)
834 m_logicalFunction
= function
;
836 SetRop((WXHDC
) m_hDC
);
839 void wxDC::SetRop(WXHDC dc
)
841 if (!dc
|| m_logicalFunction
< 0)
845 // These may be wrong
846 switch (m_logicalFunction
)
848 // case wxXOR: c_rop = R2_XORPEN; break;
849 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
850 case wxINVERT
: c_rop
= R2_NOT
; break;
851 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
852 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
853 case wxCLEAR
: c_rop
= R2_WHITE
; break;
854 case wxSET
: c_rop
= R2_BLACK
; break;
855 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
856 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
857 case wxAND
: c_rop
= R2_MASKPEN
; break;
858 case wxOR
: c_rop
= R2_MERGEPEN
; break;
859 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
864 c_rop
= R2_COPYPEN
; break;
866 SetROP2((HDC
) dc
, c_rop
);
869 bool wxDC::StartDoc(const wxString
& message
)
871 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
875 docinfo
.cbSize
= sizeof(DOCINFO
);
876 docinfo
.lpszDocName
= (const char *)message
;
878 if (m_filename
.IsEmpty())
879 docinfo
.lpszOutput
= NULL
;
881 docinfo
.lpszOutput
= (const char *)m_filename
;
883 #if defined(__WIN95__)
884 docinfo
.lpszDatatype
= NULL
;
893 ::StartDoc((HDC
) m_hDC
, &docinfo
);
896 ::StartDocW((HDC
) m_hDC
, &docinfo
);
899 ::StartDoc((HDC
) m_hDC
, &docinfo
);
901 ::StartDocA((HDC
) m_hDC
, &docinfo
);
909 DWORD lastError
= GetLastError();
910 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
917 void wxDC::EndDoc(void)
919 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
921 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
924 void wxDC::StartPage(void)
926 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
929 ::StartPage((HDC
) m_hDC
);
932 void wxDC::EndPage(void)
934 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
937 ::EndPage((HDC
) m_hDC
);
940 long wxDC::GetCharHeight(void) const
942 TEXTMETRIC lpTextMetric
;
944 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
946 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
949 long wxDC::GetCharWidth(void) const
951 TEXTMETRIC lpTextMetric
;
953 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
955 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
958 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
959 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
961 wxFont
*fontToUse
= (wxFont
*) theFont
;
963 fontToUse
= (wxFont
*) &m_font
;
968 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
969 GetTextMetrics((HDC
) m_hDC
, &tm
);
971 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
972 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
973 if (descent
) *descent
= tm
.tmDescent
;
974 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
977 void wxDC::SetMapMode(int mode
)
979 m_mappingMode
= mode
;
982 int pixel_height
= 0;
986 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
987 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
988 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
989 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
991 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
996 double mm2pixelsX
= pixel_width
/mm_width
;
997 double mm2pixelsY
= pixel_height
/mm_height
;
1003 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1004 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1009 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1010 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1015 m_logicalScaleX
= mm2pixelsX
;
1016 m_logicalScaleY
= mm2pixelsY
;
1021 m_logicalScaleX
= (mm2pixelsX
/10.0);
1022 m_logicalScaleY
= (mm2pixelsY
/10.0);
1028 m_logicalScaleX
= 1.0;
1029 m_logicalScaleY
= 1.0;
1034 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1035 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1037 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1038 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1039 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1040 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1041 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1042 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1045 void wxDC::SetUserScale(double x
, double y
)
1050 SetMapMode(m_mappingMode
);
1053 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1055 m_signX
= xLeftRight
? 1 : -1;
1056 m_signY
= yBottomUp
? -1 : 1;
1058 SetMapMode(m_mappingMode
);
1061 void wxDC::SetSystemScale(double x
, double y
)
1066 SetMapMode(m_mappingMode
);
1069 void wxDC::SetLogicalOrigin(long x
, long y
)
1071 m_logicalOriginX
= x
;
1072 m_logicalOriginY
= y
;
1074 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1077 void wxDC::SetDeviceOrigin(long x
, long y
)
1079 m_deviceOriginX
= x
;
1080 m_deviceOriginY
= y
;
1082 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1085 long wxDC::DeviceToLogicalX(long x
) const
1087 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1090 long wxDC::DeviceToLogicalXRel(long x
) const
1092 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1095 long wxDC::DeviceToLogicalY(long y
) const
1097 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1100 long wxDC::DeviceToLogicalYRel(long y
) const
1102 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1105 long wxDC::LogicalToDeviceX(long x
) const
1107 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1110 long wxDC::LogicalToDeviceXRel(long x
) const
1112 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1115 long wxDC::LogicalToDeviceY(long y
) const
1117 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1120 long wxDC::LogicalToDeviceYRel(long y
) const
1122 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1125 // This group of functions may not do any conversion
1126 // if m_scaleGDI is TRUE, since the HDC does the
1127 // conversion automatically.
1129 long wxDC::ImplDeviceToLogicalX(long x
) const
1131 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1135 long wxDC::ImplDeviceToLogicalY(long y
) const
1137 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1141 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1143 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1147 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1149 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1153 long wxDC::ImplLogicalToDeviceX(long x
) const
1155 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1159 long wxDC::ImplLogicalToDeviceY(long y
) const
1161 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1165 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1167 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1171 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1173 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1177 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1178 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1180 long xdest1
= xdest
;
1181 long ydest1
= ydest
;
1185 // Chris Breeze 18/5/98: use text foreground/background colours
1186 // when blitting from 1-bit bitmaps
1187 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1188 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1189 if (m_textForegroundColour
.Ok())
1191 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1193 if (m_textBackgroundColour
.Ok())
1195 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1198 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1199 rop
== wxCLEAR
? WHITENESS
:
1200 rop
== wxSET
? BLACKNESS
:
1201 rop
== wxINVERT
? DSTINVERT
:
1202 rop
== wxAND
? MERGECOPY
:
1203 rop
== wxOR
? MERGEPAINT
:
1204 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1205 rop
== wxXOR
? SRCINVERT
:
1206 rop
== wxOR_REVERSE
? MERGEPAINT
:
1207 rop
== wxAND_REVERSE
? SRCERASE
:
1208 rop
== wxSRC_OR
? SRCPAINT
:
1209 rop
== wxSRC_AND
? SRCAND
:
1212 bool success
= TRUE
;
1213 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1217 // Not implemented under Win95 (or maybe a specific device?)
1218 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1219 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1229 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1230 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1231 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1232 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1233 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1234 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1235 ::SelectObject(dc_mask
, 0);
1236 ::DeleteDC(dc_mask
);
1238 // New code from Chris Breeze, 15/7/98
1239 // Blit bitmap with mask
1241 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1243 // If we are printing source colours are screen colours
1244 // not printer colours and so we need copy the bitmap
1247 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1248 HDC dc_src
= (HDC
) source
->m_hDC
;
1250 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1251 for (int x
= 0; x
< width
; x
++)
1253 for (int y
= 0; y
< height
; y
++)
1255 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1258 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1259 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1260 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1261 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1262 ::DeleteObject(brush
);
1266 ::SelectObject(dc_mask
, 0);
1267 ::DeleteDC(dc_mask
);
1271 // create a temp buffer bitmap and DCs to access it and the mask
1272 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1273 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1274 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1275 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1276 ::SelectObject(dc_buffer
, buffer_bmap
);
1278 // copy dest to buffer
1279 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1280 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1282 // copy src to buffer using selected raster op
1283 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1284 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1286 // set masked area in buffer to BLACK (pixel value 0)
1287 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1288 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1289 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1290 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1292 // set unmasked area in dest to BLACK
1293 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1294 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1295 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1296 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1297 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1298 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1300 // OR buffer to dest
1301 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1302 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1304 // tidy up temporary DCs and bitmap
1305 ::SelectObject(dc_mask
, 0);
1306 ::DeleteDC(dc_mask
);
1307 ::SelectObject(dc_buffer
, 0);
1308 ::DeleteDC(dc_buffer
);
1309 ::DeleteObject(buffer_bmap
);
1315 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1317 // If we are printing, source colours are screen colours
1318 // not printer colours and so we need copy the bitmap
1320 HDC dc_src
= (HDC
) source
->m_hDC
;
1322 for (int x
= 0; x
< width
; x
++)
1324 for (int y
= 0; y
< height
; y
++)
1326 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1327 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1328 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1329 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1330 ::DeleteObject(brush
);
1336 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1337 xsrc1
, ysrc1
, dwRop
) != 0);
1340 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1341 ::SetBkColor((HDC
)m_hDC
, old_background
);
1346 void wxDC::GetSize(int* width
, int* height
) const
1348 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1349 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1354 void wxDC::GetSizeMM(long *width
, long *height
) const
1356 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1357 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1362 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1364 int n
= list
->Number();
1365 wxPoint
*points
= new wxPoint
[n
];
1368 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1369 wxPoint
*point
= (wxPoint
*)node
->Data();
1370 points
[i
].x
= point
->x
;
1371 points
[i
++].y
= point
->y
;
1373 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1377 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1379 int n
= list
->Number();
1380 wxPoint
*points
= new wxPoint
[n
];
1383 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1384 wxPoint
*point
= (wxPoint
*)node
->Data();
1385 points
[i
].x
= point
->x
;
1386 points
[i
++].y
= point
->y
;
1388 DrawLines(n
, points
, xoffset
, yoffset
);
1392 void wxDC::SetTextForeground(const wxColour
& colour
)
1394 m_textForegroundColour
= colour
;
1397 void wxDC::SetTextBackground(const wxColour
& colour
)
1399 m_textBackgroundColour
= colour
;
1402 // For use by wxWindows only, unless custom units are required.
1403 void wxDC::SetLogicalScale(double x
, double y
)
1405 m_logicalScaleX
= x
;
1406 m_logicalScaleY
= y
;
1409 void wxDC::CalcBoundingBox(long x
, long y
)
1411 if (x
< m_minX
) m_minX
= x
;
1412 if (y
< m_minY
) m_minY
= y
;
1413 if (x
> m_maxX
) m_maxX
= x
;
1414 if (y
> m_maxY
) m_maxY
= y
;
1417 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1423 *w
= (m_clipX2
- m_clipX1
) ;
1424 *h
= (m_clipY2
- m_clipY1
) ;
1427 *x
= *y
= *w
= *h
= 0 ;
1430 #if WXWIN_COMPATIBILITY
1431 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1432 float *descent
, float *externalLeading
,
1433 wxFont
*theFont
, bool use16bit
) const
1435 long x1
, y1
, descent1
, externalLeading1
;
1436 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1439 *descent
= descent1
;
1440 if (externalLeading
)
1441 *externalLeading
= externalLeading1
;
1445 int wxDC::GetDepth(void) const
1447 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1452 // Make a 3-point spline
1453 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1455 wxList
*point_list
= new wxList
;
1457 wxPoint
*point1
= new wxPoint
;
1458 point1
->x
= x1
; point1
->y
= y1
;
1459 point_list
->Append((wxObject
*)point1
);
1461 wxPoint
*point2
= new wxPoint
;
1462 point2
->x
= x2
; point2
->y
= y2
;
1463 point_list
->Append((wxObject
*)point2
);
1465 wxPoint
*point3
= new wxPoint
;
1466 point3
->x
= x3
; point3
->y
= y3
;
1467 point_list
->Append((wxObject
*)point3
);
1469 DrawSpline(point_list
);
1471 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1472 wxPoint
*p
= (wxPoint
*)node
->Data();
1478 ////#define wx_round(a) (int)((a)+.5)
1479 //#define wx_round(a) (a)
1481 class wxSpline
: public wxObject
1487 wxSpline(wxList
*list
);
1488 void DeletePoints(void);
1490 // Doesn't delete points
1494 void wxDC::DrawSpline(int n
, wxPoint points
[])
1498 for (i
=0; i
< n
; i
++)
1499 list
.Append((wxObject
*)&points
[i
]);
1500 DrawSpline((wxList
*)&list
);
1503 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1505 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1506 double a3
, double b3
, double a4
, double b4
);
1507 void wx_clear_stack(void);
1508 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1509 double *y3
, double *x4
, double *y4
);
1510 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1511 double x4
, double y4
);
1512 static bool wx_spline_add_point(double x
, double y
);
1513 static void wx_spline_draw_point_array(wxDC
*dc
);
1514 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1516 void wxDC::DrawSpline(wxList
*list
)
1518 wxSpline
spline(list
);
1520 wx_draw_open_spline(this, &spline
);
1524 wxList wx_spline_point_list
;
1526 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1529 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1530 double x1
, y1
, x2
, y2
;
1532 wxNode
*node
= spline
->points
->First();
1533 p
= (wxPoint
*)node
->Data();
1538 node
= node
->Next();
1539 p
= (wxPoint
*)node
->Data();
1543 cx1
= (double)((x1
+ x2
) / 2);
1544 cy1
= (double)((y1
+ y2
) / 2);
1545 cx2
= (double)((cx1
+ x2
) / 2);
1546 cy2
= (double)((cy1
+ y2
) / 2);
1548 wx_spline_add_point(x1
, y1
);
1550 while ((node
= node
->Next()) != NULL
)
1552 p
= (wxPoint
*)node
->Data();
1557 cx4
= (double)(x1
+ x2
) / 2;
1558 cy4
= (double)(y1
+ y2
) / 2;
1559 cx3
= (double)(x1
+ cx4
) / 2;
1560 cy3
= (double)(y1
+ cy4
) / 2;
1562 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1566 cx2
= (double)(cx1
+ x2
) / 2;
1567 cy2
= (double)(cy1
+ y2
) / 2;
1570 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1571 wx_spline_add_point(x2
, y2
);
1573 wx_spline_draw_point_array(dc
);
1577 /********************* CURVES FOR SPLINES *****************************
1579 The following spline drawing routine is from
1581 "An Algorithm for High-Speed Curve Generation"
1582 by George Merrill Chaikin,
1583 Computer Graphics and Image Processing, 3, Academic Press,
1588 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1589 Computer Graphics and Image Processing, 4, Academic Press,
1592 ***********************************************************************/
1594 #define half(z1, z2) ((z1+z2)/2.0)
1597 /* iterative version */
1599 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1602 register double xmid
, ymid
;
1603 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1606 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1608 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1609 xmid
= (double)half(x2
, x3
);
1610 ymid
= (double)half(y2
, y3
);
1611 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1612 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1613 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1614 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1616 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1617 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1618 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1619 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1625 /* utilities used by spline drawing routines */
1628 typedef struct wx_spline_stack_struct
{
1629 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1633 #define SPLINE_STACK_DEPTH 20
1634 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1635 static Stack
*wx_stack_top
;
1636 static int wx_stack_count
;
1638 void wx_clear_stack(void)
1640 wx_stack_top
= wx_spline_stack
;
1644 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1646 wx_stack_top
->x1
= x1
;
1647 wx_stack_top
->y1
= y1
;
1648 wx_stack_top
->x2
= x2
;
1649 wx_stack_top
->y2
= y2
;
1650 wx_stack_top
->x3
= x3
;
1651 wx_stack_top
->y3
= y3
;
1652 wx_stack_top
->x4
= x4
;
1653 wx_stack_top
->y4
= y4
;
1658 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1659 double *x3
, double *y3
, double *x4
, double *y4
)
1661 if (wx_stack_count
== 0)
1665 *x1
= wx_stack_top
->x1
;
1666 *y1
= wx_stack_top
->y1
;
1667 *x2
= wx_stack_top
->x2
;
1668 *y2
= wx_stack_top
->y2
;
1669 *x3
= wx_stack_top
->x3
;
1670 *y3
= wx_stack_top
->y3
;
1671 *x4
= wx_stack_top
->x4
;
1672 *y4
= wx_stack_top
->y4
;
1676 static bool wx_spline_add_point(double x
, double y
)
1678 wxPoint
*point
= new wxPoint
;
1681 wx_spline_point_list
.Append((wxObject
*)point
);
1685 static void wx_spline_draw_point_array(wxDC
*dc
)
1687 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1688 wxNode
*node
= wx_spline_point_list
.First();
1691 wxPoint
*point
= (wxPoint
*)node
->Data();
1694 node
= wx_spline_point_list
.First();
1698 wxSpline::wxSpline(wxList
*list
)
1703 wxSpline::~wxSpline(void)
1707 void wxSpline::DeletePoints(void)
1709 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1711 wxPoint
*point
= (wxPoint
*)node
->Data();
1719 #endif // wxUSE_SPLINES