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 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
50 #if wxUSE_COMMON_DIALOGS
51 #if wxUSE_NORLANDER_HEADERS
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 // No, I think we should simply ignore this if printing on e.g.
267 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
268 if (!m_selectedBitmap
.Ok())
271 rect
.left
= 0; rect
.top
= 0;
272 rect
.right
= m_selectedBitmap
.GetWidth();
273 rect
.bottom
= m_selectedBitmap
.GetHeight();
276 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
278 DWORD colour
= GetBkColor(GetHdc());
279 HBRUSH brush
= CreateSolidBrush(colour
);
280 FillRect(GetHdc(), &rect
, brush
);
283 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
284 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
285 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
286 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
287 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
290 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
292 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
294 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
297 CalcBoundingBox(x
, y
);
300 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
302 // added by steve 29.12.94 (copied from DrawPoint)
303 // returns TRUE for pixels in the color of the current pen
304 // and FALSE for all other pixels colors
305 // if col is non-NULL return the color of the pixel
307 // get the color of the pixel
308 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
309 // get the color of the pen
310 COLORREF pencolor
= 0x00ffffff;
313 pencolor
= m_pen
.GetColour().GetPixel();
316 // return the color of the pixel
318 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
320 // check, if color of the pixels is the same as the color
321 // of the current pen
322 return(pixelcolor
==pencolor
);
325 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
327 wxCoord x1
= x
-VIEWPORT_EXTENT
;
328 wxCoord y1
= y
-VIEWPORT_EXTENT
;
329 wxCoord x2
= x
+VIEWPORT_EXTENT
;
330 wxCoord y2
= y
+VIEWPORT_EXTENT
;
332 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
333 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
335 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
336 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
338 CalcBoundingBox(x1
, y1
);
339 CalcBoundingBox(x2
, y2
);
342 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
344 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
345 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
347 /* MATTHEW: [6] New normalization */
348 #if WX_STANDARD_GRAPHICS
349 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
352 CalcBoundingBox(x1
, y1
);
353 CalcBoundingBox(x2
, y2
);
356 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
360 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
361 if (x1
==x2
&& x2
==y2
)
363 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
367 wxCoord xx1
= XLOG2DEV(x1
);
368 wxCoord yy1
= YLOG2DEV(y1
);
369 wxCoord xx2
= XLOG2DEV(x2
);
370 wxCoord yy2
= YLOG2DEV(y2
);
371 wxCoord xxc
= XLOG2DEV(xc
);
372 wxCoord yyc
= YLOG2DEV(yc
);
373 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
375 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
376 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
377 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
378 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
379 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
380 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
382 // Have to add 1 to bottom-right corner of rectangle
383 // to make semi-circles look right (crooked line otherwise).
384 // Unfortunately this is not a reliable method, depends
385 // on the size of shape.
386 // TODO: figure out why this happens!
387 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
391 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
394 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
395 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
398 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
400 COLORREF color
= 0x00ffffff;
403 color
= m_pen
.GetColour().GetPixel();
406 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
408 CalcBoundingBox(x
, y
);
411 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
413 COLORREF old_textground
= ::GetTextColor(GetHdc());
414 COLORREF old_background
= ::GetBkColor(GetHdc());
415 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
418 if (m_textForegroundColour
.Ok())
419 { //just the oposite from what is expected see help on pattern brush
420 // 1 in mask becomes bk color
421 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
423 if (m_textBackgroundColour
.Ok())
424 { //just the oposite from what is expected
425 // 0 in mask becomes text color
426 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
429 if (m_backgroundMode
== wxTRANSPARENT
)
430 SetBkMode(GetHdc(), TRANSPARENT
);
432 SetBkMode(GetHdc(), OPAQUE
);
435 // Do things less efficiently if we have offsets
436 if (xoffset
!= 0 || yoffset
!= 0)
438 POINT
*cpoints
= new POINT
[n
];
440 for (i
= 0; i
< n
; i
++)
442 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
443 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
445 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
447 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
448 (void)Polygon(GetHdc(), cpoints
, n
);
449 SetPolyFillMode(GetHdc(),prev
);
455 for (i
= 0; i
< n
; i
++)
456 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
458 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
459 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
460 SetPolyFillMode(GetHdc(),prev
);
463 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
465 ::SetBkMode(GetHdc(), TRANSPARENT
);
466 ::SetTextColor(GetHdc(), old_textground
);
467 ::SetBkColor(GetHdc(), old_background
);
471 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
473 // Do things less efficiently if we have offsets
474 if (xoffset
!= 0 || yoffset
!= 0)
476 POINT
*cpoints
= new POINT
[n
];
478 for (i
= 0; i
< n
; i
++)
480 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
481 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
483 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
485 (void)Polyline(GetHdc(), cpoints
, n
);
491 for (i
= 0; i
< n
; i
++)
492 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
494 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
498 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
500 COLORREF old_textground
= ::GetTextColor(GetHdc());
501 COLORREF old_background
= ::GetBkColor(GetHdc());
502 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
505 if (m_textForegroundColour
.Ok())
506 { //just the oposite from what is expected see help on pattern brush
507 // 1 in mask becomes bk color
508 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
510 if (m_textBackgroundColour
.Ok())
511 { //just the oposite from what is expected
512 // 0 in mask becomes text color
513 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
516 if (m_backgroundMode
== wxTRANSPARENT
)
517 SetBkMode(GetHdc(), TRANSPARENT
);
519 SetBkMode(GetHdc(), OPAQUE
);
522 wxCoord x2
= x
+ width
;
523 wxCoord y2
= y
+ height
;
525 /* MATTHEW: [6] new normalization */
526 #if WX_STANDARD_GRAPHICS
527 bool do_brush
, do_pen
;
529 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
530 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
533 HPEN orig_pen
= NULL
;
535 if (do_pen
|| !m_pen
.Ok())
536 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
538 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
539 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
541 if (do_pen
|| !m_pen
.Ok())
542 ::SelectObject(GetHdc() , orig_pen
);
545 HBRUSH orig_brush
= NULL
;
547 if (do_brush
|| !m_brush
.Ok())
548 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
550 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
551 XLOG2DEV(x2
), YLOG2DEV(y2
));
553 if (do_brush
|| !m_brush
.Ok())
554 ::SelectObject(GetHdc(), orig_brush
);
557 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
560 CalcBoundingBox(x
, y
);
561 CalcBoundingBox(x2
, y2
);
563 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
565 ::SetBkMode(GetHdc(), TRANSPARENT
);
566 ::SetTextColor(GetHdc(), old_textground
);
567 ::SetBkColor(GetHdc(), old_background
);
571 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
573 // Now, a negative radius value is interpreted to mean
574 // 'the proportion of the smallest X or Y dimension'
578 double smallest
= 0.0;
583 radius
= (- radius
* smallest
);
586 wxCoord x2
= (x
+width
);
587 wxCoord y2
= (y
+height
);
589 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
590 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
592 CalcBoundingBox(x
, y
);
593 CalcBoundingBox(x2
, y2
);
596 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
598 wxCoord x2
= (x
+width
);
599 wxCoord y2
= (y
+height
);
601 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
603 CalcBoundingBox(x
, y
);
604 CalcBoundingBox(x2
, y2
);
607 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
608 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
613 int rx1
= XLOG2DEV(x
+w
/2);
614 int ry1
= YLOG2DEV(y
+h
/2);
621 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
622 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
623 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
624 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
626 // draw pie with NULL_PEN first and then outline otherwise a line is
627 // drawn from the start and end points to the centre
628 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
631 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
636 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
637 rx1
, ry1
-1, rx2
, ry2
-1);
639 ::SelectObject(GetHdc(), orig_pen
);
640 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
643 CalcBoundingBox(x
, y
);
644 CalcBoundingBox(x2
, y2
);
647 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
649 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
651 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
653 CalcBoundingBox(x
, y
);
654 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
657 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
659 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
661 int width
= bmp
.GetWidth(),
662 height
= bmp
.GetHeight();
667 HDC memdc
= ::CreateCompatibleDC( cdc
);
668 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
670 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
672 COLORREF old_textground
= ::GetTextColor(GetHdc());
673 COLORREF old_background
= ::GetBkColor(GetHdc());
674 if (m_textForegroundColour
.Ok())
676 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
678 if (m_textBackgroundColour
.Ok())
680 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
683 ::SelectObject( memdc
, hbitmap
);
684 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
687 ::SetTextColor(GetHdc(), old_textground
);
688 ::SetBkColor(GetHdc(), old_background
);
692 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
694 memDC
.SelectObject(bmp
);
696 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
698 memDC
.SelectObject(wxNullBitmap
);
702 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
704 DrawAnyText(text
, x
, y
);
706 // update the bounding box
707 CalcBoundingBox(x
, y
);
710 GetTextExtent(text
, &w
, &h
);
711 CalcBoundingBox(x
+ w
, y
+ h
);
714 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
716 // prepare for drawing the text
717 if ( m_textForegroundColour
.Ok() )
718 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
720 DWORD old_background
= 0;
721 if ( m_textBackgroundColour
.Ok() )
723 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
726 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
729 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
730 text
.c_str(), text
.length()) == 0 )
732 wxLogLastError("TextOut");
735 // restore the old parameters (text foreground colour may be left because
736 // it never is set to anything else, but background should remain
737 // transparent even if we just drew an opaque string)
738 if ( m_textBackgroundColour
.Ok() )
739 (void)SetBkColor(GetHdc(), old_background
);
741 SetBkMode(GetHdc(), TRANSPARENT
);
744 void wxDC::DoDrawRotatedText(const wxString
& text
,
745 wxCoord x
, wxCoord y
,
748 // we test that we have some font because otherwise we should still use the
749 // "else" part below to avoid that DrawRotatedText(angle = 180) and
750 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
751 // font for drawing rotated fonts unfortunately)
752 if ( (angle
== 0.0) && m_font
.Ok() )
754 DoDrawText(text
, x
, y
);
758 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
759 // can't have non zero orientation/escapement
760 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
761 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
763 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
765 wxLogLastError("GetObject(hfont)");
768 // GDI wants the angle in tenth of degree
769 long angle10
= (long)(angle
* 10);
770 lf
.lfEscapement
= angle10
;
771 lf
. lfOrientation
= angle10
;
773 hfont
= ::CreateFontIndirect(&lf
);
776 wxLogLastError("CreateFont");
780 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
782 DrawAnyText(text
, x
, y
);
784 (void)::SelectObject(GetHdc(), hfontOld
);
787 // call the bounding box by adding all four vertices of the rectangle
788 // containing the text to it (simpler and probably not slower than
789 // determining which of them is really topmost/leftmost/...)
791 GetTextExtent(text
, &w
, &h
);
793 double rad
= DegToRad(angle
);
795 // "upper left" and "upper right"
796 CalcBoundingBox(x
, y
);
797 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
799 // "bottom left" and "bottom right"
800 x
+= (wxCoord
)(h
*sin(rad
));
801 y
+= (wxCoord
)(h
*cos(rad
));
802 CalcBoundingBox(x
, y
);
803 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
807 // ---------------------------------------------------------------------------
809 // ---------------------------------------------------------------------------
811 void wxDC::SetPalette(const wxPalette
& palette
)
813 // Set the old object temporarily, in case the assignment deletes an object
814 // that's not yet selected out.
817 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
825 // Setting a NULL colourmap is a way of restoring
826 // the original colourmap
829 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
836 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
838 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
840 m_oldPalette
= (WXHPALETTE
) oldPal
;
842 ::RealizePalette(GetHdc());
846 void wxDC::SetFont(const wxFont
& the_font
)
848 // Set the old object temporarily, in case the assignment deletes an object
849 // that's not yet selected out.
852 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
861 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
865 if (m_font
.Ok() && m_font
.GetResourceHandle())
867 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
868 if (f
== (HFONT
) NULL
)
870 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
873 m_oldFont
= (WXHFONT
) f
;
877 void wxDC::SetPen(const wxPen
& pen
)
879 // Set the old object temporarily, in case the assignment deletes an object
880 // that's not yet selected out.
883 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
892 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
898 if (m_pen
.GetResourceHandle())
900 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
902 m_oldPen
= (WXHPEN
) p
;
907 void wxDC::SetBrush(const wxBrush
& brush
)
909 // Set the old object temporarily, in case the assignment deletes an object
910 // that's not yet selected out.
913 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
922 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
928 if (m_brush
.GetResourceHandle())
931 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
933 m_oldBrush
= (WXHBRUSH
) b
;
938 void wxDC::SetBackground(const wxBrush
& brush
)
940 m_backgroundBrush
= brush
;
942 if (!m_backgroundBrush
.Ok())
947 bool customColours
= TRUE
;
948 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
949 // change background colours from the control-panel specified colours.
950 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
951 customColours
= FALSE
;
955 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
957 m_canvas
->SetTransparent(TRUE
);
961 // New behaviour, 10/2/99: setting the background brush of a DC
962 // doesn't affect the window background colour. However,
963 // I'm leaving in the transparency setting because it's needed by
964 // various controls (e.g. wxStaticText) to determine whether to draw
965 // transparently or not. TODO: maybe this should be a new function
966 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
968 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
969 m_canvas
->SetTransparent(FALSE
);
973 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
975 (void)SetBkColor(GetHdc(), new_color
);
979 void wxDC::SetBackgroundMode(int mode
)
981 m_backgroundMode
= mode
;
983 // SetBackgroundColour now only refers to text background
984 // and m_backgroundMode is used there
987 if (m_backgroundMode == wxTRANSPARENT)
988 ::SetBkMode(GetHdc(), TRANSPARENT);
990 ::SetBkMode(GetHdc(), OPAQUE);
994 void wxDC::SetLogicalFunction(int function
)
996 m_logicalFunction
= function
;
998 SetRop((WXHDC
) m_hDC
);
1001 void wxDC::SetRop(WXHDC dc
)
1003 if (!dc
|| m_logicalFunction
< 0)
1007 // These may be wrong
1008 switch (m_logicalFunction
)
1010 // case wxXOR: c_rop = R2_XORPEN; break;
1011 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
1012 case wxINVERT
: c_rop
= R2_NOT
; break;
1013 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
1014 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
1015 case wxCLEAR
: c_rop
= R2_WHITE
; break;
1016 case wxSET
: c_rop
= R2_BLACK
; break;
1017 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
1018 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
1019 case wxAND
: c_rop
= R2_MASKPEN
; break;
1020 case wxOR
: c_rop
= R2_MERGEPEN
; break;
1021 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
1026 c_rop
= R2_COPYPEN
; break;
1028 SetROP2((HDC
) dc
, c_rop
);
1031 bool wxDC::StartDoc(const wxString
& message
)
1033 // We might be previewing, so return TRUE to let it continue.
1041 void wxDC::StartPage()
1045 void wxDC::EndPage()
1049 // ---------------------------------------------------------------------------
1051 // ---------------------------------------------------------------------------
1053 wxCoord
wxDC::GetCharHeight() const
1055 TEXTMETRIC lpTextMetric
;
1057 GetTextMetrics(GetHdc(), &lpTextMetric
);
1059 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1062 wxCoord
wxDC::GetCharWidth() const
1064 TEXTMETRIC lpTextMetric
;
1066 GetTextMetrics(GetHdc(), &lpTextMetric
);
1068 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1071 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1072 wxCoord
*descent
, wxCoord
*externalLeading
,
1073 wxFont
*theFont
) const
1075 wxFont
*fontToUse
= (wxFont
*) theFont
;
1077 fontToUse
= (wxFont
*) &m_font
;
1082 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1083 GetTextMetrics(GetHdc(), &tm
);
1085 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1086 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1087 if (descent
) *descent
= tm
.tmDescent
;
1088 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1091 void wxDC::SetMapMode(int mode
)
1093 m_mappingMode
= mode
;
1095 int pixel_width
= 0;
1096 int pixel_height
= 0;
1100 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1101 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1102 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1103 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1105 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1110 double mm2pixelsX
= pixel_width
/mm_width
;
1111 double mm2pixelsY
= pixel_height
/mm_height
;
1117 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1118 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1123 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1124 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1129 m_logicalScaleX
= mm2pixelsX
;
1130 m_logicalScaleY
= mm2pixelsY
;
1135 m_logicalScaleX
= (mm2pixelsX
/10.0);
1136 m_logicalScaleY
= (mm2pixelsY
/10.0);
1142 m_logicalScaleX
= 1.0;
1143 m_logicalScaleY
= 1.0;
1148 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1149 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1151 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1152 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1153 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1154 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1155 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1156 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1159 void wxDC::SetUserScale(double x
, double y
)
1164 SetMapMode(m_mappingMode
);
1167 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1169 m_signX
= xLeftRight
? 1 : -1;
1170 m_signY
= yBottomUp
? -1 : 1;
1172 SetMapMode(m_mappingMode
);
1175 void wxDC::SetSystemScale(double x
, double y
)
1180 SetMapMode(m_mappingMode
);
1183 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1185 m_logicalOriginX
= x
;
1186 m_logicalOriginY
= y
;
1188 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1191 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1193 m_deviceOriginX
= x
;
1194 m_deviceOriginY
= y
;
1196 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1199 // ---------------------------------------------------------------------------
1200 // coordinates transformations
1201 // ---------------------------------------------------------------------------
1203 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1205 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1208 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1210 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1213 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1215 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1218 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1220 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1223 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1225 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1228 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1230 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1233 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1235 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1238 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1240 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1243 // ---------------------------------------------------------------------------
1245 // ---------------------------------------------------------------------------
1247 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1248 wxCoord width
, wxCoord height
,
1249 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1250 int rop
, bool useMask
)
1252 wxMask
*mask
= NULL
;
1255 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1256 mask
= bmp
.GetMask();
1258 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1260 // don't give assert here because this would break existing
1261 // programs - just silently ignore useMask parameter
1266 COLORREF old_textground
= ::GetTextColor(GetHdc());
1267 COLORREF old_background
= ::GetBkColor(GetHdc());
1268 if (m_textForegroundColour
.Ok())
1270 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1272 if (m_textBackgroundColour
.Ok())
1274 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1277 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1278 rop
== wxCLEAR
? WHITENESS
:
1279 rop
== wxSET
? BLACKNESS
:
1280 rop
== wxINVERT
? DSTINVERT
:
1281 rop
== wxAND
? MERGECOPY
:
1282 rop
== wxOR
? MERGEPAINT
:
1283 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1284 rop
== wxXOR
? SRCINVERT
:
1285 rop
== wxOR_REVERSE
? MERGEPAINT
:
1286 rop
== wxAND_REVERSE
? SRCERASE
:
1287 rop
== wxSRC_OR
? SRCPAINT
:
1288 rop
== wxSRC_AND
? SRCAND
:
1296 HBITMAP hbmpMask
= wxInvertMask((HBITMAP
)mask
->GetMaskBitmap());
1298 // we want the part of the image corresponding to the mask to be
1299 // transparent, i.e. do PATCOPY there and apply dwRop elsewhere
1300 const wxColour
& colBg
= m_backgroundBrush
.GetColour();
1301 HBRUSH hbrBg
= (HBRUSH
)::CreateSolidBrush(wxColourToRGB(colBg
));
1302 HBRUSH hbrOld
= (HBRUSH
)::SelectObject(GetHdc(), hbrBg
);
1304 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1305 GetHdcOf(*source
), xsrc
, ysrc
,
1307 MAKEROP4(PATCOPY
, dwRop
)) != 0;
1309 (void)::SelectObject(GetHdc(), hbrOld
);
1310 ::DeleteObject(hbrOld
);
1311 ::DeleteObject(hbmpMask
);
1316 // Blit bitmap with mask
1318 // create a temp buffer bitmap and DCs to access it and the mask
1319 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1320 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1321 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1322 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1323 ::SelectObject(dc_buffer
, buffer_bmap
);
1325 // copy dest to buffer
1326 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1327 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1329 wxLogLastError("BitBlt");
1332 // copy src to buffer using selected raster op
1333 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1334 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1336 wxLogLastError("BitBlt");
1339 // set masked area in buffer to BLACK (pixel value 0)
1340 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1341 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1342 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1343 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1345 wxLogLastError("BitBlt");
1348 // set unmasked area in dest to BLACK
1349 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1350 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1351 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1352 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1354 wxLogLastError("BitBlt");
1356 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1357 ::SetTextColor(GetHdc(), prevCol
);
1359 // OR buffer to dest
1360 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1361 (int)width
, (int)height
,
1362 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1365 wxLogLastError("BitBlt");
1368 // tidy up temporary DCs and bitmap
1369 ::SelectObject(dc_mask
, 0);
1370 ::DeleteDC(dc_mask
);
1371 ::SelectObject(dc_buffer
, 0);
1372 ::DeleteDC(dc_buffer
);
1373 ::DeleteObject(buffer_bmap
);
1376 else // no mask, just BitBlt() it
1378 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1379 (int)width
, (int)height
,
1380 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1383 wxLogLastError("BitBlt");
1387 ::SetTextColor(GetHdc(), old_textground
);
1388 ::SetBkColor(GetHdc(), old_background
);
1393 void wxDC::DoGetSize(int *w
, int *h
) const
1395 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1396 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1399 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1401 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1402 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1405 wxSize
wxDC::GetPPI() const
1407 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1408 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1410 return wxSize(x
, y
);
1413 // For use by wxWindows only, unless custom units are required.
1414 void wxDC::SetLogicalScale(double x
, double y
)
1416 m_logicalScaleX
= x
;
1417 m_logicalScaleY
= y
;
1420 #if WXWIN_COMPATIBILITY
1421 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1422 float *descent
, float *externalLeading
,
1423 wxFont
*theFont
, bool use16bit
) const
1425 wxCoord x1
, y1
, descent1
, externalLeading1
;
1426 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1429 *descent
= descent1
;
1430 if (externalLeading
)
1431 *externalLeading
= externalLeading1
;
1435 // ---------------------------------------------------------------------------
1436 // spline drawing code
1437 // ---------------------------------------------------------------------------
1441 class wxSpline
: public wxObject
1447 wxSpline(wxList
*list
);
1448 void DeletePoints();
1450 // Doesn't delete points
1454 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1456 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1457 double a3
, double b3
, double a4
, double b4
);
1458 void wx_clear_stack();
1459 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1460 double *y3
, double *x4
, double *y4
);
1461 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1462 double x4
, double y4
);
1463 static bool wx_spline_add_point(double x
, double y
);
1464 static void wx_spline_draw_point_array(wxDC
*dc
);
1465 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1467 void wxDC::DoDrawSpline(wxList
*list
)
1469 wxSpline
spline(list
);
1471 wx_draw_open_spline(this, &spline
);
1474 wxList wx_spline_point_list
;
1476 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1479 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1480 double x1
, y1
, x2
, y2
;
1482 wxNode
*node
= spline
->points
->First();
1483 p
= (wxPoint
*)node
->Data();
1488 node
= node
->Next();
1489 p
= (wxPoint
*)node
->Data();
1493 cx1
= (double)((x1
+ x2
) / 2);
1494 cy1
= (double)((y1
+ y2
) / 2);
1495 cx2
= (double)((cx1
+ x2
) / 2);
1496 cy2
= (double)((cy1
+ y2
) / 2);
1498 wx_spline_add_point(x1
, y1
);
1500 while ((node
= node
->Next()) != NULL
)
1502 p
= (wxPoint
*)node
->Data();
1507 cx4
= (double)(x1
+ x2
) / 2;
1508 cy4
= (double)(y1
+ y2
) / 2;
1509 cx3
= (double)(x1
+ cx4
) / 2;
1510 cy3
= (double)(y1
+ cy4
) / 2;
1512 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1516 cx2
= (double)(cx1
+ x2
) / 2;
1517 cy2
= (double)(cy1
+ y2
) / 2;
1520 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1521 wx_spline_add_point(x2
, y2
);
1523 wx_spline_draw_point_array(dc
);
1527 /********************* CURVES FOR SPLINES *****************************
1529 The following spline drawing routine is from
1531 "An Algorithm for High-Speed Curve Generation"
1532 by George Merrill Chaikin,
1533 Computer Graphics and Image Processing, 3, Academic Press,
1538 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1539 Computer Graphics and Image Processing, 4, Academic Press,
1542 ***********************************************************************/
1544 #define half(z1, z2) ((z1+z2)/2.0)
1547 /* iterative version */
1549 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1552 register double xmid
, ymid
;
1553 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1556 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1558 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1559 xmid
= (double)half(x2
, x3
);
1560 ymid
= (double)half(y2
, y3
);
1561 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1562 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1563 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1564 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1566 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1567 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1568 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1569 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1575 /* utilities used by spline drawing routines */
1578 typedef struct wx_spline_stack_struct
{
1579 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1583 #define SPLINE_STACK_DEPTH 20
1584 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1585 static Stack
*wx_stack_top
;
1586 static int wx_stack_count
;
1588 void wx_clear_stack()
1590 wx_stack_top
= wx_spline_stack
;
1594 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1596 wx_stack_top
->x1
= x1
;
1597 wx_stack_top
->y1
= y1
;
1598 wx_stack_top
->x2
= x2
;
1599 wx_stack_top
->y2
= y2
;
1600 wx_stack_top
->x3
= x3
;
1601 wx_stack_top
->y3
= y3
;
1602 wx_stack_top
->x4
= x4
;
1603 wx_stack_top
->y4
= y4
;
1608 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1609 double *x3
, double *y3
, double *x4
, double *y4
)
1611 if (wx_stack_count
== 0)
1615 *x1
= wx_stack_top
->x1
;
1616 *y1
= wx_stack_top
->y1
;
1617 *x2
= wx_stack_top
->x2
;
1618 *y2
= wx_stack_top
->y2
;
1619 *x3
= wx_stack_top
->x3
;
1620 *y3
= wx_stack_top
->y3
;
1621 *x4
= wx_stack_top
->x4
;
1622 *y4
= wx_stack_top
->y4
;
1626 static bool wx_spline_add_point(double x
, double y
)
1628 wxPoint
*point
= new wxPoint
;
1631 wx_spline_point_list
.Append((wxObject
*)point
);
1635 static void wx_spline_draw_point_array(wxDC
*dc
)
1637 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1638 wxNode
*node
= wx_spline_point_list
.First();
1641 wxPoint
*point
= (wxPoint
*)node
->Data();
1644 node
= wx_spline_point_list
.First();
1648 wxSpline::wxSpline(wxList
*list
)
1653 wxSpline::~wxSpline()
1657 void wxSpline::DeletePoints()
1659 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1661 wxPoint
*point
= (wxPoint
*)node
->Data();
1669 #endif // wxUSE_SPLINES