1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/window.h"
35 #include "wx/dialog.h"
37 #include "wx/bitmap.h"
38 #include "wx/dcmemory.h"
43 #include "wx/dcprint.h"
48 #if wxUSE_COMMON_DIALOGS
49 #if wxUSE_NORLANDER_HEADERS
59 #include "wx/msw/private.h"
61 #if !USE_SHARED_LIBRARY
62 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
65 // ---------------------------------------------------------------------------
67 // ---------------------------------------------------------------------------
69 static const int VIEWPORT_EXTENT
= 1000;
71 static const int MM_POINTS
= 9;
72 static const int MM_METRIC
= 10;
74 // usually this is defined in math.h
76 static const double M_PI
= 3.14159265358979323846;
79 // ---------------------------------------------------------------------------
81 // ---------------------------------------------------------------------------
83 // convert degrees to radians
84 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
86 // ===========================================================================
88 // ===========================================================================
90 // ---------------------------------------------------------------------------
92 // ---------------------------------------------------------------------------
94 // Default constructor
108 m_windowExtX
= VIEWPORT_EXTENT
;
109 m_windowExtY
= VIEWPORT_EXTENT
;
118 SelectOldObjects(m_hDC
);
120 if ( m_canvas
== NULL
)
121 ::DeleteDC(GetHdc());
123 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
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 // ---------------------------------------------------------------------------
177 // ---------------------------------------------------------------------------
179 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
184 m_clipX2
= (int)(cx
+ cw
);
185 m_clipY2
= (int)(cy
+ ch
);
187 DoClipping((WXHDC
) m_hDC
);
190 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
192 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
194 wxRect box
= region
.GetBox();
199 m_clipX2
= box
.x
+ box
.width
;
200 m_clipY2
= box
.y
+ box
.height
;
203 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
205 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
209 void wxDC::DoClipping(WXHDC dc
)
211 if (m_clipping
&& dc
)
213 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
214 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
218 void wxDC::DestroyClippingRegion()
220 if (m_clipping
&& m_hDC
)
222 // TODO: this should restore the previous clipping region,
223 // so that OnPaint processing works correctly, and the update clipping region
224 // doesn't get destroyed after the first DestroyClippingRegion.
225 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
226 SelectClipRgn(GetHdc(), rgn
);
232 // ---------------------------------------------------------------------------
233 // query capabilities
234 // ---------------------------------------------------------------------------
236 bool wxDC::CanDrawBitmap() const
241 bool wxDC::CanGetTextExtent() const
243 // What sort of display is it?
244 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
246 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
249 int wxDC::GetDepth() const
251 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
254 // ---------------------------------------------------------------------------
256 // ---------------------------------------------------------------------------
263 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
267 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
269 rect
.left
= 0; rect
.top
= 0;
270 rect
.right
= m_selectedBitmap
.GetWidth();
271 rect
.bottom
= m_selectedBitmap
.GetHeight();
274 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
276 DWORD colour
= GetBkColor(GetHdc());
277 HBRUSH brush
= CreateSolidBrush(colour
);
278 FillRect(GetHdc(), &rect
, brush
);
281 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
282 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
283 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
284 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
285 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
288 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
290 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
292 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
295 CalcBoundingBox(x
, y
);
298 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
300 // added by steve 29.12.94 (copied from DrawPoint)
301 // returns TRUE for pixels in the color of the current pen
302 // and FALSE for all other pixels colors
303 // if col is non-NULL return the color of the pixel
305 // get the color of the pixel
306 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
307 // get the color of the pen
308 COLORREF pencolor
= 0x00ffffff;
311 pencolor
= m_pen
.GetColour().GetPixel();
314 // return the color of the pixel
316 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
318 // check, if color of the pixels is the same as the color
319 // of the current pen
320 return(pixelcolor
==pencolor
);
323 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
325 wxCoord x1
= x
-VIEWPORT_EXTENT
;
326 wxCoord y1
= y
-VIEWPORT_EXTENT
;
327 wxCoord x2
= x
+VIEWPORT_EXTENT
;
328 wxCoord y2
= y
+VIEWPORT_EXTENT
;
330 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
331 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
333 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
334 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
336 CalcBoundingBox(x1
, y1
);
337 CalcBoundingBox(x2
, y2
);
340 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
342 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
343 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
345 /* MATTHEW: [6] New normalization */
346 #if WX_STANDARD_GRAPHICS
347 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
350 CalcBoundingBox(x1
, y1
);
351 CalcBoundingBox(x2
, y2
);
354 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
358 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
359 if (x1
==x2
&& x2
==y2
)
361 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
365 wxCoord xx1
= XLOG2DEV(x1
);
366 wxCoord yy1
= YLOG2DEV(y1
);
367 wxCoord xx2
= XLOG2DEV(x2
);
368 wxCoord yy2
= YLOG2DEV(y2
);
369 wxCoord xxc
= XLOG2DEV(xc
);
370 wxCoord yyc
= YLOG2DEV(yc
);
371 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
373 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
374 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
375 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
376 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
377 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
378 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
380 // Have to add 1 to bottom-right corner of rectangle
381 // to make semi-circles look right (crooked line otherwise).
382 // Unfortunately this is not a reliable method, depends
383 // on the size of shape.
384 // TODO: figure out why this happens!
385 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
389 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
392 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
393 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
396 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
398 COLORREF color
= 0x00ffffff;
401 color
= m_pen
.GetColour().GetPixel();
404 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
406 CalcBoundingBox(x
, y
);
409 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
411 // Do things less efficiently if we have offsets
412 if (xoffset
!= 0 || yoffset
!= 0)
414 POINT
*cpoints
= new POINT
[n
];
416 for (i
= 0; i
< n
; i
++)
418 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
419 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
421 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
423 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
424 (void)Polygon(GetHdc(), cpoints
, n
);
425 SetPolyFillMode(GetHdc(),prev
);
431 for (i
= 0; i
< n
; i
++)
432 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
434 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
435 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
436 SetPolyFillMode(GetHdc(),prev
);
440 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
442 // Do things less efficiently if we have offsets
443 if (xoffset
!= 0 || yoffset
!= 0)
445 POINT
*cpoints
= new POINT
[n
];
447 for (i
= 0; i
< n
; i
++)
449 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
450 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
452 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
454 (void)Polyline(GetHdc(), cpoints
, n
);
460 for (i
= 0; i
< n
; i
++)
461 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
463 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
467 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
469 wxCoord x2
= x
+ width
;
470 wxCoord y2
= y
+ height
;
472 /* MATTHEW: [6] new normalization */
473 #if WX_STANDARD_GRAPHICS
474 bool do_brush
, do_pen
;
476 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
477 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
480 HPEN orig_pen
= NULL
;
482 if (do_pen
|| !m_pen
.Ok())
483 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
485 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
486 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
488 if (do_pen
|| !m_pen
.Ok())
489 ::SelectObject(GetHdc() , orig_pen
);
492 HBRUSH orig_brush
= NULL
;
494 if (do_brush
|| !m_brush
.Ok())
495 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
497 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
498 XLOG2DEV(x2
), YLOG2DEV(y2
));
500 if (do_brush
|| !m_brush
.Ok())
501 ::SelectObject(GetHdc(), orig_brush
);
504 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
507 CalcBoundingBox(x
, y
);
508 CalcBoundingBox(x2
, y2
);
511 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
513 // Now, a negative radius value is interpreted to mean
514 // 'the proportion of the smallest X or Y dimension'
518 double smallest
= 0.0;
523 radius
= (- radius
* smallest
);
526 wxCoord x2
= (x
+width
);
527 wxCoord y2
= (y
+height
);
529 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
530 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
532 CalcBoundingBox(x
, y
);
533 CalcBoundingBox(x2
, y2
);
536 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
538 wxCoord x2
= (x
+width
);
539 wxCoord y2
= (y
+height
);
541 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
543 CalcBoundingBox(x
, y
);
544 CalcBoundingBox(x2
, y2
);
547 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
548 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
553 int rx1
= XLOG2DEV(x
+w
/2);
554 int ry1
= YLOG2DEV(y
+h
/2);
561 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
562 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
563 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
564 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
566 // draw pie with NULL_PEN first and then outline otherwise a line is
567 // drawn from the start and end points to the centre
568 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
571 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
576 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
577 rx1
, ry1
-1, rx2
, ry2
-1);
579 ::SelectObject(GetHdc(), orig_pen
);
580 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
583 CalcBoundingBox(x
, y
);
584 CalcBoundingBox(x2
, y2
);
587 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
589 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
590 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
591 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
593 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
596 CalcBoundingBox(x
, y
);
597 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
600 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
605 // If we're not drawing transparently, and not drawing to a printer,
606 // optimize this function to use Windows functions.
607 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
610 HDC memdc
= ::CreateCompatibleDC( cdc
);
611 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
613 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
615 ::SelectObject( memdc
, hbitmap
);
616 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
621 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
623 memDC
.SelectObject(bmp
);
625 /* Not sure if we need this. The mask should leave the
626 * masked areas as per the original background of this DC.
629 // There might be transparent areas, so make these
630 // the same colour as this DC
631 memDC.SetBackground(* GetBackground());
635 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
637 memDC
.SelectObject(wxNullBitmap
);
641 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
643 DrawAnyText(text
, x
, y
);
645 // update the bounding box
646 CalcBoundingBox(x
, y
);
649 GetTextExtent(text
, &w
, &h
);
650 CalcBoundingBox(x
+ w
, y
+ h
);
653 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
655 // prepare for drawing the text
656 if ( m_textForegroundColour
.Ok() )
657 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
659 DWORD old_background
= 0;
660 if ( m_textBackgroundColour
.Ok() )
662 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
665 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
668 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
669 text
.c_str(), text
.length()) == 0 )
671 wxLogLastError("TextOut");
674 // restore the old parameters (text foreground colour may be left because
675 // it never is set to anything else, but background should remain
676 // transparent even if we just drew an opaque string)
677 if ( m_textBackgroundColour
.Ok() )
678 (void)SetBkColor(GetHdc(), old_background
);
680 SetBkMode(GetHdc(), TRANSPARENT
);
683 void wxDC::DoDrawRotatedText(const wxString
& text
,
684 wxCoord x
, wxCoord y
,
687 // we test that we have some font because otherwise we should still use the
688 // "else" part below to avoid that DrawRotatedText(angle = 180) and
689 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
690 // font for drawing rotated fonts unfortunately)
691 if ( (angle
== 0.0) && m_font
.Ok() )
693 DoDrawText(text
, x
, y
);
697 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
698 // can't have non zero orientation/escapement
699 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
700 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
702 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
704 wxLogLastError("GetObject(hfont)");
707 // GDI wants the angle in tenth of degree
708 long angle10
= (long)(angle
* 10);
709 lf
.lfEscapement
= angle10
;
710 lf
. lfOrientation
= angle10
;
712 hfont
= ::CreateFontIndirect(&lf
);
715 wxLogLastError("CreateFont");
719 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
721 DrawAnyText(text
, x
, y
);
723 (void)::SelectObject(GetHdc(), hfontOld
);
726 // call the bounding box by adding all four vertices of the rectangle
727 // containing the text to it (simpler and probably not slower than
728 // determining which of them is really topmost/leftmost/...)
730 GetTextExtent(text
, &w
, &h
);
732 double rad
= DegToRad(angle
);
734 // "upper left" and "upper right"
735 CalcBoundingBox(x
, y
);
736 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
738 // "bottom left" and "bottom right"
739 x
+= (wxCoord
)(h
*sin(rad
));
740 y
+= (wxCoord
)(h
*cos(rad
));
741 CalcBoundingBox(x
, y
);
742 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
746 // ---------------------------------------------------------------------------
748 // ---------------------------------------------------------------------------
750 void wxDC::SetPalette(const wxPalette
& palette
)
752 // Set the old object temporarily, in case the assignment deletes an object
753 // that's not yet selected out.
756 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
764 // Setting a NULL colourmap is a way of restoring
765 // the original colourmap
768 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
775 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
777 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
779 m_oldPalette
= (WXHPALETTE
) oldPal
;
781 ::RealizePalette(GetHdc());
785 void wxDC::SetFont(const wxFont
& the_font
)
787 // Set the old object temporarily, in case the assignment deletes an object
788 // that's not yet selected out.
791 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
800 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
804 if (m_font
.Ok() && m_font
.GetResourceHandle())
806 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
807 if (f
== (HFONT
) NULL
)
809 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
812 m_oldFont
= (WXHFONT
) f
;
816 void wxDC::SetPen(const wxPen
& pen
)
818 // Set the old object temporarily, in case the assignment deletes an object
819 // that's not yet selected out.
822 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
831 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
837 if (m_pen
.GetResourceHandle())
839 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
841 m_oldPen
= (WXHPEN
) p
;
846 void wxDC::SetBrush(const wxBrush
& brush
)
848 // Set the old object temporarily, in case the assignment deletes an object
849 // that's not yet selected out.
852 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
861 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
867 if (m_brush
.GetResourceHandle())
870 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
872 m_oldBrush
= (WXHBRUSH
) b
;
877 void wxDC::SetBackground(const wxBrush
& brush
)
879 m_backgroundBrush
= brush
;
881 if (!m_backgroundBrush
.Ok())
886 bool customColours
= TRUE
;
887 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
888 // change background colours from the control-panel specified colours.
889 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
890 customColours
= FALSE
;
894 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
896 m_canvas
->SetTransparent(TRUE
);
900 // New behaviour, 10/2/99: setting the background brush of a DC
901 // doesn't affect the window background colour. However,
902 // I'm leaving in the transparency setting because it's needed by
903 // various controls (e.g. wxStaticText) to determine whether to draw
904 // transparently or not. TODO: maybe this should be a new function
905 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
907 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
908 m_canvas
->SetTransparent(FALSE
);
912 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
914 (void)SetBkColor(GetHdc(), new_color
);
918 void wxDC::SetBackgroundMode(int mode
)
920 m_backgroundMode
= mode
;
922 // SetBackgroundColour now only refers to text background
923 // and m_backgroundMode is used there
926 if (m_backgroundMode == wxTRANSPARENT)
927 ::SetBkMode(GetHdc(), TRANSPARENT);
929 ::SetBkMode(GetHdc(), OPAQUE);
933 void wxDC::SetLogicalFunction(int function
)
935 m_logicalFunction
= function
;
937 SetRop((WXHDC
) m_hDC
);
940 void wxDC::SetRop(WXHDC dc
)
942 if (!dc
|| m_logicalFunction
< 0)
946 // These may be wrong
947 switch (m_logicalFunction
)
949 // case wxXOR: c_rop = R2_XORPEN; break;
950 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
951 case wxINVERT
: c_rop
= R2_NOT
; break;
952 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
953 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
954 case wxCLEAR
: c_rop
= R2_WHITE
; break;
955 case wxSET
: c_rop
= R2_BLACK
; break;
956 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
957 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
958 case wxAND
: c_rop
= R2_MASKPEN
; break;
959 case wxOR
: c_rop
= R2_MERGEPEN
; break;
960 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
965 c_rop
= R2_COPYPEN
; break;
967 SetROP2((HDC
) dc
, c_rop
);
970 bool wxDC::StartDoc(const wxString
& message
)
972 // We might be previewing, so return TRUE to let it continue.
980 void wxDC::StartPage()
988 // ---------------------------------------------------------------------------
990 // ---------------------------------------------------------------------------
992 wxCoord
wxDC::GetCharHeight() const
994 TEXTMETRIC lpTextMetric
;
996 GetTextMetrics(GetHdc(), &lpTextMetric
);
998 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1001 wxCoord
wxDC::GetCharWidth() const
1003 TEXTMETRIC lpTextMetric
;
1005 GetTextMetrics(GetHdc(), &lpTextMetric
);
1007 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1010 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1011 wxCoord
*descent
, wxCoord
*externalLeading
,
1012 wxFont
*theFont
) const
1014 wxFont
*fontToUse
= (wxFont
*) theFont
;
1016 fontToUse
= (wxFont
*) &m_font
;
1021 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1022 GetTextMetrics(GetHdc(), &tm
);
1024 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1025 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1026 if (descent
) *descent
= tm
.tmDescent
;
1027 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1030 void wxDC::SetMapMode(int mode
)
1032 m_mappingMode
= mode
;
1034 int pixel_width
= 0;
1035 int pixel_height
= 0;
1039 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1040 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1041 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1042 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1044 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1049 double mm2pixelsX
= pixel_width
/mm_width
;
1050 double mm2pixelsY
= pixel_height
/mm_height
;
1056 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1057 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1062 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1063 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1068 m_logicalScaleX
= mm2pixelsX
;
1069 m_logicalScaleY
= mm2pixelsY
;
1074 m_logicalScaleX
= (mm2pixelsX
/10.0);
1075 m_logicalScaleY
= (mm2pixelsY
/10.0);
1081 m_logicalScaleX
= 1.0;
1082 m_logicalScaleY
= 1.0;
1087 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1088 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1090 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1091 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1092 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1093 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1094 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1095 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1098 void wxDC::SetUserScale(double x
, double y
)
1103 SetMapMode(m_mappingMode
);
1106 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1108 m_signX
= xLeftRight
? 1 : -1;
1109 m_signY
= yBottomUp
? -1 : 1;
1111 SetMapMode(m_mappingMode
);
1114 void wxDC::SetSystemScale(double x
, double y
)
1119 SetMapMode(m_mappingMode
);
1122 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1124 m_logicalOriginX
= x
;
1125 m_logicalOriginY
= y
;
1127 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1130 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1132 m_deviceOriginX
= x
;
1133 m_deviceOriginY
= y
;
1135 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1138 // ---------------------------------------------------------------------------
1139 // coordinates transformations
1140 // ---------------------------------------------------------------------------
1142 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1144 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1147 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1149 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1152 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1154 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1157 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1159 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1162 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1164 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1167 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1169 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1172 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1174 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1177 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1179 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1182 // ---------------------------------------------------------------------------
1184 // ---------------------------------------------------------------------------
1185 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1186 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int rop
, bool useMask
)
1188 wxCoord xdest1
= xdest
;
1189 wxCoord ydest1
= ydest
;
1190 wxCoord xsrc1
= xsrc
;
1191 wxCoord ysrc1
= ysrc
;
1193 // Chris Breeze 18/5/98: use text foreground/background colours
1194 // when blitting from 1-bit bitmaps
1195 COLORREF old_textground
= ::GetTextColor(GetHdc());
1196 COLORREF old_background
= ::GetBkColor(GetHdc());
1197 if (m_textForegroundColour
.Ok())
1199 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1201 if (m_textBackgroundColour
.Ok())
1203 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1206 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1207 rop
== wxCLEAR
? WHITENESS
:
1208 rop
== wxSET
? BLACKNESS
:
1209 rop
== wxINVERT
? DSTINVERT
:
1210 rop
== wxAND
? MERGECOPY
:
1211 rop
== wxOR
? MERGEPAINT
:
1212 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1213 rop
== wxXOR
? SRCINVERT
:
1214 rop
== wxOR_REVERSE
? MERGEPAINT
:
1215 rop
== wxAND_REVERSE
? SRCERASE
:
1216 rop
== wxSRC_OR
? SRCPAINT
:
1217 rop
== wxSRC_AND
? SRCAND
:
1220 bool success
= TRUE
;
1221 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1225 // Not implemented under Win95 (or maybe a specific device?)
1226 if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1227 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1237 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1238 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1239 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1240 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1241 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1242 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1243 ::SelectObject(dc_mask
, 0);
1244 ::DeleteDC(dc_mask
);
1246 // New code from Chris Breeze, 15/7/98
1247 // Blit bitmap with mask
1249 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1251 // If we are printing source colours are screen colours
1252 // not printer colours and so we need copy the bitmap
1255 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1256 HDC dc_src
= (HDC
) source
->m_hDC
;
1258 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1259 for (int x
= 0; x
< width
; x
++)
1261 for (int y
= 0; y
< height
; y
++)
1263 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1266 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1267 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1268 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1269 ::FillRect(GetHdc(), &rect
, brush
);
1270 ::DeleteObject(brush
);
1274 ::SelectObject(dc_mask
, 0);
1275 ::DeleteDC(dc_mask
);
1279 // create a temp buffer bitmap and DCs to access it and the mask
1280 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1281 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1282 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1283 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1284 ::SelectObject(dc_buffer
, buffer_bmap
);
1286 // copy dest to buffer
1287 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1288 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1290 // copy src to buffer using selected raster op
1291 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1292 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1294 // set masked area in buffer to BLACK (pixel value 0)
1295 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1296 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1297 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1298 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1300 // set unmasked area in dest to BLACK
1301 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1302 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1303 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1304 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1305 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1306 ::SetTextColor(GetHdc(), prevCol
);
1308 // OR buffer to dest
1309 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1310 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1312 // tidy up temporary DCs and bitmap
1313 ::SelectObject(dc_mask
, 0);
1314 ::DeleteDC(dc_mask
);
1315 ::SelectObject(dc_buffer
, 0);
1316 ::DeleteDC(dc_buffer
);
1317 ::DeleteObject(buffer_bmap
);
1323 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1325 // If we are printing, source colours are screen colours
1326 // not printer colours and so we need copy the bitmap
1328 HDC dc_src
= (HDC
) source
->m_hDC
;
1330 for (int x
= 0; x
< width
; x
++)
1332 for (int y
= 0; y
< height
; y
++)
1334 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1335 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1336 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1337 ::FillRect(GetHdc(), &rect
, brush
);
1338 ::DeleteObject(brush
);
1344 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1345 xsrc1
, ysrc1
, dwRop
) != 0);
1348 ::SetTextColor(GetHdc(), old_textground
);
1349 ::SetBkColor(GetHdc(), old_background
);
1354 void wxDC::DoGetSize(int *w
, int *h
) const
1356 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1357 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1360 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1362 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1363 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1366 wxSize
wxDC::GetPPI() const
1368 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1369 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1371 return wxSize(x
, y
);
1374 // For use by wxWindows only, unless custom units are required.
1375 void wxDC::SetLogicalScale(double x
, double y
)
1377 m_logicalScaleX
= x
;
1378 m_logicalScaleY
= y
;
1381 #if WXWIN_COMPATIBILITY
1382 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1383 float *descent
, float *externalLeading
,
1384 wxFont
*theFont
, bool use16bit
) const
1386 wxCoord x1
, y1
, descent1
, externalLeading1
;
1387 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1390 *descent
= descent1
;
1391 if (externalLeading
)
1392 *externalLeading
= externalLeading1
;
1396 // ---------------------------------------------------------------------------
1397 // spline drawing code
1398 // ---------------------------------------------------------------------------
1402 class wxSpline
: public wxObject
1408 wxSpline(wxList
*list
);
1409 void DeletePoints();
1411 // Doesn't delete points
1415 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1417 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1418 double a3
, double b3
, double a4
, double b4
);
1419 void wx_clear_stack();
1420 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1421 double *y3
, double *x4
, double *y4
);
1422 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1423 double x4
, double y4
);
1424 static bool wx_spline_add_point(double x
, double y
);
1425 static void wx_spline_draw_point_array(wxDC
*dc
);
1426 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1428 void wxDC::DoDrawSpline(wxList
*list
)
1430 wxSpline
spline(list
);
1432 wx_draw_open_spline(this, &spline
);
1435 wxList wx_spline_point_list
;
1437 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1440 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1441 double x1
, y1
, x2
, y2
;
1443 wxNode
*node
= spline
->points
->First();
1444 p
= (wxPoint
*)node
->Data();
1449 node
= node
->Next();
1450 p
= (wxPoint
*)node
->Data();
1454 cx1
= (double)((x1
+ x2
) / 2);
1455 cy1
= (double)((y1
+ y2
) / 2);
1456 cx2
= (double)((cx1
+ x2
) / 2);
1457 cy2
= (double)((cy1
+ y2
) / 2);
1459 wx_spline_add_point(x1
, y1
);
1461 while ((node
= node
->Next()) != NULL
)
1463 p
= (wxPoint
*)node
->Data();
1468 cx4
= (double)(x1
+ x2
) / 2;
1469 cy4
= (double)(y1
+ y2
) / 2;
1470 cx3
= (double)(x1
+ cx4
) / 2;
1471 cy3
= (double)(y1
+ cy4
) / 2;
1473 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1477 cx2
= (double)(cx1
+ x2
) / 2;
1478 cy2
= (double)(cy1
+ y2
) / 2;
1481 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1482 wx_spline_add_point(x2
, y2
);
1484 wx_spline_draw_point_array(dc
);
1488 /********************* CURVES FOR SPLINES *****************************
1490 The following spline drawing routine is from
1492 "An Algorithm for High-Speed Curve Generation"
1493 by George Merrill Chaikin,
1494 Computer Graphics and Image Processing, 3, Academic Press,
1499 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1500 Computer Graphics and Image Processing, 4, Academic Press,
1503 ***********************************************************************/
1505 #define half(z1, z2) ((z1+z2)/2.0)
1508 /* iterative version */
1510 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1513 register double xmid
, ymid
;
1514 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1517 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1519 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1520 xmid
= (double)half(x2
, x3
);
1521 ymid
= (double)half(y2
, y3
);
1522 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1523 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1524 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1525 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1527 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1528 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1529 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1530 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1536 /* utilities used by spline drawing routines */
1539 typedef struct wx_spline_stack_struct
{
1540 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1544 #define SPLINE_STACK_DEPTH 20
1545 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1546 static Stack
*wx_stack_top
;
1547 static int wx_stack_count
;
1549 void wx_clear_stack()
1551 wx_stack_top
= wx_spline_stack
;
1555 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1557 wx_stack_top
->x1
= x1
;
1558 wx_stack_top
->y1
= y1
;
1559 wx_stack_top
->x2
= x2
;
1560 wx_stack_top
->y2
= y2
;
1561 wx_stack_top
->x3
= x3
;
1562 wx_stack_top
->y3
= y3
;
1563 wx_stack_top
->x4
= x4
;
1564 wx_stack_top
->y4
= y4
;
1569 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1570 double *x3
, double *y3
, double *x4
, double *y4
)
1572 if (wx_stack_count
== 0)
1576 *x1
= wx_stack_top
->x1
;
1577 *y1
= wx_stack_top
->y1
;
1578 *x2
= wx_stack_top
->x2
;
1579 *y2
= wx_stack_top
->y2
;
1580 *x3
= wx_stack_top
->x3
;
1581 *y3
= wx_stack_top
->y3
;
1582 *x4
= wx_stack_top
->x4
;
1583 *y4
= wx_stack_top
->y4
;
1587 static bool wx_spline_add_point(double x
, double y
)
1589 wxPoint
*point
= new wxPoint
;
1592 wx_spline_point_list
.Append((wxObject
*)point
);
1596 static void wx_spline_draw_point_array(wxDC
*dc
)
1598 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1599 wxNode
*node
= wx_spline_point_list
.First();
1602 wxPoint
*point
= (wxPoint
*)node
->Data();
1605 node
= wx_spline_point_list
.First();
1609 wxSpline::wxSpline(wxList
*list
)
1614 wxSpline::~wxSpline()
1618 void wxSpline::DeletePoints()
1620 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1622 wxPoint
*point
= (wxPoint
*)node
->Data();
1630 #endif // wxUSE_SPLINES