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
= MM_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
);
258 m_palette
= m_palette
;
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
,(double)(radius
*2.0),(double)(radius
*2)) ;
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__)
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());
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
);
898 ::StartDocA((HDC
) m_hDC
, &docinfo
);
905 DWORD lastError
= GetLastError();
906 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
913 void wxDC::EndDoc(void)
915 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
917 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
920 void wxDC::StartPage(void)
922 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
925 ::StartPage((HDC
) m_hDC
);
928 void wxDC::EndPage(void)
930 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
933 ::EndPage((HDC
) m_hDC
);
936 long wxDC::GetCharHeight(void) const
938 TEXTMETRIC lpTextMetric
;
940 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
942 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
945 long wxDC::GetCharWidth(void) const
947 TEXTMETRIC lpTextMetric
;
949 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
951 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
954 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
955 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
957 wxFont
*fontToUse
= (wxFont
*) theFont
;
959 fontToUse
= (wxFont
*) &m_font
;
964 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
965 GetTextMetrics((HDC
) m_hDC
, &tm
);
967 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
968 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
969 if (descent
) *descent
= tm
.tmDescent
;
970 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
973 void wxDC::SetMapMode(int mode
)
975 m_mappingMode
= mode
;
978 int pixel_height
= 0;
982 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
983 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
984 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
985 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
987 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
992 double mm2pixelsX
= pixel_width
/mm_width
;
993 double mm2pixelsY
= pixel_height
/mm_height
;
999 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1000 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1005 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1006 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1011 m_logicalScaleX
= mm2pixelsX
;
1012 m_logicalScaleY
= mm2pixelsY
;
1017 m_logicalScaleX
= (mm2pixelsX
/10.0);
1018 m_logicalScaleY
= (mm2pixelsY
/10.0);
1024 m_logicalScaleX
= 1.0;
1025 m_logicalScaleY
= 1.0;
1030 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1031 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1033 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1034 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1035 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1036 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1037 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1038 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1041 void wxDC::SetUserScale(double x
, double y
)
1046 SetMapMode(m_mappingMode
);
1049 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1051 m_signX
= xLeftRight
? 1 : -1;
1052 m_signY
= yBottomUp
? -1 : 1;
1054 SetMapMode(m_mappingMode
);
1057 void wxDC::SetSystemScale(double x
, double y
)
1062 SetMapMode(m_mappingMode
);
1065 void wxDC::SetLogicalOrigin(long x
, long y
)
1067 m_logicalOriginX
= x
;
1068 m_logicalOriginY
= y
;
1070 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1073 void wxDC::SetDeviceOrigin(long x
, long y
)
1075 m_deviceOriginX
= x
;
1076 m_deviceOriginY
= y
;
1078 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1081 long wxDC::DeviceToLogicalX(long x
) const
1083 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1086 long wxDC::DeviceToLogicalXRel(long x
) const
1088 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1091 long wxDC::DeviceToLogicalY(long y
) const
1093 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1096 long wxDC::DeviceToLogicalYRel(long y
) const
1098 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1101 long wxDC::LogicalToDeviceX(long x
) const
1103 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1106 long wxDC::LogicalToDeviceXRel(long x
) const
1108 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1111 long wxDC::LogicalToDeviceY(long y
) const
1113 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1116 long wxDC::LogicalToDeviceYRel(long y
) const
1118 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1121 // This group of functions may not do any conversion
1122 // if m_scaleGDI is TRUE, since the HDC does the
1123 // conversion automatically.
1125 long wxDC::ImplDeviceToLogicalX(long x
) const
1127 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1131 long wxDC::ImplDeviceToLogicalY(long y
) const
1133 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1137 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1139 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1143 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1145 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1149 long wxDC::ImplLogicalToDeviceX(long x
) const
1151 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1155 long wxDC::ImplLogicalToDeviceY(long y
) const
1157 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1161 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1163 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1167 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1169 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1173 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1174 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1176 long xdest1
= xdest
;
1177 long ydest1
= ydest
;
1181 // Chris Breeze 18/5/98: use text foreground/background colours
1182 // when blitting from 1-bit bitmaps
1183 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1184 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1185 if (m_textForegroundColour
.Ok())
1187 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1189 if (m_textBackgroundColour
.Ok())
1191 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1194 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1195 rop
== wxCLEAR
? WHITENESS
:
1196 rop
== wxSET
? BLACKNESS
:
1197 rop
== wxINVERT
? DSTINVERT
:
1198 rop
== wxAND
? MERGECOPY
:
1199 rop
== wxOR
? MERGEPAINT
:
1200 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1201 rop
== wxXOR
? SRCINVERT
:
1202 rop
== wxOR_REVERSE
? MERGEPAINT
:
1203 rop
== wxAND_REVERSE
? SRCERASE
:
1204 rop
== wxSRC_OR
? SRCPAINT
:
1205 rop
== wxSRC_AND
? SRCAND
:
1208 bool success
= TRUE
;
1209 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1213 // Not implemented under Win95 (or maybe a specific device?)
1214 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1215 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1225 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1226 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1227 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1228 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1229 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1230 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1231 ::SelectObject(dc_mask
, 0);
1232 ::DeleteDC(dc_mask
);
1234 // New code from Chris Breeze, 15/7/98
1235 // Blit bitmap with mask
1237 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1239 // If we are printing source colours are screen colours
1240 // not printer colours and so we need copy the bitmap
1243 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1244 HDC dc_src
= (HDC
) source
->m_hDC
;
1246 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1247 for (int x
= 0; x
< width
; x
++)
1249 for (int y
= 0; y
< height
; y
++)
1251 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1254 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1255 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1256 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1257 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1258 ::DeleteObject(brush
);
1262 ::SelectObject(dc_mask
, 0);
1263 ::DeleteDC(dc_mask
);
1267 // create a temp buffer bitmap and DCs to access it and the mask
1268 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1269 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1270 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1271 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1272 ::SelectObject(dc_buffer
, buffer_bmap
);
1274 // copy dest to buffer
1275 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1276 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1278 // copy src to buffer using selected raster op
1279 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1280 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1282 // set masked area in buffer to BLACK (pixel value 0)
1283 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1284 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1285 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1286 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1288 // set unmasked area in dest to BLACK
1289 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1290 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1291 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1292 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1293 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1294 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1296 // OR buffer to dest
1297 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1298 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1300 // tidy up temporary DCs and bitmap
1301 ::SelectObject(dc_mask
, 0);
1302 ::DeleteDC(dc_mask
);
1303 ::SelectObject(dc_buffer
, 0);
1304 ::DeleteDC(dc_buffer
);
1305 ::DeleteObject(buffer_bmap
);
1311 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1313 // If we are printing, source colours are screen colours
1314 // not printer colours and so we need copy the bitmap
1316 HDC dc_src
= (HDC
) source
->m_hDC
;
1318 for (int x
= 0; x
< width
; x
++)
1320 for (int y
= 0; y
< height
; y
++)
1322 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1323 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1324 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1325 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1326 ::DeleteObject(brush
);
1332 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1333 xsrc1
, ysrc1
, dwRop
) != 0);
1336 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1337 ::SetBkColor((HDC
)m_hDC
, old_background
);
1342 void wxDC::GetSize(int* width
, int* height
) const
1344 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1345 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1350 void wxDC::GetSizeMM(long *width
, long *height
) const
1352 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1353 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1358 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1360 int n
= list
->Number();
1361 wxPoint
*points
= new wxPoint
[n
];
1364 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1365 wxPoint
*point
= (wxPoint
*)node
->Data();
1366 points
[i
].x
= point
->x
;
1367 points
[i
++].y
= point
->y
;
1369 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1373 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1375 int n
= list
->Number();
1376 wxPoint
*points
= new wxPoint
[n
];
1379 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1380 wxPoint
*point
= (wxPoint
*)node
->Data();
1381 points
[i
].x
= point
->x
;
1382 points
[i
++].y
= point
->y
;
1384 DrawLines(n
, points
, xoffset
, yoffset
);
1388 void wxDC::SetTextForeground(const wxColour
& colour
)
1390 m_textForegroundColour
= colour
;
1393 void wxDC::SetTextBackground(const wxColour
& colour
)
1395 m_textBackgroundColour
= colour
;
1398 // For use by wxWindows only, unless custom units are required.
1399 void wxDC::SetLogicalScale(double x
, double y
)
1401 m_logicalScaleX
= x
;
1402 m_logicalScaleY
= y
;
1405 void wxDC::CalcBoundingBox(long x
, long y
)
1407 if (x
< m_minX
) m_minX
= x
;
1408 if (y
< m_minY
) m_minY
= y
;
1409 if (x
> m_maxX
) m_maxX
= x
;
1410 if (y
> m_maxY
) m_maxY
= y
;
1413 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1419 *w
= (m_clipX2
- m_clipX1
) ;
1420 *h
= (m_clipY2
- m_clipY1
) ;
1423 *x
= *y
= *w
= *h
= 0 ;
1426 #if WXWIN_COMPATIBILITY
1427 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1428 float *descent
, float *externalLeading
,
1429 wxFont
*theFont
, bool use16bit
) const
1431 long x1
, y1
, descent1
, externalLeading1
;
1432 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1435 *descent
= descent1
;
1436 if (externalLeading
)
1437 *externalLeading
= externalLeading1
;
1441 int wxDC::GetDepth(void) const
1443 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1448 // Make a 3-point spline
1449 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1451 wxList
*point_list
= new wxList
;
1453 wxPoint
*point1
= new wxPoint
;
1454 point1
->x
= x1
; point1
->y
= y1
;
1455 point_list
->Append((wxObject
*)point1
);
1457 wxPoint
*point2
= new wxPoint
;
1458 point2
->x
= x2
; point2
->y
= y2
;
1459 point_list
->Append((wxObject
*)point2
);
1461 wxPoint
*point3
= new wxPoint
;
1462 point3
->x
= x3
; point3
->y
= y3
;
1463 point_list
->Append((wxObject
*)point3
);
1465 DrawSpline(point_list
);
1467 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1468 wxPoint
*p
= (wxPoint
*)node
->Data();
1474 ////#define wx_round(a) (int)((a)+.5)
1475 //#define wx_round(a) (a)
1477 class wxSpline
: public wxObject
1483 wxSpline(wxList
*list
);
1484 void DeletePoints(void);
1486 // Doesn't delete points
1490 void wxDC::DrawSpline(int n
, wxPoint points
[])
1494 for (i
=0; i
< n
; i
++)
1495 list
.Append((wxObject
*)&points
[i
]);
1496 DrawSpline((wxList
*)&list
);
1499 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1501 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1502 double a3
, double b3
, double a4
, double b4
);
1503 void wx_clear_stack(void);
1504 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1505 double *y3
, double *x4
, double *y4
);
1506 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1507 double x4
, double y4
);
1508 static bool wx_spline_add_point(double x
, double y
);
1509 static void wx_spline_draw_point_array(wxDC
*dc
);
1510 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1512 void wxDC::DrawSpline(wxList
*list
)
1514 wxSpline
spline(list
);
1516 wx_draw_open_spline(this, &spline
);
1520 wxList wx_spline_point_list
;
1522 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1525 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1526 double x1
, y1
, x2
, y2
;
1528 wxNode
*node
= spline
->points
->First();
1529 p
= (wxPoint
*)node
->Data();
1534 node
= node
->Next();
1535 p
= (wxPoint
*)node
->Data();
1539 cx1
= (double)((x1
+ x2
) / 2);
1540 cy1
= (double)((y1
+ y2
) / 2);
1541 cx2
= (double)((cx1
+ x2
) / 2);
1542 cy2
= (double)((cy1
+ y2
) / 2);
1544 wx_spline_add_point(x1
, y1
);
1546 while ((node
= node
->Next()) != NULL
)
1548 p
= (wxPoint
*)node
->Data();
1553 cx4
= (double)(x1
+ x2
) / 2;
1554 cy4
= (double)(y1
+ y2
) / 2;
1555 cx3
= (double)(x1
+ cx4
) / 2;
1556 cy3
= (double)(y1
+ cy4
) / 2;
1558 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1562 cx2
= (double)(cx1
+ x2
) / 2;
1563 cy2
= (double)(cy1
+ y2
) / 2;
1566 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1567 wx_spline_add_point(x2
, y2
);
1569 wx_spline_draw_point_array(dc
);
1573 /********************* CURVES FOR SPLINES *****************************
1575 The following spline drawing routine is from
1577 "An Algorithm for High-Speed Curve Generation"
1578 by George Merrill Chaikin,
1579 Computer Graphics and Image Processing, 3, Academic Press,
1584 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1585 Computer Graphics and Image Processing, 4, Academic Press,
1588 ***********************************************************************/
1590 #define half(z1, z2) ((z1+z2)/2.0)
1593 /* iterative version */
1595 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1598 register double xmid
, ymid
;
1599 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1602 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1604 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1605 xmid
= (double)half(x2
, x3
);
1606 ymid
= (double)half(y2
, y3
);
1607 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1608 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1609 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1610 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1612 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1613 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1614 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1615 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1621 /* utilities used by spline drawing routines */
1624 typedef struct wx_spline_stack_struct
{
1625 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1629 #define SPLINE_STACK_DEPTH 20
1630 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1631 static Stack
*wx_stack_top
;
1632 static int wx_stack_count
;
1634 void wx_clear_stack(void)
1636 wx_stack_top
= wx_spline_stack
;
1640 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1642 wx_stack_top
->x1
= x1
;
1643 wx_stack_top
->y1
= y1
;
1644 wx_stack_top
->x2
= x2
;
1645 wx_stack_top
->y2
= y2
;
1646 wx_stack_top
->x3
= x3
;
1647 wx_stack_top
->y3
= y3
;
1648 wx_stack_top
->x4
= x4
;
1649 wx_stack_top
->y4
= y4
;
1654 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1655 double *x3
, double *y3
, double *x4
, double *y4
)
1657 if (wx_stack_count
== 0)
1661 *x1
= wx_stack_top
->x1
;
1662 *y1
= wx_stack_top
->y1
;
1663 *x2
= wx_stack_top
->x2
;
1664 *y2
= wx_stack_top
->y2
;
1665 *x3
= wx_stack_top
->x3
;
1666 *y3
= wx_stack_top
->y3
;
1667 *x4
= wx_stack_top
->x4
;
1668 *y4
= wx_stack_top
->y4
;
1672 static bool wx_spline_add_point(double x
, double y
)
1674 wxPoint
*point
= new wxPoint
;
1677 wx_spline_point_list
.Append((wxObject
*)point
);
1681 static void wx_spline_draw_point_array(wxDC
*dc
)
1683 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1684 wxNode
*node
= wx_spline_point_list
.First();
1687 wxPoint
*point
= (wxPoint
*)node
->Data();
1690 node
= wx_spline_point_list
.First();
1694 wxSpline::wxSpline(wxList
*list
)
1699 wxSpline::~wxSpline(void)
1703 void wxSpline::DeletePoints(void)
1705 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1707 wxPoint
*point
= (wxPoint
*)node
->Data();
1715 #endif // wxUSE_SPLINES