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 // New behaviour, 10/2/99: setting the background brush of a DC
812 // doesn't affect the window background colour. However,
813 // I'm leaving in the transparency setting because it's needed by
814 // various controls (e.g. wxStaticText) to determine whether to draw
815 // transparently or not. TODO: maybe this should be a new function
816 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
818 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
819 m_canvas
->m_backgroundTransparent
= FALSE
;
823 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
825 (void)SetBkColor((HDC
) m_hDC
, new_color
);
829 void wxDC::SetBackgroundMode(int mode
)
831 m_backgroundMode
= mode
;
833 if (m_backgroundMode
== wxTRANSPARENT
)
834 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
836 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
839 void wxDC::SetLogicalFunction(int function
)
841 m_logicalFunction
= function
;
843 SetRop((WXHDC
) m_hDC
);
846 void wxDC::SetRop(WXHDC dc
)
848 if (!dc
|| m_logicalFunction
< 0)
852 // These may be wrong
853 switch (m_logicalFunction
)
855 // case wxXOR: c_rop = R2_XORPEN; break;
856 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
857 case wxINVERT
: c_rop
= R2_NOT
; break;
858 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
859 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
860 case wxCLEAR
: c_rop
= R2_WHITE
; break;
861 case wxSET
: c_rop
= R2_BLACK
; break;
862 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
863 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
864 case wxAND
: c_rop
= R2_MASKPEN
; break;
865 case wxOR
: c_rop
= R2_MERGEPEN
; break;
866 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
871 c_rop
= R2_COPYPEN
; break;
873 SetROP2((HDC
) dc
, c_rop
);
876 bool wxDC::StartDoc(const wxString
& message
)
878 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
882 docinfo
.cbSize
= sizeof(DOCINFO
);
883 docinfo
.lpszDocName
= (const char *)message
;
885 if (m_filename
.IsEmpty())
886 docinfo
.lpszOutput
= NULL
;
888 docinfo
.lpszOutput
= (const char *)m_filename
;
890 #if defined(__WIN95__)
891 docinfo
.lpszDatatype
= NULL
;
900 ::StartDoc((HDC
) m_hDC
, &docinfo
);
903 ::StartDocW((HDC
) m_hDC
, &docinfo
);
906 ::StartDoc((HDC
) m_hDC
, &docinfo
);
908 ::StartDocA((HDC
) m_hDC
, &docinfo
);
916 DWORD lastError
= GetLastError();
917 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
924 void wxDC::EndDoc(void)
926 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
928 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
931 void wxDC::StartPage(void)
933 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
936 ::StartPage((HDC
) m_hDC
);
939 void wxDC::EndPage(void)
941 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
944 ::EndPage((HDC
) m_hDC
);
947 long wxDC::GetCharHeight(void) const
949 TEXTMETRIC lpTextMetric
;
951 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
953 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
956 long wxDC::GetCharWidth(void) const
958 TEXTMETRIC lpTextMetric
;
960 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
962 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
965 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
966 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
968 wxFont
*fontToUse
= (wxFont
*) theFont
;
970 fontToUse
= (wxFont
*) &m_font
;
975 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
976 GetTextMetrics((HDC
) m_hDC
, &tm
);
978 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
979 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
980 if (descent
) *descent
= tm
.tmDescent
;
981 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
984 void wxDC::SetMapMode(int mode
)
986 m_mappingMode
= mode
;
989 int pixel_height
= 0;
993 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
994 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
995 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
996 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
998 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1003 double mm2pixelsX
= pixel_width
/mm_width
;
1004 double mm2pixelsY
= pixel_height
/mm_height
;
1010 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1011 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1016 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1017 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1022 m_logicalScaleX
= mm2pixelsX
;
1023 m_logicalScaleY
= mm2pixelsY
;
1028 m_logicalScaleX
= (mm2pixelsX
/10.0);
1029 m_logicalScaleY
= (mm2pixelsY
/10.0);
1035 m_logicalScaleX
= 1.0;
1036 m_logicalScaleY
= 1.0;
1041 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1042 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1044 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1045 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1046 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1047 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1048 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1049 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1052 void wxDC::SetUserScale(double x
, double y
)
1057 SetMapMode(m_mappingMode
);
1060 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1062 m_signX
= xLeftRight
? 1 : -1;
1063 m_signY
= yBottomUp
? -1 : 1;
1065 SetMapMode(m_mappingMode
);
1068 void wxDC::SetSystemScale(double x
, double y
)
1073 SetMapMode(m_mappingMode
);
1076 void wxDC::SetLogicalOrigin(long x
, long y
)
1078 m_logicalOriginX
= x
;
1079 m_logicalOriginY
= y
;
1081 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1084 void wxDC::SetDeviceOrigin(long x
, long y
)
1086 m_deviceOriginX
= x
;
1087 m_deviceOriginY
= y
;
1089 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1092 long wxDC::DeviceToLogicalX(long x
) const
1094 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1097 long wxDC::DeviceToLogicalXRel(long x
) const
1099 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1102 long wxDC::DeviceToLogicalY(long y
) const
1104 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1107 long wxDC::DeviceToLogicalYRel(long y
) const
1109 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1112 long wxDC::LogicalToDeviceX(long x
) const
1114 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1117 long wxDC::LogicalToDeviceXRel(long x
) const
1119 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1122 long wxDC::LogicalToDeviceY(long y
) const
1124 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1127 long wxDC::LogicalToDeviceYRel(long y
) const
1129 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1132 // This group of functions may not do any conversion
1133 // if m_scaleGDI is TRUE, since the HDC does the
1134 // conversion automatically.
1136 long wxDC::ImplDeviceToLogicalX(long x
) const
1138 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1142 long wxDC::ImplDeviceToLogicalY(long y
) const
1144 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1148 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1150 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1154 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1156 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1160 long wxDC::ImplLogicalToDeviceX(long x
) const
1162 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1166 long wxDC::ImplLogicalToDeviceY(long y
) const
1168 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1172 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1174 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1178 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1180 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1184 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1185 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1187 long xdest1
= xdest
;
1188 long ydest1
= ydest
;
1192 // Chris Breeze 18/5/98: use text foreground/background colours
1193 // when blitting from 1-bit bitmaps
1194 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1195 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1196 if (m_textForegroundColour
.Ok())
1198 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1200 if (m_textBackgroundColour
.Ok())
1202 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1205 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1206 rop
== wxCLEAR
? WHITENESS
:
1207 rop
== wxSET
? BLACKNESS
:
1208 rop
== wxINVERT
? DSTINVERT
:
1209 rop
== wxAND
? MERGECOPY
:
1210 rop
== wxOR
? MERGEPAINT
:
1211 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1212 rop
== wxXOR
? SRCINVERT
:
1213 rop
== wxOR_REVERSE
? MERGEPAINT
:
1214 rop
== wxAND_REVERSE
? SRCERASE
:
1215 rop
== wxSRC_OR
? SRCPAINT
:
1216 rop
== wxSRC_AND
? SRCAND
:
1219 bool success
= TRUE
;
1220 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1224 // Not implemented under Win95 (or maybe a specific device?)
1225 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1226 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1236 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1237 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1238 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1239 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1240 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1241 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1242 ::SelectObject(dc_mask
, 0);
1243 ::DeleteDC(dc_mask
);
1245 // New code from Chris Breeze, 15/7/98
1246 // Blit bitmap with mask
1248 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1250 // If we are printing source colours are screen colours
1251 // not printer colours and so we need copy the bitmap
1254 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1255 HDC dc_src
= (HDC
) source
->m_hDC
;
1257 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1258 for (int x
= 0; x
< width
; x
++)
1260 for (int y
= 0; y
< height
; y
++)
1262 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1265 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1266 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1267 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1268 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1269 ::DeleteObject(brush
);
1273 ::SelectObject(dc_mask
, 0);
1274 ::DeleteDC(dc_mask
);
1278 // create a temp buffer bitmap and DCs to access it and the mask
1279 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1280 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1281 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1282 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1283 ::SelectObject(dc_buffer
, buffer_bmap
);
1285 // copy dest to buffer
1286 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1287 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1289 // copy src to buffer using selected raster op
1290 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1291 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1293 // set masked area in buffer to BLACK (pixel value 0)
1294 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1295 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1296 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1297 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1299 // set unmasked area in dest to BLACK
1300 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1301 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1302 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1303 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1304 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1305 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1307 // OR buffer to dest
1308 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1309 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1311 // tidy up temporary DCs and bitmap
1312 ::SelectObject(dc_mask
, 0);
1313 ::DeleteDC(dc_mask
);
1314 ::SelectObject(dc_buffer
, 0);
1315 ::DeleteDC(dc_buffer
);
1316 ::DeleteObject(buffer_bmap
);
1322 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1324 // If we are printing, source colours are screen colours
1325 // not printer colours and so we need copy the bitmap
1327 HDC dc_src
= (HDC
) source
->m_hDC
;
1329 for (int x
= 0; x
< width
; x
++)
1331 for (int y
= 0; y
< height
; y
++)
1333 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1334 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1335 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1336 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1337 ::DeleteObject(brush
);
1343 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1344 xsrc1
, ysrc1
, dwRop
) != 0);
1347 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1348 ::SetBkColor((HDC
)m_hDC
, old_background
);
1353 void wxDC::GetSize(int* width
, int* height
) const
1355 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1356 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1361 void wxDC::GetSizeMM(long *width
, long *height
) const
1363 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1364 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1369 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1371 int n
= list
->Number();
1372 wxPoint
*points
= new wxPoint
[n
];
1375 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1376 wxPoint
*point
= (wxPoint
*)node
->Data();
1377 points
[i
].x
= point
->x
;
1378 points
[i
++].y
= point
->y
;
1380 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1384 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1386 int n
= list
->Number();
1387 wxPoint
*points
= new wxPoint
[n
];
1390 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1391 wxPoint
*point
= (wxPoint
*)node
->Data();
1392 points
[i
].x
= point
->x
;
1393 points
[i
++].y
= point
->y
;
1395 DrawLines(n
, points
, xoffset
, yoffset
);
1399 void wxDC::SetTextForeground(const wxColour
& colour
)
1401 m_textForegroundColour
= colour
;
1404 void wxDC::SetTextBackground(const wxColour
& colour
)
1406 m_textBackgroundColour
= colour
;
1409 // For use by wxWindows only, unless custom units are required.
1410 void wxDC::SetLogicalScale(double x
, double y
)
1412 m_logicalScaleX
= x
;
1413 m_logicalScaleY
= y
;
1416 void wxDC::CalcBoundingBox(long x
, long y
)
1418 if (x
< m_minX
) m_minX
= x
;
1419 if (y
< m_minY
) m_minY
= y
;
1420 if (x
> m_maxX
) m_maxX
= x
;
1421 if (y
> m_maxY
) m_maxY
= y
;
1424 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1430 *w
= (m_clipX2
- m_clipX1
) ;
1431 *h
= (m_clipY2
- m_clipY1
) ;
1434 *x
= *y
= *w
= *h
= 0 ;
1437 #if WXWIN_COMPATIBILITY
1438 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1439 float *descent
, float *externalLeading
,
1440 wxFont
*theFont
, bool use16bit
) const
1442 long x1
, y1
, descent1
, externalLeading1
;
1443 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1446 *descent
= descent1
;
1447 if (externalLeading
)
1448 *externalLeading
= externalLeading1
;
1452 int wxDC::GetDepth(void) const
1454 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1459 // Make a 3-point spline
1460 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1462 wxList
*point_list
= new wxList
;
1464 wxPoint
*point1
= new wxPoint
;
1465 point1
->x
= x1
; point1
->y
= y1
;
1466 point_list
->Append((wxObject
*)point1
);
1468 wxPoint
*point2
= new wxPoint
;
1469 point2
->x
= x2
; point2
->y
= y2
;
1470 point_list
->Append((wxObject
*)point2
);
1472 wxPoint
*point3
= new wxPoint
;
1473 point3
->x
= x3
; point3
->y
= y3
;
1474 point_list
->Append((wxObject
*)point3
);
1476 DrawSpline(point_list
);
1478 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1479 wxPoint
*p
= (wxPoint
*)node
->Data();
1485 ////#define wx_round(a) (int)((a)+.5)
1486 //#define wx_round(a) (a)
1488 class wxSpline
: public wxObject
1494 wxSpline(wxList
*list
);
1495 void DeletePoints(void);
1497 // Doesn't delete points
1501 void wxDC::DrawSpline(int n
, wxPoint points
[])
1505 for (i
=0; i
< n
; i
++)
1506 list
.Append((wxObject
*)&points
[i
]);
1507 DrawSpline((wxList
*)&list
);
1510 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1512 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1513 double a3
, double b3
, double a4
, double b4
);
1514 void wx_clear_stack(void);
1515 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1516 double *y3
, double *x4
, double *y4
);
1517 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1518 double x4
, double y4
);
1519 static bool wx_spline_add_point(double x
, double y
);
1520 static void wx_spline_draw_point_array(wxDC
*dc
);
1521 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1523 void wxDC::DrawSpline(wxList
*list
)
1525 wxSpline
spline(list
);
1527 wx_draw_open_spline(this, &spline
);
1531 wxList wx_spline_point_list
;
1533 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1536 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1537 double x1
, y1
, x2
, y2
;
1539 wxNode
*node
= spline
->points
->First();
1540 p
= (wxPoint
*)node
->Data();
1545 node
= node
->Next();
1546 p
= (wxPoint
*)node
->Data();
1550 cx1
= (double)((x1
+ x2
) / 2);
1551 cy1
= (double)((y1
+ y2
) / 2);
1552 cx2
= (double)((cx1
+ x2
) / 2);
1553 cy2
= (double)((cy1
+ y2
) / 2);
1555 wx_spline_add_point(x1
, y1
);
1557 while ((node
= node
->Next()) != NULL
)
1559 p
= (wxPoint
*)node
->Data();
1564 cx4
= (double)(x1
+ x2
) / 2;
1565 cy4
= (double)(y1
+ y2
) / 2;
1566 cx3
= (double)(x1
+ cx4
) / 2;
1567 cy3
= (double)(y1
+ cy4
) / 2;
1569 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1573 cx2
= (double)(cx1
+ x2
) / 2;
1574 cy2
= (double)(cy1
+ y2
) / 2;
1577 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1578 wx_spline_add_point(x2
, y2
);
1580 wx_spline_draw_point_array(dc
);
1584 /********************* CURVES FOR SPLINES *****************************
1586 The following spline drawing routine is from
1588 "An Algorithm for High-Speed Curve Generation"
1589 by George Merrill Chaikin,
1590 Computer Graphics and Image Processing, 3, Academic Press,
1595 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1596 Computer Graphics and Image Processing, 4, Academic Press,
1599 ***********************************************************************/
1601 #define half(z1, z2) ((z1+z2)/2.0)
1604 /* iterative version */
1606 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1609 register double xmid
, ymid
;
1610 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1613 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1615 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1616 xmid
= (double)half(x2
, x3
);
1617 ymid
= (double)half(y2
, y3
);
1618 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1619 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1620 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1621 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1623 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1624 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1625 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1626 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1632 /* utilities used by spline drawing routines */
1635 typedef struct wx_spline_stack_struct
{
1636 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1640 #define SPLINE_STACK_DEPTH 20
1641 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1642 static Stack
*wx_stack_top
;
1643 static int wx_stack_count
;
1645 void wx_clear_stack(void)
1647 wx_stack_top
= wx_spline_stack
;
1651 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1653 wx_stack_top
->x1
= x1
;
1654 wx_stack_top
->y1
= y1
;
1655 wx_stack_top
->x2
= x2
;
1656 wx_stack_top
->y2
= y2
;
1657 wx_stack_top
->x3
= x3
;
1658 wx_stack_top
->y3
= y3
;
1659 wx_stack_top
->x4
= x4
;
1660 wx_stack_top
->y4
= y4
;
1665 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1666 double *x3
, double *y3
, double *x4
, double *y4
)
1668 if (wx_stack_count
== 0)
1672 *x1
= wx_stack_top
->x1
;
1673 *y1
= wx_stack_top
->y1
;
1674 *x2
= wx_stack_top
->x2
;
1675 *y2
= wx_stack_top
->y2
;
1676 *x3
= wx_stack_top
->x3
;
1677 *y3
= wx_stack_top
->y3
;
1678 *x4
= wx_stack_top
->x4
;
1679 *y4
= wx_stack_top
->y4
;
1683 static bool wx_spline_add_point(double x
, double y
)
1685 wxPoint
*point
= new wxPoint
;
1688 wx_spline_point_list
.Append((wxObject
*)point
);
1692 static void wx_spline_draw_point_array(wxDC
*dc
)
1694 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1695 wxNode
*node
= wx_spline_point_list
.First();
1698 wxPoint
*point
= (wxPoint
*)node
->Data();
1701 node
= wx_spline_point_list
.First();
1705 wxSpline::wxSpline(wxList
*list
)
1710 wxSpline::~wxSpline(void)
1714 void wxSpline::DeletePoints(void)
1716 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1718 wxPoint
*point
= (wxPoint
*)node
->Data();
1726 #endif // wxUSE_SPLINES