1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dc.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/dialog.h"
31 #include "wx/dcprint.h"
32 #include "wx/msw/private.h"
37 #if wxUSE_COMMON_DIALOGS
57 #if !USE_SHARED_LIBRARY
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
61 // Declarations local to this file
63 #define YSCALE(y) (yorigin - (y))
65 // #define wx_round(a) (int)((a)+.5)
67 // Default constructor
70 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
80 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
85 m_logicalScaleX
= 1.0;
86 m_logicalScaleY
= 1.0;
93 m_mappingMode
= MM_TEXT
;
98 m_windowExtX
= VIEWPORT_EXTENT
;
99 m_windowExtY
= VIEWPORT_EXTENT
;
100 m_logicalFunction
= -1;
102 m_backgroundBrush
= *wxWHITE_BRUSH
;
104 m_textForegroundColour
= *wxBLACK
;
105 m_textBackgroundColour
= *wxWHITE
;
107 m_colour
= wxColourDisplay();
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC((HDC
)m_hDC
);
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
127 // This will select current objects out of the DC,
128 // which is what you have to do before deleting the
130 void wxDC::SelectOldObjects(WXHDC dc
)
136 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
137 if (m_selectedBitmap
.Ok())
139 m_selectedBitmap
.SetSelectedInto(NULL
);
145 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
150 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
155 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
160 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
165 m_brush
= wxNullBrush
;
167 m_palette
= wxNullPalette
;
169 m_backgroundBrush
= wxNullBrush
;
170 m_selectedBitmap
= wxNullBitmap
;
173 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
178 m_clipX2
= (int)(cx
+ cw
);
179 m_clipY2
= (int)(cy
+ ch
);
181 DoClipping((WXHDC
) m_hDC
);
184 void wxDC::SetClippingRegion(const wxRegion
& region
)
186 if (!region
.GetHRGN())
189 wxRect box
= region
.GetBox();
194 m_clipX2
= box
.x
+ box
.width
;
195 m_clipY2
= box
.y
+ box
.height
;
197 ExtSelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN(), RGN_AND
);
200 void wxDC::DoClipping(WXHDC dc
)
202 if (m_clipping
&& dc
)
204 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
205 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
209 void wxDC::DestroyClippingRegion(void)
211 if (m_clipping
&& m_hDC
)
213 // TODO: this should restore the previous clipping region,
214 // so that OnPaint processing works correctly, and the update clipping region
215 // doesn't get destroyed after the first DestroyClippingRegion.
216 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
217 SelectClipRgn((HDC
) m_hDC
, rgn
);
223 bool wxDC::CanDrawBitmap(void) const
228 bool wxDC::CanGetTextExtent(void) const
230 // What sort of display is it?
231 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
235 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
242 void wxDC::SetPalette(const wxPalette
& palette
)
244 // Set the old object temporarily, in case the assignment deletes an object
245 // that's not yet selected out.
248 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
252 m_palette
= m_palette
;
256 // Setting a NULL colourmap is a way of restoring
257 // the original colourmap
260 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
267 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
269 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
271 m_oldPalette
= (WXHPALETTE
) oldPal
;
273 ::RealizePalette((HDC
) m_hDC
);
277 void wxDC::Clear(void)
281 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
282 else if (m_selectedBitmap
.Ok())
284 rect
.left
= 0; rect
.top
= 0;
285 rect
.right
= m_selectedBitmap
.GetWidth();
286 rect
.bottom
= m_selectedBitmap
.GetHeight();
288 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
290 DWORD colour
= GetBkColor((HDC
) m_hDC
);
291 HBRUSH brush
= CreateSolidBrush(colour
);
292 FillRect((HDC
) m_hDC
, &rect
, brush
);
295 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
296 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
297 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
298 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
299 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
302 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
304 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
306 style
==wxFLOOD_SURFACE
?
307 FLOODFILLSURFACE
:FLOODFILLBORDER
310 CalcBoundingBox(x
, y
);
313 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
315 // added by steve 29.12.94 (copied from DrawPoint)
316 // returns TRUE for pixels in the color of the current pen
317 // and FALSE for all other pixels colors
318 // if col is non-NULL return the color of the pixel
320 // get the color of the pixel
321 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
322 // get the color of the pen
323 COLORREF pencolor
= 0x00ffffff;
326 pencolor
= m_pen
.GetColour().GetPixel() ;
329 // return the color of the pixel
331 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
333 // check, if color of the pixels is the same as the color
334 // of the current pen
335 return(pixelcolor
==pencolor
);
338 void wxDC::CrossHair(long x
, long y
)
340 // We suppose that our screen is 2000x2000 max.
346 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
347 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
349 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
350 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
352 CalcBoundingBox(x1
, y1
);
353 CalcBoundingBox(x2
, y2
);
356 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
358 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
359 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
361 /* MATTHEW: [6] New normalization */
362 #if WX_STANDARD_GRAPHICS
363 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
366 CalcBoundingBox(x1
, y1
);
367 CalcBoundingBox(x2
, y2
);
370 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
374 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
375 if (x1
==x2
&& x2
==y2
)
377 DrawEllipse(xc
,yc
,(double)(radius
*2.0),(double)(radius
*2)) ;
381 long xx1
= XLOG2DEV(x1
) ;
382 long yy1
= YLOG2DEV(y1
) ;
383 long xx2
= XLOG2DEV(x2
) ;
384 long yy2
= YLOG2DEV(y2
) ;
385 long xxc
= XLOG2DEV(xc
) ;
386 long yyc
= YLOG2DEV(yc
) ;
387 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
389 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
390 long xxx1
= (long) (xxc
-ray
);
391 long yyy1
= (long) (yyc
-ray
);
392 long xxx2
= (long) (xxc
+ray
);
393 long yyy2
= (long) (yyc
+ray
);
394 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
396 // Have to add 1 to bottom-right corner of rectangle
397 // to make semi-circles look right (crooked line otherwise).
398 // Unfortunately this is not a reliable method, depends
399 // on the size of shape.
400 // TODO: figure out why this happens!
401 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
405 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
408 CalcBoundingBox((xc
-radius
), (yc
-radius
));
409 CalcBoundingBox((xc
+radius
), (yc
+radius
));
412 void wxDC::DrawPoint(long x
, long y
)
414 COLORREF color
= 0x00ffffff;
417 color
= m_pen
.GetColour().GetPixel() ;
420 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
422 CalcBoundingBox(x
, y
);
425 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
427 // Do things less efficiently if we have offsets
428 if (xoffset
!= 0 || yoffset
!= 0)
430 POINT
*cpoints
= new POINT
[n
];
432 for (i
= 0; i
< n
; i
++)
434 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
435 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
437 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
439 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
440 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
441 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
447 for (i
= 0; i
< n
; i
++)
448 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
450 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
451 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
452 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
456 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
458 // Do things less efficiently if we have offsets
459 if (xoffset
!= 0 || yoffset
!= 0)
461 POINT
*cpoints
= new POINT
[n
];
463 for (i
= 0; i
< n
; i
++)
465 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
466 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
468 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
470 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
476 for (i
= 0; i
< n
; i
++)
477 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
479 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
483 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
486 long y2
= y
+ height
;
488 /* MATTHEW: [6] new normalization */
489 #if WX_STANDARD_GRAPHICS
490 bool do_brush
, do_pen
;
492 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
493 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
496 HPEN orig_pen
= NULL
;
498 if (do_pen
|| !m_pen
.Ok())
499 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
501 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
502 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
504 if (do_pen
|| !m_pen
.Ok())
505 ::SelectObject((HDC
) m_hDC
, orig_pen
);
508 HBRUSH orig_brush
= NULL
;
510 if (do_brush
|| !m_brush
.Ok())
511 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
513 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
514 XLOG2DEV(x2
), YLOG2DEV(y2
));
516 if (do_brush
|| !m_brush
.Ok())
517 ::SelectObject((HDC
) m_hDC
, orig_brush
);
520 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
523 CalcBoundingBox(x
, y
);
524 CalcBoundingBox(x2
, y2
);
527 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
529 // Now, a negative radius value is interpreted to mean
530 // 'the proportion of the smallest X or Y dimension'
534 double smallest
= 0.0;
539 radius
= (- radius
* smallest
);
543 long y2
= (y
+height
);
545 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
546 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
548 CalcBoundingBox(x
, y
);
549 CalcBoundingBox(x2
, y2
);
552 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
555 long y2
= (y
+height
);
557 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
559 CalcBoundingBox(x
, y
);
560 CalcBoundingBox(x2
, y2
);
563 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
564 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
569 const double deg2rad
= 3.14159265359 / 180.0;
570 int rx1
= XLOG2DEV(x
+w
/2);
571 int ry1
= YLOG2DEV(y
+h
/2);
574 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
575 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
576 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
577 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
579 // draw pie with NULL_PEN first and then outline otherwise a line is
580 // drawn from the start and end points to the centre
581 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
584 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
589 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
590 rx1
, ry1
-1, rx2
, ry2
-1);
592 ::SelectObject((HDC
) m_hDC
, orig_pen
);
593 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
596 CalcBoundingBox(x
, y
);
597 CalcBoundingBox(x2
, y2
);
600 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
602 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
603 CalcBoundingBox(x
, y
);
604 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
607 void wxDC::SetFont(const wxFont
& the_font
)
609 // Set the old object temporarily, in case the assignment deletes an object
610 // that's not yet selected out.
613 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
622 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
626 if (m_font
.Ok() && m_font
.GetResourceHandle())
628 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
631 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
634 m_oldFont
= (WXHFONT
) f
;
638 void wxDC::SetPen(const wxPen
& pen
)
640 // Set the old object temporarily, in case the assignment deletes an object
641 // that's not yet selected out.
644 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
653 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
659 if (m_pen
.GetResourceHandle())
661 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
663 m_oldPen
= (WXHPEN
) p
;
668 void wxDC::SetBrush(const wxBrush
& brush
)
670 // Set the old object temporarily, in case the assignment deletes an object
671 // that's not yet selected out.
674 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
683 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
689 if (m_brush
.GetResourceHandle())
692 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
694 m_oldBrush
= (WXHBRUSH
) b
;
699 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
701 // Should be unnecessary: SetFont should have done this already.
703 if (m_font
.Ok() && m_font
.GetResourceHandle())
705 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
707 m_oldFont
= (WXHFONT
) f
;
711 if (m_textForegroundColour
.Ok())
712 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
714 DWORD old_background
= 0;
715 if (m_textBackgroundColour
.Ok())
717 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
720 if (m_backgroundMode
== wxTRANSPARENT
)
721 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
723 SetBkMode((HDC
) m_hDC
, OPAQUE
);
725 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
727 if (m_textBackgroundColour
.Ok())
728 (void)SetBkColor((HDC
) m_hDC
, old_background
);
730 CalcBoundingBox(x
, y
);
733 GetTextExtent(text
, &w
, &h
);
734 CalcBoundingBox((x
+ w
), (y
+ h
));
737 void wxDC::SetBackground(const wxBrush
& brush
)
739 m_backgroundBrush
= brush
;
741 if (!m_backgroundBrush
.Ok())
746 bool customColours
= TRUE
;
747 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
748 // change background colours from the control-panel specified colours.
749 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
750 customColours
= FALSE
;
754 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
756 m_canvas
->m_backgroundTransparent
= TRUE
;
760 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
761 m_canvas
->m_backgroundTransparent
= FALSE
;
765 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
767 (void)SetBkColor((HDC
) m_hDC
, new_color
);
771 void wxDC::SetBackgroundMode(int mode
)
773 m_backgroundMode
= mode
;
775 if (m_backgroundMode
== wxTRANSPARENT
)
776 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
778 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
781 void wxDC::SetLogicalFunction(int function
)
783 m_logicalFunction
= function
;
785 SetRop((WXHDC
) m_hDC
);
788 void wxDC::SetRop(WXHDC dc
)
790 if (!dc
|| m_logicalFunction
< 0)
794 // These may be wrong
795 switch (m_logicalFunction
)
797 // case wxXOR: c_rop = R2_XORPEN; break;
798 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
799 case wxINVERT
: c_rop
= R2_NOT
; break;
800 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
801 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
802 case wxCLEAR
: c_rop
= R2_WHITE
; break;
803 case wxSET
: c_rop
= R2_BLACK
; break;
804 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
805 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
806 case wxAND
: c_rop
= R2_MASKPEN
; break;
807 case wxOR
: c_rop
= R2_MERGEPEN
; break;
808 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
813 c_rop
= R2_COPYPEN
; break;
815 SetROP2((HDC
) dc
, c_rop
);
818 bool wxDC::StartDoc(const wxString
& message
)
820 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
824 docinfo
.cbSize
= sizeof(DOCINFO
);
825 docinfo
.lpszDocName
= (const char *)message
;
827 if (m_filename
.IsEmpty())
828 docinfo
.lpszOutput
= NULL
;
830 docinfo
.lpszOutput
= (const char *)m_filename
;
832 #if defined(__WIN95__)
833 docinfo
.lpszDatatype
= NULL
;
842 ::StartDoc((HDC
) m_hDC
, &docinfo
);
845 ::StartDocW((HDC
) m_hDC
, &docinfo
);
847 ::StartDocA((HDC
) m_hDC
, &docinfo
);
853 DWORD lastError
= GetLastError();
854 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
859 void wxDC::EndDoc(void)
861 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
863 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
866 void wxDC::StartPage(void)
868 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
871 ::StartPage((HDC
) m_hDC
);
874 void wxDC::EndPage(void)
876 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
879 ::EndPage((HDC
) m_hDC
);
882 long wxDC::GetCharHeight(void) const
884 TEXTMETRIC lpTextMetric
;
886 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
888 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
891 long wxDC::GetCharWidth(void) const
893 TEXTMETRIC lpTextMetric
;
895 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
897 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
900 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
901 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
903 wxFont
*fontToUse
= (wxFont
*) theFont
;
905 fontToUse
= (wxFont
*) &m_font
;
910 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
911 GetTextMetrics((HDC
) m_hDC
, &tm
);
913 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
914 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
915 if (descent
) *descent
= tm
.tmDescent
;
916 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
919 void wxDC::SetMapMode(int mode
)
921 m_mappingMode
= mode
;
924 int pixel_height
= 0;
928 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
929 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
930 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
931 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
933 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
938 double mm2pixelsX
= pixel_width
/mm_width
;
939 double mm2pixelsY
= pixel_height
/mm_height
;
945 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
946 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
951 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
952 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
957 m_logicalScaleX
= mm2pixelsX
;
958 m_logicalScaleY
= mm2pixelsY
;
963 m_logicalScaleX
= (mm2pixelsX
/10.0);
964 m_logicalScaleY
= (mm2pixelsY
/10.0);
970 m_logicalScaleX
= 1.0;
971 m_logicalScaleY
= 1.0;
976 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
977 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
979 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
980 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
981 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
982 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
983 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
984 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
987 void wxDC::SetUserScale(double x
, double y
)
992 SetMapMode(m_mappingMode
);
995 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
997 m_signX
= xLeftRight
? 1 : -1;
998 m_signY
= yBottomUp
? -1 : 1;
1000 SetMapMode(m_mappingMode
);
1003 void wxDC::SetSystemScale(double x
, double y
)
1008 SetMapMode(m_mappingMode
);
1011 void wxDC::SetLogicalOrigin(long x
, long y
)
1013 m_logicalOriginX
= x
;
1014 m_logicalOriginY
= y
;
1016 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1019 void wxDC::SetDeviceOrigin(long x
, long y
)
1021 m_deviceOriginX
= x
;
1022 m_deviceOriginY
= y
;
1024 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1027 long wxDC::DeviceToLogicalX(long x
) const
1029 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1032 long wxDC::DeviceToLogicalXRel(long x
) const
1034 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1037 long wxDC::DeviceToLogicalY(long y
) const
1039 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1042 long wxDC::DeviceToLogicalYRel(long y
) const
1044 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1047 long wxDC::LogicalToDeviceX(long x
) const
1049 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1052 long wxDC::LogicalToDeviceXRel(long x
) const
1054 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1057 long wxDC::LogicalToDeviceY(long y
) const
1059 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1062 long wxDC::LogicalToDeviceYRel(long y
) const
1064 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1067 // This group of functions may not do any conversion
1068 // if m_scaleGDI is TRUE, since the HDC does the
1069 // conversion automatically.
1071 long wxDC::ImplDeviceToLogicalX(long x
) const
1073 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1077 long wxDC::ImplDeviceToLogicalY(long y
) const
1079 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1083 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1085 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1089 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1091 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1095 long wxDC::ImplLogicalToDeviceX(long x
) const
1097 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1101 long wxDC::ImplLogicalToDeviceY(long y
) const
1103 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1107 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1109 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1113 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1115 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1119 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1120 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1122 long xdest1
= xdest
;
1123 long ydest1
= ydest
;
1127 // Chris Breeze 18/5/98: use text foreground/background colours
1128 // when blitting from 1-bit bitmaps
1129 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1130 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1131 if (m_textForegroundColour
.Ok())
1133 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1135 if (m_textBackgroundColour
.Ok())
1137 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1140 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1141 rop
== wxCLEAR
? WHITENESS
:
1142 rop
== wxSET
? BLACKNESS
:
1143 rop
== wxINVERT
? DSTINVERT
:
1144 rop
== wxAND
? MERGECOPY
:
1145 rop
== wxOR
? MERGEPAINT
:
1146 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1147 rop
== wxXOR
? SRCINVERT
:
1148 rop
== wxOR_REVERSE
? MERGEPAINT
:
1149 rop
== wxAND_REVERSE
? SRCERASE
:
1150 rop
== wxSRC_OR
? SRCPAINT
:
1151 rop
== wxSRC_AND
? SRCAND
:
1154 bool success
= TRUE
;
1155 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1159 // Not implemented under Win95 (or maybe a specific device?)
1160 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1161 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1171 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1172 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1173 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1174 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1175 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1176 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1177 ::SelectObject(dc_mask
, 0);
1178 ::DeleteDC(dc_mask
);
1180 // New code from Chris Breeze, 15/7/98
1181 // Blit bitmap with mask
1183 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1185 // If we are printing source colours are screen colours
1186 // not printer colours and so we need copy the bitmap
1189 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1190 HDC dc_src
= (HDC
) source
->m_hDC
;
1192 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1193 for (int x
= 0; x
< width
; x
++)
1195 for (int y
= 0; y
< height
; y
++)
1197 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1200 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1201 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1202 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1203 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1204 ::DeleteObject(brush
);
1208 ::SelectObject(dc_mask
, 0);
1209 ::DeleteDC(dc_mask
);
1213 // create a temp buffer bitmap and DCs to access it and the mask
1214 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1215 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1216 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1217 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1218 ::SelectObject(dc_buffer
, buffer_bmap
);
1220 // copy dest to buffer
1221 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1222 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1224 // copy src to buffer using selected raster op
1225 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1226 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1228 // set masked area in buffer to BLACK (pixel value 0)
1229 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1230 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1231 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1232 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1234 // set unmasked area in dest to BLACK
1235 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1236 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1237 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1238 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1239 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1240 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1242 // OR buffer to dest
1243 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1244 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1246 // tidy up temporary DCs and bitmap
1247 ::SelectObject(dc_mask
, 0);
1248 ::DeleteDC(dc_mask
);
1249 ::SelectObject(dc_buffer
, 0);
1250 ::DeleteDC(dc_buffer
);
1251 ::DeleteObject(buffer_bmap
);
1257 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1259 // If we are printing source colours are screen colours
1260 // not printer colours and so we need copy the bitmap
1262 HDC dc_src
= (HDC
) source
->m_hDC
;
1264 for (int x
= 0; x
< width
; x
++)
1266 for (int y
= 0; y
< height
; y
++)
1268 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1269 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1270 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1271 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1272 ::DeleteObject(brush
);
1278 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1279 xsrc1
, ysrc1
, dwRop
) != 0);
1282 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1283 ::SetBkColor((HDC
)m_hDC
, old_background
);
1288 void wxDC::GetSize(int* width
, int* height
) const
1290 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1291 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1296 void wxDC::GetSizeMM(long *width
, long *height
) const
1298 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1299 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1304 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1306 int n
= list
->Number();
1307 wxPoint
*points
= new wxPoint
[n
];
1310 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1311 wxPoint
*point
= (wxPoint
*)node
->Data();
1312 points
[i
].x
= point
->x
;
1313 points
[i
++].y
= point
->y
;
1315 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1319 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1321 int n
= list
->Number();
1322 wxPoint
*points
= new wxPoint
[n
];
1325 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1326 wxPoint
*point
= (wxPoint
*)node
->Data();
1327 points
[i
].x
= point
->x
;
1328 points
[i
++].y
= point
->y
;
1330 DrawLines(n
, points
, xoffset
, yoffset
);
1334 void wxDC::SetTextForeground(const wxColour
& colour
)
1336 m_textForegroundColour
= colour
;
1339 void wxDC::SetTextBackground(const wxColour
& colour
)
1341 m_textBackgroundColour
= colour
;
1344 // For use by wxWindows only, unless custom units are required.
1345 void wxDC::SetLogicalScale(double x
, double y
)
1347 m_logicalScaleX
= x
;
1348 m_logicalScaleY
= y
;
1351 void wxDC::CalcBoundingBox(long x
, long y
)
1353 if (x
< m_minX
) m_minX
= x
;
1354 if (y
< m_minY
) m_minY
= y
;
1355 if (x
> m_maxX
) m_maxX
= x
;
1356 if (y
> m_maxY
) m_maxY
= y
;
1359 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1365 *w
= (m_clipX2
- m_clipX1
) ;
1366 *h
= (m_clipY2
- m_clipY1
) ;
1369 *x
= *y
= *w
= *h
= 0 ;
1372 #if WXWIN_COMPATIBILITY
1373 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1374 float *descent
, float *externalLeading
,
1375 wxFont
*theFont
, bool use16bit
) const
1377 long x1
, y1
, descent1
, externalLeading1
;
1378 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1381 *descent
= descent1
;
1382 if (externalLeading
)
1383 *externalLeading
= externalLeading1
;
1387 int wxDC::GetDepth(void) const
1389 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1394 // Make a 3-point spline
1395 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1397 wxList
*point_list
= new wxList
;
1399 wxPoint
*point1
= new wxPoint
;
1400 point1
->x
= x1
; point1
->y
= y1
;
1401 point_list
->Append((wxObject
*)point1
);
1403 wxPoint
*point2
= new wxPoint
;
1404 point2
->x
= x2
; point2
->y
= y2
;
1405 point_list
->Append((wxObject
*)point2
);
1407 wxPoint
*point3
= new wxPoint
;
1408 point3
->x
= x3
; point3
->y
= y3
;
1409 point_list
->Append((wxObject
*)point3
);
1411 DrawSpline(point_list
);
1413 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1414 wxPoint
*p
= (wxPoint
*)node
->Data();
1420 ////#define wx_round(a) (int)((a)+.5)
1421 //#define wx_round(a) (a)
1423 class wxSpline
: public wxObject
1429 wxSpline(wxList
*list
);
1430 void DeletePoints(void);
1432 // Doesn't delete points
1436 void wxDC::DrawSpline(int n
, wxPoint points
[])
1440 for (i
=0; i
< n
; i
++)
1441 list
.Append((wxObject
*)&points
[i
]);
1442 DrawSpline((wxList
*)&list
);
1445 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1447 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1448 double a3
, double b3
, double a4
, double b4
);
1449 void wx_clear_stack(void);
1450 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1451 double *y3
, double *x4
, double *y4
);
1452 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1453 double x4
, double y4
);
1454 static bool wx_spline_add_point(double x
, double y
);
1455 static void wx_spline_draw_point_array(wxDC
*dc
);
1456 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1458 void wxDC::DrawSpline(wxList
*list
)
1460 wxSpline
spline(list
);
1462 wx_draw_open_spline(this, &spline
);
1466 wxList wx_spline_point_list
;
1468 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1471 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1472 double x1
, y1
, x2
, y2
;
1474 wxNode
*node
= spline
->points
->First();
1475 p
= (wxPoint
*)node
->Data();
1480 node
= node
->Next();
1481 p
= (wxPoint
*)node
->Data();
1485 cx1
= (double)((x1
+ x2
) / 2);
1486 cy1
= (double)((y1
+ y2
) / 2);
1487 cx2
= (double)((cx1
+ x2
) / 2);
1488 cy2
= (double)((cy1
+ y2
) / 2);
1490 wx_spline_add_point(x1
, y1
);
1492 while ((node
= node
->Next()) != NULL
)
1494 p
= (wxPoint
*)node
->Data();
1499 cx4
= (double)(x1
+ x2
) / 2;
1500 cy4
= (double)(y1
+ y2
) / 2;
1501 cx3
= (double)(x1
+ cx4
) / 2;
1502 cy3
= (double)(y1
+ cy4
) / 2;
1504 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1508 cx2
= (double)(cx1
+ x2
) / 2;
1509 cy2
= (double)(cy1
+ y2
) / 2;
1512 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1513 wx_spline_add_point(x2
, y2
);
1515 wx_spline_draw_point_array(dc
);
1519 /********************* CURVES FOR SPLINES *****************************
1521 The following spline drawing routine is from
1523 "An Algorithm for High-Speed Curve Generation"
1524 by George Merrill Chaikin,
1525 Computer Graphics and Image Processing, 3, Academic Press,
1530 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1531 Computer Graphics and Image Processing, 4, Academic Press,
1534 ***********************************************************************/
1536 #define half(z1, z2) ((z1+z2)/2.0)
1539 /* iterative version */
1541 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1544 register double xmid
, ymid
;
1545 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1548 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1550 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1551 xmid
= (double)half(x2
, x3
);
1552 ymid
= (double)half(y2
, y3
);
1553 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1554 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1555 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1556 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1558 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1559 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1560 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1561 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1567 /* utilities used by spline drawing routines */
1570 typedef struct wx_spline_stack_struct
{
1571 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1575 #define SPLINE_STACK_DEPTH 20
1576 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1577 static Stack
*wx_stack_top
;
1578 static int wx_stack_count
;
1580 void wx_clear_stack(void)
1582 wx_stack_top
= wx_spline_stack
;
1586 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1588 wx_stack_top
->x1
= x1
;
1589 wx_stack_top
->y1
= y1
;
1590 wx_stack_top
->x2
= x2
;
1591 wx_stack_top
->y2
= y2
;
1592 wx_stack_top
->x3
= x3
;
1593 wx_stack_top
->y3
= y3
;
1594 wx_stack_top
->x4
= x4
;
1595 wx_stack_top
->y4
= y4
;
1600 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1601 double *x3
, double *y3
, double *x4
, double *y4
)
1603 if (wx_stack_count
== 0)
1607 *x1
= wx_stack_top
->x1
;
1608 *y1
= wx_stack_top
->y1
;
1609 *x2
= wx_stack_top
->x2
;
1610 *y2
= wx_stack_top
->y2
;
1611 *x3
= wx_stack_top
->x3
;
1612 *y3
= wx_stack_top
->y3
;
1613 *x4
= wx_stack_top
->x4
;
1614 *y4
= wx_stack_top
->y4
;
1618 static bool wx_spline_add_point(double x
, double y
)
1620 wxPoint
*point
= new wxPoint
;
1623 wx_spline_point_list
.Append((wxObject
*)point
);
1627 static void wx_spline_draw_point_array(wxDC
*dc
)
1629 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1630 wxNode
*node
= wx_spline_point_list
.First();
1633 wxPoint
*point
= (wxPoint
*)node
->Data();
1636 node
= wx_spline_point_list
.First();
1640 wxSpline::wxSpline(wxList
*list
)
1645 wxSpline::~wxSpline(void)
1649 void wxSpline::DeletePoints(void)
1651 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1653 wxPoint
*point
= (wxPoint
*)node
->Data();
1661 #endif // wxUSE_SPLINES