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
));
737 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
739 // "bottom left" and "bottom right"
740 x
+= (wxCoord
)(h
*sin(rad
));
741 y
+= (wxCoord
)(h
*cos(rad
));
742 CalcBoundingBox(x
, y
);
743 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
747 // ---------------------------------------------------------------------------
749 // ---------------------------------------------------------------------------
751 void wxDC::SetPalette(const wxPalette
& palette
)
753 // Set the old object temporarily, in case the assignment deletes an object
754 // that's not yet selected out.
757 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
765 // Setting a NULL colourmap is a way of restoring
766 // the original colourmap
769 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
776 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
778 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
780 m_oldPalette
= (WXHPALETTE
) oldPal
;
782 ::RealizePalette(GetHdc());
786 void wxDC::SetFont(const wxFont
& the_font
)
788 // Set the old object temporarily, in case the assignment deletes an object
789 // that's not yet selected out.
792 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
801 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
805 if (m_font
.Ok() && m_font
.GetResourceHandle())
807 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
808 if (f
== (HFONT
) NULL
)
810 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
813 m_oldFont
= (WXHFONT
) f
;
817 void wxDC::SetPen(const wxPen
& pen
)
819 // Set the old object temporarily, in case the assignment deletes an object
820 // that's not yet selected out.
823 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
832 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
838 if (m_pen
.GetResourceHandle())
840 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
842 m_oldPen
= (WXHPEN
) p
;
847 void wxDC::SetBrush(const wxBrush
& brush
)
849 // Set the old object temporarily, in case the assignment deletes an object
850 // that's not yet selected out.
853 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
862 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
868 if (m_brush
.GetResourceHandle())
871 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
873 m_oldBrush
= (WXHBRUSH
) b
;
878 void wxDC::SetBackground(const wxBrush
& brush
)
880 m_backgroundBrush
= brush
;
882 if (!m_backgroundBrush
.Ok())
887 bool customColours
= TRUE
;
888 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
889 // change background colours from the control-panel specified colours.
890 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
891 customColours
= FALSE
;
895 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
897 m_canvas
->SetTransparent(TRUE
);
901 // New behaviour, 10/2/99: setting the background brush of a DC
902 // doesn't affect the window background colour. However,
903 // I'm leaving in the transparency setting because it's needed by
904 // various controls (e.g. wxStaticText) to determine whether to draw
905 // transparently or not. TODO: maybe this should be a new function
906 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
908 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
909 m_canvas
->SetTransparent(FALSE
);
913 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
915 (void)SetBkColor(GetHdc(), new_color
);
919 void wxDC::SetBackgroundMode(int mode
)
921 m_backgroundMode
= mode
;
923 // SetBackgroundColour now only refers to text background
924 // and m_backgroundMode is used there
927 if (m_backgroundMode == wxTRANSPARENT)
928 ::SetBkMode(GetHdc(), TRANSPARENT);
930 ::SetBkMode(GetHdc(), OPAQUE);
934 void wxDC::SetLogicalFunction(int function
)
936 m_logicalFunction
= function
;
938 SetRop((WXHDC
) m_hDC
);
941 void wxDC::SetRop(WXHDC dc
)
943 if (!dc
|| m_logicalFunction
< 0)
947 // These may be wrong
948 switch (m_logicalFunction
)
950 // case wxXOR: c_rop = R2_XORPEN; break;
951 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
952 case wxINVERT
: c_rop
= R2_NOT
; break;
953 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
954 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
955 case wxCLEAR
: c_rop
= R2_WHITE
; break;
956 case wxSET
: c_rop
= R2_BLACK
; break;
957 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
958 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
959 case wxAND
: c_rop
= R2_MASKPEN
; break;
960 case wxOR
: c_rop
= R2_MERGEPEN
; break;
961 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
966 c_rop
= R2_COPYPEN
; break;
968 SetROP2((HDC
) dc
, c_rop
);
971 bool wxDC::StartDoc(const wxString
& message
)
973 // We might be previewing, so return TRUE to let it continue.
981 void wxDC::StartPage()
989 // ---------------------------------------------------------------------------
991 // ---------------------------------------------------------------------------
993 wxCoord
wxDC::GetCharHeight() const
995 TEXTMETRIC lpTextMetric
;
997 GetTextMetrics(GetHdc(), &lpTextMetric
);
999 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1002 wxCoord
wxDC::GetCharWidth() const
1004 TEXTMETRIC lpTextMetric
;
1006 GetTextMetrics(GetHdc(), &lpTextMetric
);
1008 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1011 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1012 wxCoord
*descent
, wxCoord
*externalLeading
,
1013 wxFont
*theFont
) const
1015 wxFont
*fontToUse
= (wxFont
*) theFont
;
1017 fontToUse
= (wxFont
*) &m_font
;
1022 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1023 GetTextMetrics(GetHdc(), &tm
);
1025 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1026 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1027 if (descent
) *descent
= tm
.tmDescent
;
1028 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1031 void wxDC::SetMapMode(int mode
)
1033 m_mappingMode
= mode
;
1035 int pixel_width
= 0;
1036 int pixel_height
= 0;
1040 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1041 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1042 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1043 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1045 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1050 double mm2pixelsX
= pixel_width
/mm_width
;
1051 double mm2pixelsY
= pixel_height
/mm_height
;
1057 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1058 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1063 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1064 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1069 m_logicalScaleX
= mm2pixelsX
;
1070 m_logicalScaleY
= mm2pixelsY
;
1075 m_logicalScaleX
= (mm2pixelsX
/10.0);
1076 m_logicalScaleY
= (mm2pixelsY
/10.0);
1082 m_logicalScaleX
= 1.0;
1083 m_logicalScaleY
= 1.0;
1088 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1089 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1091 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1092 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1093 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1094 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1095 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1096 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1099 void wxDC::SetUserScale(double x
, double y
)
1104 SetMapMode(m_mappingMode
);
1107 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1109 m_signX
= xLeftRight
? 1 : -1;
1110 m_signY
= yBottomUp
? -1 : 1;
1112 SetMapMode(m_mappingMode
);
1115 void wxDC::SetSystemScale(double x
, double y
)
1120 SetMapMode(m_mappingMode
);
1123 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1125 m_logicalOriginX
= x
;
1126 m_logicalOriginY
= y
;
1128 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1131 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1133 m_deviceOriginX
= x
;
1134 m_deviceOriginY
= y
;
1136 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1139 // ---------------------------------------------------------------------------
1140 // coordinates transformations
1141 // ---------------------------------------------------------------------------
1143 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1145 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1148 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1150 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1153 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1155 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1158 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1160 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1163 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1165 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1168 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1170 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1173 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1175 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1178 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1180 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1183 // ---------------------------------------------------------------------------
1185 // ---------------------------------------------------------------------------
1186 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1187 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int rop
, bool useMask
)
1189 wxCoord xdest1
= xdest
;
1190 wxCoord ydest1
= ydest
;
1191 wxCoord xsrc1
= xsrc
;
1192 wxCoord ysrc1
= ysrc
;
1194 // Chris Breeze 18/5/98: use text foreground/background colours
1195 // when blitting from 1-bit bitmaps
1196 COLORREF old_textground
= ::GetTextColor(GetHdc());
1197 COLORREF old_background
= ::GetBkColor(GetHdc());
1198 if (m_textForegroundColour
.Ok())
1200 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1202 if (m_textBackgroundColour
.Ok())
1204 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1207 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1208 rop
== wxCLEAR
? WHITENESS
:
1209 rop
== wxSET
? BLACKNESS
:
1210 rop
== wxINVERT
? DSTINVERT
:
1211 rop
== wxAND
? MERGECOPY
:
1212 rop
== wxOR
? MERGEPAINT
:
1213 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1214 rop
== wxXOR
? SRCINVERT
:
1215 rop
== wxOR_REVERSE
? MERGEPAINT
:
1216 rop
== wxAND_REVERSE
? SRCERASE
:
1217 rop
== wxSRC_OR
? SRCPAINT
:
1218 rop
== wxSRC_AND
? SRCAND
:
1221 bool success
= TRUE
;
1222 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1226 // Not implemented under Win95 (or maybe a specific device?)
1227 if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1228 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1238 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1239 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1240 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1241 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1242 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1243 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1244 ::SelectObject(dc_mask
, 0);
1245 ::DeleteDC(dc_mask
);
1247 // New code from Chris Breeze, 15/7/98
1248 // Blit bitmap with mask
1250 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1252 // If we are printing source colours are screen colours
1253 // not printer colours and so we need copy the bitmap
1256 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1257 HDC dc_src
= (HDC
) source
->m_hDC
;
1259 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1260 for (int x
= 0; x
< width
; x
++)
1262 for (int y
= 0; y
< height
; y
++)
1264 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1267 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1268 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1269 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1270 ::FillRect(GetHdc(), &rect
, brush
);
1271 ::DeleteObject(brush
);
1275 ::SelectObject(dc_mask
, 0);
1276 ::DeleteDC(dc_mask
);
1280 // create a temp buffer bitmap and DCs to access it and the mask
1281 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1282 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1283 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1284 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1285 ::SelectObject(dc_buffer
, buffer_bmap
);
1287 // copy dest to buffer
1288 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1289 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1291 // copy src to buffer using selected raster op
1292 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1293 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1295 // set masked area in buffer to BLACK (pixel value 0)
1296 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1297 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1298 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1299 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1301 // set unmasked area in dest to BLACK
1302 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1303 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1304 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1305 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1306 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1307 ::SetTextColor(GetHdc(), prevCol
);
1309 // OR buffer to dest
1310 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1311 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1313 // tidy up temporary DCs and bitmap
1314 ::SelectObject(dc_mask
, 0);
1315 ::DeleteDC(dc_mask
);
1316 ::SelectObject(dc_buffer
, 0);
1317 ::DeleteDC(dc_buffer
);
1318 ::DeleteObject(buffer_bmap
);
1324 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1326 // If we are printing, source colours are screen colours
1327 // not printer colours and so we need copy the bitmap
1329 HDC dc_src
= (HDC
) source
->m_hDC
;
1331 for (int x
= 0; x
< width
; x
++)
1333 for (int y
= 0; y
< height
; y
++)
1335 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1336 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1337 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1338 ::FillRect(GetHdc(), &rect
, brush
);
1339 ::DeleteObject(brush
);
1345 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1346 xsrc1
, ysrc1
, dwRop
) != 0);
1349 ::SetTextColor(GetHdc(), old_textground
);
1350 ::SetBkColor(GetHdc(), old_background
);
1355 void wxDC::DoGetSize(int *w
, int *h
) const
1357 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1358 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1361 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1363 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1364 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1367 wxSize
wxDC::GetPPI() const
1369 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1370 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1372 return wxSize(x
, y
);
1375 // For use by wxWindows only, unless custom units are required.
1376 void wxDC::SetLogicalScale(double x
, double y
)
1378 m_logicalScaleX
= x
;
1379 m_logicalScaleY
= y
;
1382 #if WXWIN_COMPATIBILITY
1383 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1384 float *descent
, float *externalLeading
,
1385 wxFont
*theFont
, bool use16bit
) const
1387 wxCoord x1
, y1
, descent1
, externalLeading1
;
1388 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1391 *descent
= descent1
;
1392 if (externalLeading
)
1393 *externalLeading
= externalLeading1
;
1397 // ---------------------------------------------------------------------------
1398 // spline drawing code
1399 // ---------------------------------------------------------------------------
1403 class wxSpline
: public wxObject
1409 wxSpline(wxList
*list
);
1410 void DeletePoints();
1412 // Doesn't delete points
1416 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1418 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1419 double a3
, double b3
, double a4
, double b4
);
1420 void wx_clear_stack();
1421 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1422 double *y3
, double *x4
, double *y4
);
1423 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1424 double x4
, double y4
);
1425 static bool wx_spline_add_point(double x
, double y
);
1426 static void wx_spline_draw_point_array(wxDC
*dc
);
1427 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1429 void wxDC::DoDrawSpline(wxList
*list
)
1431 wxSpline
spline(list
);
1433 wx_draw_open_spline(this, &spline
);
1436 wxList wx_spline_point_list
;
1438 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1441 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1442 double x1
, y1
, x2
, y2
;
1444 wxNode
*node
= spline
->points
->First();
1445 p
= (wxPoint
*)node
->Data();
1450 node
= node
->Next();
1451 p
= (wxPoint
*)node
->Data();
1455 cx1
= (double)((x1
+ x2
) / 2);
1456 cy1
= (double)((y1
+ y2
) / 2);
1457 cx2
= (double)((cx1
+ x2
) / 2);
1458 cy2
= (double)((cy1
+ y2
) / 2);
1460 wx_spline_add_point(x1
, y1
);
1462 while ((node
= node
->Next()) != NULL
)
1464 p
= (wxPoint
*)node
->Data();
1469 cx4
= (double)(x1
+ x2
) / 2;
1470 cy4
= (double)(y1
+ y2
) / 2;
1471 cx3
= (double)(x1
+ cx4
) / 2;
1472 cy3
= (double)(y1
+ cy4
) / 2;
1474 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1478 cx2
= (double)(cx1
+ x2
) / 2;
1479 cy2
= (double)(cy1
+ y2
) / 2;
1482 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1483 wx_spline_add_point(x2
, y2
);
1485 wx_spline_draw_point_array(dc
);
1489 /********************* CURVES FOR SPLINES *****************************
1491 The following spline drawing routine is from
1493 "An Algorithm for High-Speed Curve Generation"
1494 by George Merrill Chaikin,
1495 Computer Graphics and Image Processing, 3, Academic Press,
1500 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1501 Computer Graphics and Image Processing, 4, Academic Press,
1504 ***********************************************************************/
1506 #define half(z1, z2) ((z1+z2)/2.0)
1509 /* iterative version */
1511 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1514 register double xmid
, ymid
;
1515 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1518 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1520 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1521 xmid
= (double)half(x2
, x3
);
1522 ymid
= (double)half(y2
, y3
);
1523 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1524 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1525 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1526 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1528 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1529 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1530 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1531 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1537 /* utilities used by spline drawing routines */
1540 typedef struct wx_spline_stack_struct
{
1541 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1545 #define SPLINE_STACK_DEPTH 20
1546 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1547 static Stack
*wx_stack_top
;
1548 static int wx_stack_count
;
1550 void wx_clear_stack()
1552 wx_stack_top
= wx_spline_stack
;
1556 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1558 wx_stack_top
->x1
= x1
;
1559 wx_stack_top
->y1
= y1
;
1560 wx_stack_top
->x2
= x2
;
1561 wx_stack_top
->y2
= y2
;
1562 wx_stack_top
->x3
= x3
;
1563 wx_stack_top
->y3
= y3
;
1564 wx_stack_top
->x4
= x4
;
1565 wx_stack_top
->y4
= y4
;
1570 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1571 double *x3
, double *y3
, double *x4
, double *y4
)
1573 if (wx_stack_count
== 0)
1577 *x1
= wx_stack_top
->x1
;
1578 *y1
= wx_stack_top
->y1
;
1579 *x2
= wx_stack_top
->x2
;
1580 *y2
= wx_stack_top
->y2
;
1581 *x3
= wx_stack_top
->x3
;
1582 *y3
= wx_stack_top
->y3
;
1583 *x4
= wx_stack_top
->x4
;
1584 *y4
= wx_stack_top
->y4
;
1588 static bool wx_spline_add_point(double x
, double y
)
1590 wxPoint
*point
= new wxPoint
;
1593 wx_spline_point_list
.Append((wxObject
*)point
);
1597 static void wx_spline_draw_point_array(wxDC
*dc
)
1599 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1600 wxNode
*node
= wx_spline_point_list
.First();
1603 wxPoint
*point
= (wxPoint
*)node
->Data();
1606 node
= wx_spline_point_list
.First();
1610 wxSpline::wxSpline(wxList
*list
)
1615 wxSpline::~wxSpline()
1619 void wxSpline::DeletePoints()
1621 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1623 wxPoint
*point
= (wxPoint
*)node
->Data();
1631 #endif // wxUSE_SPLINES