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 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
63 // ---------------------------------------------------------------------------
65 // ---------------------------------------------------------------------------
67 static const int VIEWPORT_EXTENT
= 1000;
69 static const int MM_POINTS
= 9;
70 static const int MM_METRIC
= 10;
72 // usually this is defined in math.h
74 static const double M_PI
= 3.14159265358979323846;
77 // ---------------------------------------------------------------------------
79 // ---------------------------------------------------------------------------
81 // convert degrees to radians
82 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
84 // ===========================================================================
86 // ===========================================================================
88 // ---------------------------------------------------------------------------
90 // ---------------------------------------------------------------------------
92 // Default constructor
106 m_windowExtX
= VIEWPORT_EXTENT
;
107 m_windowExtY
= VIEWPORT_EXTENT
;
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC(GetHdc());
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
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 // ---------------------------------------------------------------------------
175 // ---------------------------------------------------------------------------
177 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
182 m_clipX2
= (int)(cx
+ cw
);
183 m_clipY2
= (int)(cy
+ ch
);
185 DoClipping((WXHDC
) m_hDC
);
188 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
190 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
192 wxRect box
= region
.GetBox();
197 m_clipX2
= box
.x
+ box
.width
;
198 m_clipY2
= box
.y
+ box
.height
;
201 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
203 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
207 void wxDC::DoClipping(WXHDC dc
)
209 if (m_clipping
&& dc
)
211 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
212 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
216 void wxDC::DestroyClippingRegion()
218 if (m_clipping
&& m_hDC
)
220 // TODO: this should restore the previous clipping region,
221 // so that OnPaint processing works correctly, and the update clipping region
222 // doesn't get destroyed after the first DestroyClippingRegion.
223 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
224 SelectClipRgn(GetHdc(), rgn
);
230 // ---------------------------------------------------------------------------
231 // query capabilities
232 // ---------------------------------------------------------------------------
234 bool wxDC::CanDrawBitmap() const
239 bool wxDC::CanGetTextExtent() const
241 // What sort of display is it?
242 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
244 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
247 int wxDC::GetDepth() const
249 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
252 // ---------------------------------------------------------------------------
254 // ---------------------------------------------------------------------------
261 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
265 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
267 rect
.left
= 0; rect
.top
= 0;
268 rect
.right
= m_selectedBitmap
.GetWidth();
269 rect
.bottom
= m_selectedBitmap
.GetHeight();
272 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
274 DWORD colour
= GetBkColor(GetHdc());
275 HBRUSH brush
= CreateSolidBrush(colour
);
276 FillRect(GetHdc(), &rect
, brush
);
279 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
280 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
281 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
282 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
283 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
286 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
288 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
290 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
293 CalcBoundingBox(x
, y
);
296 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
298 // added by steve 29.12.94 (copied from DrawPoint)
299 // returns TRUE for pixels in the color of the current pen
300 // and FALSE for all other pixels colors
301 // if col is non-NULL return the color of the pixel
303 // get the color of the pixel
304 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
305 // get the color of the pen
306 COLORREF pencolor
= 0x00ffffff;
309 pencolor
= m_pen
.GetColour().GetPixel();
312 // return the color of the pixel
314 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
316 // check, if color of the pixels is the same as the color
317 // of the current pen
318 return(pixelcolor
==pencolor
);
321 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
323 wxCoord x1
= x
-VIEWPORT_EXTENT
;
324 wxCoord y1
= y
-VIEWPORT_EXTENT
;
325 wxCoord x2
= x
+VIEWPORT_EXTENT
;
326 wxCoord y2
= y
+VIEWPORT_EXTENT
;
328 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
329 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
331 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
332 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
334 CalcBoundingBox(x1
, y1
);
335 CalcBoundingBox(x2
, y2
);
338 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
340 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
341 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
343 /* MATTHEW: [6] New normalization */
344 #if WX_STANDARD_GRAPHICS
345 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
348 CalcBoundingBox(x1
, y1
);
349 CalcBoundingBox(x2
, y2
);
352 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
356 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
357 if (x1
==x2
&& x2
==y2
)
359 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
363 wxCoord xx1
= XLOG2DEV(x1
);
364 wxCoord yy1
= YLOG2DEV(y1
);
365 wxCoord xx2
= XLOG2DEV(x2
);
366 wxCoord yy2
= YLOG2DEV(y2
);
367 wxCoord xxc
= XLOG2DEV(xc
);
368 wxCoord yyc
= YLOG2DEV(yc
);
369 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
371 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
372 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
373 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
374 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
375 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
376 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
378 // Have to add 1 to bottom-right corner of rectangle
379 // to make semi-circles look right (crooked line otherwise).
380 // Unfortunately this is not a reliable method, depends
381 // on the size of shape.
382 // TODO: figure out why this happens!
383 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
387 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
390 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
391 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
394 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
396 COLORREF color
= 0x00ffffff;
399 color
= m_pen
.GetColour().GetPixel();
402 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
404 CalcBoundingBox(x
, y
);
407 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
409 // Do things less efficiently if we have offsets
410 if (xoffset
!= 0 || yoffset
!= 0)
412 POINT
*cpoints
= new POINT
[n
];
414 for (i
= 0; i
< n
; i
++)
416 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
417 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
419 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
421 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
422 (void)Polygon(GetHdc(), cpoints
, n
);
423 SetPolyFillMode(GetHdc(),prev
);
429 for (i
= 0; i
< n
; i
++)
430 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
432 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
433 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
434 SetPolyFillMode(GetHdc(),prev
);
438 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
440 // Do things less efficiently if we have offsets
441 if (xoffset
!= 0 || yoffset
!= 0)
443 POINT
*cpoints
= new POINT
[n
];
445 for (i
= 0; i
< n
; i
++)
447 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
448 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
450 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
452 (void)Polyline(GetHdc(), cpoints
, n
);
458 for (i
= 0; i
< n
; i
++)
459 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
461 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
465 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
467 wxCoord x2
= x
+ width
;
468 wxCoord y2
= y
+ height
;
470 /* MATTHEW: [6] new normalization */
471 #if WX_STANDARD_GRAPHICS
472 bool do_brush
, do_pen
;
474 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
475 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
478 HPEN orig_pen
= NULL
;
480 if (do_pen
|| !m_pen
.Ok())
481 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
483 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
484 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
486 if (do_pen
|| !m_pen
.Ok())
487 ::SelectObject(GetHdc() , orig_pen
);
490 HBRUSH orig_brush
= NULL
;
492 if (do_brush
|| !m_brush
.Ok())
493 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
495 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
496 XLOG2DEV(x2
), YLOG2DEV(y2
));
498 if (do_brush
|| !m_brush
.Ok())
499 ::SelectObject(GetHdc(), orig_brush
);
502 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
505 CalcBoundingBox(x
, y
);
506 CalcBoundingBox(x2
, y2
);
509 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
511 // Now, a negative radius value is interpreted to mean
512 // 'the proportion of the smallest X or Y dimension'
516 double smallest
= 0.0;
521 radius
= (- radius
* smallest
);
524 wxCoord x2
= (x
+width
);
525 wxCoord y2
= (y
+height
);
527 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
528 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
530 CalcBoundingBox(x
, y
);
531 CalcBoundingBox(x2
, y2
);
534 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
536 wxCoord x2
= (x
+width
);
537 wxCoord y2
= (y
+height
);
539 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
541 CalcBoundingBox(x
, y
);
542 CalcBoundingBox(x2
, y2
);
545 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
546 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
551 int rx1
= XLOG2DEV(x
+w
/2);
552 int ry1
= YLOG2DEV(y
+h
/2);
559 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
560 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
561 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
562 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
564 // draw pie with NULL_PEN first and then outline otherwise a line is
565 // drawn from the start and end points to the centre
566 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
569 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
574 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
575 rx1
, ry1
-1, rx2
, ry2
-1);
577 ::SelectObject(GetHdc(), orig_pen
);
578 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
581 CalcBoundingBox(x
, y
);
582 CalcBoundingBox(x2
, y2
);
585 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
587 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
588 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
589 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
591 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
594 CalcBoundingBox(x
, y
);
595 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
598 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
603 bool needsPixelCopy
= false ;
604 bool isPrinter
= false ;
605 if (IsKindOf(CLASSINFO(wxPrinterDC
)) )
608 if ( ::GetDeviceCaps((HDC
) m_hDC
, RASTERCAPS
) & RC_STRETCHDIB
)
613 needsPixelCopy
= true ;
616 // If we're not drawing transparently, and not drawing to a printer,
617 // optimize this function to use Windows functions.
618 if (!useMask
&& !needsPixelCopy
)
622 BITMAPINFO
*info
= (BITMAPINFO
*) malloc( sizeof( BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
) ) ;
623 int iBitsSize
= ((bmp
.GetWidth() + 3 ) & ~3 ) * bmp
.GetHeight() ;
625 void* bits
= malloc( iBitsSize
) ;
627 memset( info
, 0 , sizeof( BITMAPINFOHEADER
) ) ;
629 info
->bmiHeader
.biSize
= sizeof( BITMAPINFOHEADER
) ;
630 info
->bmiHeader
.biWidth
= bmp
.GetWidth() ;
631 info
->bmiHeader
.biHeight
= bmp
.GetHeight() ;
632 info
->bmiHeader
.biPlanes
= 1 ;
633 info
->bmiHeader
.biBitCount
= 8 ;
634 info
->bmiHeader
.biCompression
= BI_RGB
;
636 HDC display
= GetDC( NULL
) ;
637 if ( GetDIBits( display
, (HBITMAP
) bmp
.GetHBITMAP( ) , 0 , bmp
.GetHeight() , bits
, info
, DIB_RGB_COLORS
) )
639 StretchDIBits( (HDC
) m_hDC
,
640 x
, y
, bmp
.GetWidth(), bmp
.GetHeight() ,
641 0 , 0 ,bmp
.GetWidth(), bmp
.GetHeight() ,
642 bits
, info
, DIB_RGB_COLORS
, SRCCOPY
) ;
644 ReleaseDC( NULL
, display
) ;
651 HDC memdc
= ::CreateCompatibleDC( cdc
);
652 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
654 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
656 ::SelectObject( memdc
, hbitmap
);
657 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
663 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
665 memDC
.SelectObject(bmp
);
667 /* Not sure if we need this. The mask should leave the
668 * masked areas as per the original background of this DC.
671 // There might be transparent areas, so make these
672 // the same colour as this DC
673 memDC.SetBackground(* GetBackground());
677 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
679 memDC
.SelectObject(wxNullBitmap
);
683 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
685 DrawAnyText(text
, x
, y
);
687 // update the bounding box
688 CalcBoundingBox(x
, y
);
691 GetTextExtent(text
, &w
, &h
);
692 CalcBoundingBox(x
+ w
, y
+ h
);
695 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
697 // prepare for drawing the text
698 if ( m_textForegroundColour
.Ok() )
699 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
701 DWORD old_background
= 0;
702 if ( m_textBackgroundColour
.Ok() )
704 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
707 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
710 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
711 text
.c_str(), text
.length()) == 0 )
713 wxLogLastError("TextOut");
716 // restore the old parameters (text foreground colour may be left because
717 // it never is set to anything else, but background should remain
718 // transparent even if we just drew an opaque string)
719 if ( m_textBackgroundColour
.Ok() )
720 (void)SetBkColor(GetHdc(), old_background
);
722 SetBkMode(GetHdc(), TRANSPARENT
);
725 void wxDC::DoDrawRotatedText(const wxString
& text
,
726 wxCoord x
, wxCoord y
,
729 // we test that we have some font because otherwise we should still use the
730 // "else" part below to avoid that DrawRotatedText(angle = 180) and
731 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
732 // font for drawing rotated fonts unfortunately)
733 if ( (angle
== 0.0) && m_font
.Ok() )
735 DoDrawText(text
, x
, y
);
739 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
740 // can't have non zero orientation/escapement
741 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
742 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
744 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
746 wxLogLastError("GetObject(hfont)");
749 // GDI wants the angle in tenth of degree
750 long angle10
= (long)(angle
* 10);
751 lf
.lfEscapement
= angle10
;
752 lf
. lfOrientation
= angle10
;
754 hfont
= ::CreateFontIndirect(&lf
);
757 wxLogLastError("CreateFont");
761 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
763 DrawAnyText(text
, x
, y
);
765 (void)::SelectObject(GetHdc(), hfontOld
);
768 // call the bounding box by adding all four vertices of the rectangle
769 // containing the text to it (simpler and probably not slower than
770 // determining which of them is really topmost/leftmost/...)
772 GetTextExtent(text
, &w
, &h
);
774 double rad
= DegToRad(angle
);
776 // "upper left" and "upper right"
777 CalcBoundingBox(x
, y
);
778 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
780 // "bottom left" and "bottom right"
781 x
+= (wxCoord
)(h
*sin(rad
));
782 y
+= (wxCoord
)(h
*cos(rad
));
783 CalcBoundingBox(x
, y
);
784 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
788 // ---------------------------------------------------------------------------
790 // ---------------------------------------------------------------------------
792 void wxDC::SetPalette(const wxPalette
& palette
)
794 // Set the old object temporarily, in case the assignment deletes an object
795 // that's not yet selected out.
798 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
806 // Setting a NULL colourmap is a way of restoring
807 // the original colourmap
810 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
817 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
819 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
821 m_oldPalette
= (WXHPALETTE
) oldPal
;
823 ::RealizePalette(GetHdc());
827 void wxDC::SetFont(const wxFont
& the_font
)
829 // Set the old object temporarily, in case the assignment deletes an object
830 // that's not yet selected out.
833 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
842 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
846 if (m_font
.Ok() && m_font
.GetResourceHandle())
848 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
849 if (f
== (HFONT
) NULL
)
851 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
854 m_oldFont
= (WXHFONT
) f
;
858 void wxDC::SetPen(const wxPen
& pen
)
860 // Set the old object temporarily, in case the assignment deletes an object
861 // that's not yet selected out.
864 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
873 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
879 if (m_pen
.GetResourceHandle())
881 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
883 m_oldPen
= (WXHPEN
) p
;
888 void wxDC::SetBrush(const wxBrush
& brush
)
890 // Set the old object temporarily, in case the assignment deletes an object
891 // that's not yet selected out.
894 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
903 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
909 if (m_brush
.GetResourceHandle())
912 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
914 m_oldBrush
= (WXHBRUSH
) b
;
919 void wxDC::SetBackground(const wxBrush
& brush
)
921 m_backgroundBrush
= brush
;
923 if (!m_backgroundBrush
.Ok())
928 bool customColours
= TRUE
;
929 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
930 // change background colours from the control-panel specified colours.
931 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
932 customColours
= FALSE
;
936 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
938 m_canvas
->SetTransparent(TRUE
);
942 // New behaviour, 10/2/99: setting the background brush of a DC
943 // doesn't affect the window background colour. However,
944 // I'm leaving in the transparency setting because it's needed by
945 // various controls (e.g. wxStaticText) to determine whether to draw
946 // transparently or not. TODO: maybe this should be a new function
947 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
949 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
950 m_canvas
->SetTransparent(FALSE
);
954 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
956 (void)SetBkColor(GetHdc(), new_color
);
960 void wxDC::SetBackgroundMode(int mode
)
962 m_backgroundMode
= mode
;
964 // SetBackgroundColour now only refers to text background
965 // and m_backgroundMode is used there
968 if (m_backgroundMode == wxTRANSPARENT)
969 ::SetBkMode(GetHdc(), TRANSPARENT);
971 ::SetBkMode(GetHdc(), OPAQUE);
975 void wxDC::SetLogicalFunction(int function
)
977 m_logicalFunction
= function
;
979 SetRop((WXHDC
) m_hDC
);
982 void wxDC::SetRop(WXHDC dc
)
984 if (!dc
|| m_logicalFunction
< 0)
988 // These may be wrong
989 switch (m_logicalFunction
)
991 // case wxXOR: c_rop = R2_XORPEN; break;
992 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
993 case wxINVERT
: c_rop
= R2_NOT
; break;
994 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
995 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
996 case wxCLEAR
: c_rop
= R2_WHITE
; break;
997 case wxSET
: c_rop
= R2_BLACK
; break;
998 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
999 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
1000 case wxAND
: c_rop
= R2_MASKPEN
; break;
1001 case wxOR
: c_rop
= R2_MERGEPEN
; break;
1002 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
1007 c_rop
= R2_COPYPEN
; break;
1009 SetROP2((HDC
) dc
, c_rop
);
1012 bool wxDC::StartDoc(const wxString
& message
)
1014 // We might be previewing, so return TRUE to let it continue.
1022 void wxDC::StartPage()
1026 void wxDC::EndPage()
1030 // ---------------------------------------------------------------------------
1032 // ---------------------------------------------------------------------------
1034 wxCoord
wxDC::GetCharHeight() const
1036 TEXTMETRIC lpTextMetric
;
1038 GetTextMetrics(GetHdc(), &lpTextMetric
);
1040 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1043 wxCoord
wxDC::GetCharWidth() const
1045 TEXTMETRIC lpTextMetric
;
1047 GetTextMetrics(GetHdc(), &lpTextMetric
);
1049 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1052 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1053 wxCoord
*descent
, wxCoord
*externalLeading
,
1054 wxFont
*theFont
) const
1056 wxFont
*fontToUse
= (wxFont
*) theFont
;
1058 fontToUse
= (wxFont
*) &m_font
;
1063 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1064 GetTextMetrics(GetHdc(), &tm
);
1066 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1067 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1068 if (descent
) *descent
= tm
.tmDescent
;
1069 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1072 void wxDC::SetMapMode(int mode
)
1074 m_mappingMode
= mode
;
1076 int pixel_width
= 0;
1077 int pixel_height
= 0;
1081 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1082 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1083 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1084 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1086 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1091 double mm2pixelsX
= pixel_width
/mm_width
;
1092 double mm2pixelsY
= pixel_height
/mm_height
;
1098 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1099 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1104 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1105 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1110 m_logicalScaleX
= mm2pixelsX
;
1111 m_logicalScaleY
= mm2pixelsY
;
1116 m_logicalScaleX
= (mm2pixelsX
/10.0);
1117 m_logicalScaleY
= (mm2pixelsY
/10.0);
1123 m_logicalScaleX
= 1.0;
1124 m_logicalScaleY
= 1.0;
1129 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1130 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1132 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1133 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1134 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1135 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1136 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1137 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1140 void wxDC::SetUserScale(double x
, double y
)
1145 SetMapMode(m_mappingMode
);
1148 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1150 m_signX
= xLeftRight
? 1 : -1;
1151 m_signY
= yBottomUp
? -1 : 1;
1153 SetMapMode(m_mappingMode
);
1156 void wxDC::SetSystemScale(double x
, double y
)
1161 SetMapMode(m_mappingMode
);
1164 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1166 m_logicalOriginX
= x
;
1167 m_logicalOriginY
= y
;
1169 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1172 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1174 m_deviceOriginX
= x
;
1175 m_deviceOriginY
= y
;
1177 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1180 // ---------------------------------------------------------------------------
1181 // coordinates transformations
1182 // ---------------------------------------------------------------------------
1184 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1186 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1189 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1191 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1194 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1196 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1199 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1201 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1204 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1206 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1209 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1211 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1214 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1216 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1219 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1221 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1224 // ---------------------------------------------------------------------------
1226 // ---------------------------------------------------------------------------
1227 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1228 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int rop
, bool useMask
)
1230 wxCoord xdest1
= xdest
;
1231 wxCoord ydest1
= ydest
;
1232 wxCoord xsrc1
= xsrc
;
1233 wxCoord ysrc1
= ysrc
;
1235 // Chris Breeze 18/5/98: use text foreground/background colours
1236 // when blitting from 1-bit bitmaps
1237 COLORREF old_textground
= ::GetTextColor(GetHdc());
1238 COLORREF old_background
= ::GetBkColor(GetHdc());
1239 if (m_textForegroundColour
.Ok())
1241 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1243 if (m_textBackgroundColour
.Ok())
1245 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1248 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1249 rop
== wxCLEAR
? WHITENESS
:
1250 rop
== wxSET
? BLACKNESS
:
1251 rop
== wxINVERT
? DSTINVERT
:
1252 rop
== wxAND
? MERGECOPY
:
1253 rop
== wxOR
? MERGEPAINT
:
1254 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1255 rop
== wxXOR
? SRCINVERT
:
1256 rop
== wxOR_REVERSE
? MERGEPAINT
:
1257 rop
== wxAND_REVERSE
? SRCERASE
:
1258 rop
== wxSRC_OR
? SRCPAINT
:
1259 rop
== wxSRC_AND
? SRCAND
:
1262 bool success
= TRUE
;
1263 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1267 // Not implemented under Win95 (or maybe a specific device?)
1268 if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1269 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1277 // New code from Chris Breeze, 15/7/98
1278 // Blit bitmap with mask
1280 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1282 // If we are printing source colours are screen colours
1283 // not printer colours and so we need copy the bitmap
1286 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1287 HDC dc_src
= (HDC
) source
->m_hDC
;
1289 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1290 for (int x
= 0; x
< width
; x
++)
1292 for (int y
= 0; y
< height
; y
++)
1294 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1297 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1298 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1299 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1300 ::FillRect(GetHdc(), &rect
, brush
);
1301 ::DeleteObject(brush
);
1305 ::SelectObject(dc_mask
, 0);
1306 ::DeleteDC(dc_mask
);
1310 // create a temp buffer bitmap and DCs to access it and the mask
1311 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1312 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1313 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1314 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1315 ::SelectObject(dc_buffer
, buffer_bmap
);
1317 // copy dest to buffer
1318 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1319 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1321 // copy src to buffer using selected raster op
1322 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1323 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1325 // set masked area in buffer to BLACK (pixel value 0)
1326 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1327 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1328 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1329 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1331 // set unmasked area in dest to BLACK
1332 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1333 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1334 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1335 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1336 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1337 ::SetTextColor(GetHdc(), prevCol
);
1339 // OR buffer to dest
1340 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1341 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1343 // tidy up temporary DCs and bitmap
1344 ::SelectObject(dc_mask
, 0);
1345 ::DeleteDC(dc_mask
);
1346 ::SelectObject(dc_buffer
, 0);
1347 ::DeleteDC(dc_buffer
);
1348 ::DeleteObject(buffer_bmap
);
1354 // If we are printing, source colours are screen colours
1355 // not printer colours and so we need copy the bitmap
1357 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1359 HDC dc_src
= (HDC
) source
->m_hDC
;
1361 for (int y
= 0; y
< height
; y
++)
1363 // This is Stefan Csomor's optimisation, where
1364 // identical adjacent pixels are drawn together.
1365 // We still need a faster way of drawing bitmaps,
1366 // perhaps converting to a DIB first and using SetDIBitsToDevice.
1367 for (int x
= 0; x
< width
; x
++)
1369 COLORREF col
= ::GetPixel(dc_src
, x
, y
) ;
1370 HBRUSH brush
= ::CreateSolidBrush( col
);
1372 rect
.left
= xdest1
+ x
;
1373 rect
.top
= ydest1
+ y
;
1374 while( (x
+ 1 < width
) && (::GetPixel(dc_src
, x
+ 1, y
) == col
) )
1378 rect
.right
= xdest1
+ x
+ 1;
1379 rect
.bottom
= rect
.top
+ 1;
1380 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1381 ::DeleteObject(brush
);
1385 HDC dc_src = (HDC) source->m_hDC;
1387 for (int x = 0; x < width; x++)
1389 for (int y = 0; y < height; y++)
1391 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
1392 rect.left = xdest1 + x; rect.right = rect.left + 1;
1393 rect.top = ydest1 + y; rect.bottom = rect.top + 1;
1394 ::FillRect(GetHdc(), &rect, brush);
1395 ::DeleteObject(brush);
1402 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1403 xsrc1
, ysrc1
, dwRop
) != 0);
1406 ::SetTextColor(GetHdc(), old_textground
);
1407 ::SetBkColor(GetHdc(), old_background
);
1412 void wxDC::DoGetSize(int *w
, int *h
) const
1414 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1415 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1418 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1420 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1421 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1424 wxSize
wxDC::GetPPI() const
1426 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1427 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1429 return wxSize(x
, y
);
1432 // For use by wxWindows only, unless custom units are required.
1433 void wxDC::SetLogicalScale(double x
, double y
)
1435 m_logicalScaleX
= x
;
1436 m_logicalScaleY
= y
;
1439 #if WXWIN_COMPATIBILITY
1440 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1441 float *descent
, float *externalLeading
,
1442 wxFont
*theFont
, bool use16bit
) const
1444 wxCoord x1
, y1
, descent1
, externalLeading1
;
1445 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1448 *descent
= descent1
;
1449 if (externalLeading
)
1450 *externalLeading
= externalLeading1
;
1454 // ---------------------------------------------------------------------------
1455 // spline drawing code
1456 // ---------------------------------------------------------------------------
1460 class wxSpline
: public wxObject
1466 wxSpline(wxList
*list
);
1467 void DeletePoints();
1469 // Doesn't delete points
1473 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1475 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1476 double a3
, double b3
, double a4
, double b4
);
1477 void wx_clear_stack();
1478 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1479 double *y3
, double *x4
, double *y4
);
1480 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1481 double x4
, double y4
);
1482 static bool wx_spline_add_point(double x
, double y
);
1483 static void wx_spline_draw_point_array(wxDC
*dc
);
1484 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1486 void wxDC::DoDrawSpline(wxList
*list
)
1488 wxSpline
spline(list
);
1490 wx_draw_open_spline(this, &spline
);
1493 wxList wx_spline_point_list
;
1495 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1498 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1499 double x1
, y1
, x2
, y2
;
1501 wxNode
*node
= spline
->points
->First();
1502 p
= (wxPoint
*)node
->Data();
1507 node
= node
->Next();
1508 p
= (wxPoint
*)node
->Data();
1512 cx1
= (double)((x1
+ x2
) / 2);
1513 cy1
= (double)((y1
+ y2
) / 2);
1514 cx2
= (double)((cx1
+ x2
) / 2);
1515 cy2
= (double)((cy1
+ y2
) / 2);
1517 wx_spline_add_point(x1
, y1
);
1519 while ((node
= node
->Next()) != NULL
)
1521 p
= (wxPoint
*)node
->Data();
1526 cx4
= (double)(x1
+ x2
) / 2;
1527 cy4
= (double)(y1
+ y2
) / 2;
1528 cx3
= (double)(x1
+ cx4
) / 2;
1529 cy3
= (double)(y1
+ cy4
) / 2;
1531 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1535 cx2
= (double)(cx1
+ x2
) / 2;
1536 cy2
= (double)(cy1
+ y2
) / 2;
1539 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1540 wx_spline_add_point(x2
, y2
);
1542 wx_spline_draw_point_array(dc
);
1546 /********************* CURVES FOR SPLINES *****************************
1548 The following spline drawing routine is from
1550 "An Algorithm for High-Speed Curve Generation"
1551 by George Merrill Chaikin,
1552 Computer Graphics and Image Processing, 3, Academic Press,
1557 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1558 Computer Graphics and Image Processing, 4, Academic Press,
1561 ***********************************************************************/
1563 #define half(z1, z2) ((z1+z2)/2.0)
1566 /* iterative version */
1568 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1571 register double xmid
, ymid
;
1572 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1575 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1577 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1578 xmid
= (double)half(x2
, x3
);
1579 ymid
= (double)half(y2
, y3
);
1580 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1581 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1582 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1583 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1585 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1586 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1587 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1588 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1594 /* utilities used by spline drawing routines */
1597 typedef struct wx_spline_stack_struct
{
1598 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1602 #define SPLINE_STACK_DEPTH 20
1603 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1604 static Stack
*wx_stack_top
;
1605 static int wx_stack_count
;
1607 void wx_clear_stack()
1609 wx_stack_top
= wx_spline_stack
;
1613 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1615 wx_stack_top
->x1
= x1
;
1616 wx_stack_top
->y1
= y1
;
1617 wx_stack_top
->x2
= x2
;
1618 wx_stack_top
->y2
= y2
;
1619 wx_stack_top
->x3
= x3
;
1620 wx_stack_top
->y3
= y3
;
1621 wx_stack_top
->x4
= x4
;
1622 wx_stack_top
->y4
= y4
;
1627 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1628 double *x3
, double *y3
, double *x4
, double *y4
)
1630 if (wx_stack_count
== 0)
1634 *x1
= wx_stack_top
->x1
;
1635 *y1
= wx_stack_top
->y1
;
1636 *x2
= wx_stack_top
->x2
;
1637 *y2
= wx_stack_top
->y2
;
1638 *x3
= wx_stack_top
->x3
;
1639 *y3
= wx_stack_top
->y3
;
1640 *x4
= wx_stack_top
->x4
;
1641 *y4
= wx_stack_top
->y4
;
1645 static bool wx_spline_add_point(double x
, double y
)
1647 wxPoint
*point
= new wxPoint
;
1650 wx_spline_point_list
.Append((wxObject
*)point
);
1654 static void wx_spline_draw_point_array(wxDC
*dc
)
1656 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1657 wxNode
*node
= wx_spline_point_list
.First();
1660 wxPoint
*point
= (wxPoint
*)node
->Data();
1663 node
= wx_spline_point_list
.First();
1667 wxSpline::wxSpline(wxList
*list
)
1672 wxSpline::~wxSpline()
1676 void wxSpline::DeletePoints()
1678 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1680 wxPoint
*point
= (wxPoint
*)node
->Data();
1688 #endif // wxUSE_SPLINES