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"
26 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/dcprint.h"
49 #if wxUSE_COMMON_DIALOGS
50 #if wxUSE_NORLANDER_HEADERS
60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
62 // ---------------------------------------------------------------------------
64 // ---------------------------------------------------------------------------
66 static const int VIEWPORT_EXTENT
= 1000;
68 static const int MM_POINTS
= 9;
69 static const int MM_METRIC
= 10;
71 // usually this is defined in math.h
73 static const double M_PI
= 3.14159265358979323846;
76 // ---------------------------------------------------------------------------
78 // ---------------------------------------------------------------------------
80 // convert degrees to radians
81 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
83 // ===========================================================================
85 // ===========================================================================
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 // Default constructor
105 m_windowExtX
= VIEWPORT_EXTENT
;
106 m_windowExtY
= VIEWPORT_EXTENT
;
115 SelectOldObjects(m_hDC
);
117 if ( m_canvas
== NULL
)
118 ::DeleteDC(GetHdc());
120 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
126 // This will select current objects out of the DC,
127 // which is what you have to do before deleting the
129 void wxDC::SelectOldObjects(WXHDC dc
)
135 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
136 if (m_selectedBitmap
.Ok())
138 m_selectedBitmap
.SetSelectedInto(NULL
);
144 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
149 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
154 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
159 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
164 m_brush
= wxNullBrush
;
166 m_palette
= wxNullPalette
;
168 m_backgroundBrush
= wxNullBrush
;
169 m_selectedBitmap
= wxNullBitmap
;
172 // ---------------------------------------------------------------------------
174 // ---------------------------------------------------------------------------
176 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
181 m_clipX2
= (int)(cx
+ cw
);
182 m_clipY2
= (int)(cy
+ ch
);
184 DoClipping((WXHDC
) m_hDC
);
187 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
189 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
191 wxRect box
= region
.GetBox();
196 m_clipX2
= box
.x
+ box
.width
;
197 m_clipY2
= box
.y
+ box
.height
;
200 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
202 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
206 void wxDC::DoClipping(WXHDC dc
)
208 if (m_clipping
&& dc
)
210 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
211 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
215 void wxDC::DestroyClippingRegion()
217 if (m_clipping
&& m_hDC
)
219 // TODO: this should restore the previous clipping region,
220 // so that OnPaint processing works correctly, and the update clipping region
221 // doesn't get destroyed after the first DestroyClippingRegion.
222 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
223 SelectClipRgn(GetHdc(), rgn
);
229 // ---------------------------------------------------------------------------
230 // query capabilities
231 // ---------------------------------------------------------------------------
233 bool wxDC::CanDrawBitmap() const
238 bool wxDC::CanGetTextExtent() const
240 // What sort of display is it?
241 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
243 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
246 int wxDC::GetDepth() const
248 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
251 // ---------------------------------------------------------------------------
253 // ---------------------------------------------------------------------------
260 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
264 // No, I think we should simply ignore this if printing on e.g.
266 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
267 if (!m_selectedBitmap
.Ok())
270 rect
.left
= 0; rect
.top
= 0;
271 rect
.right
= m_selectedBitmap
.GetWidth();
272 rect
.bottom
= m_selectedBitmap
.GetHeight();
275 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
277 DWORD colour
= GetBkColor(GetHdc());
278 HBRUSH brush
= CreateSolidBrush(colour
);
279 FillRect(GetHdc(), &rect
, brush
);
282 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
283 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
284 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
285 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
286 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
289 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
291 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
293 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
296 CalcBoundingBox(x
, y
);
299 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
301 // added by steve 29.12.94 (copied from DrawPoint)
302 // returns TRUE for pixels in the color of the current pen
303 // and FALSE for all other pixels colors
304 // if col is non-NULL return the color of the pixel
306 // get the color of the pixel
307 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
308 // get the color of the pen
309 COLORREF pencolor
= 0x00ffffff;
312 pencolor
= m_pen
.GetColour().GetPixel();
315 // return the color of the pixel
317 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
319 // check, if color of the pixels is the same as the color
320 // of the current pen
321 return(pixelcolor
==pencolor
);
324 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
326 wxCoord x1
= x
-VIEWPORT_EXTENT
;
327 wxCoord y1
= y
-VIEWPORT_EXTENT
;
328 wxCoord x2
= x
+VIEWPORT_EXTENT
;
329 wxCoord y2
= y
+VIEWPORT_EXTENT
;
331 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
332 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
334 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
335 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
337 CalcBoundingBox(x1
, y1
);
338 CalcBoundingBox(x2
, y2
);
341 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
343 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
344 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
346 /* MATTHEW: [6] New normalization */
347 #if WX_STANDARD_GRAPHICS
348 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
351 CalcBoundingBox(x1
, y1
);
352 CalcBoundingBox(x2
, y2
);
355 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
359 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
360 if (x1
==x2
&& x2
==y2
)
362 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
366 wxCoord xx1
= XLOG2DEV(x1
);
367 wxCoord yy1
= YLOG2DEV(y1
);
368 wxCoord xx2
= XLOG2DEV(x2
);
369 wxCoord yy2
= YLOG2DEV(y2
);
370 wxCoord xxc
= XLOG2DEV(xc
);
371 wxCoord yyc
= YLOG2DEV(yc
);
372 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
374 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
375 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
376 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
377 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
378 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
379 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
381 // Have to add 1 to bottom-right corner of rectangle
382 // to make semi-circles look right (crooked line otherwise).
383 // Unfortunately this is not a reliable method, depends
384 // on the size of shape.
385 // TODO: figure out why this happens!
386 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
390 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
393 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
394 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
397 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
399 COLORREF color
= 0x00ffffff;
402 color
= m_pen
.GetColour().GetPixel();
405 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
407 CalcBoundingBox(x
, y
);
410 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
412 COLORREF old_textground
= ::GetTextColor(GetHdc());
413 COLORREF old_background
= ::GetBkColor(GetHdc());
414 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
417 if (m_textForegroundColour
.Ok())
418 { //just the oposite from what is expected see help on pattern brush
419 // 1 in mask becomes bk color
420 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
422 if (m_textBackgroundColour
.Ok())
423 { //just the oposite from what is expected
424 // 0 in mask becomes text color
425 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
428 if (m_backgroundMode
== wxTRANSPARENT
)
429 SetBkMode(GetHdc(), TRANSPARENT
);
431 SetBkMode(GetHdc(), OPAQUE
);
434 // Do things less efficiently if we have offsets
435 if (xoffset
!= 0 || yoffset
!= 0)
437 POINT
*cpoints
= new POINT
[n
];
439 for (i
= 0; i
< n
; i
++)
441 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
442 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
444 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
446 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
447 (void)Polygon(GetHdc(), cpoints
, n
);
448 SetPolyFillMode(GetHdc(),prev
);
454 for (i
= 0; i
< n
; i
++)
455 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
457 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
458 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
459 SetPolyFillMode(GetHdc(),prev
);
462 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
464 ::SetBkMode(GetHdc(), TRANSPARENT
);
465 ::SetTextColor(GetHdc(), old_textground
);
466 ::SetBkColor(GetHdc(), old_background
);
470 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
472 // Do things less efficiently if we have offsets
473 if (xoffset
!= 0 || yoffset
!= 0)
475 POINT
*cpoints
= new POINT
[n
];
477 for (i
= 0; i
< n
; i
++)
479 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
480 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
482 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
484 (void)Polyline(GetHdc(), cpoints
, n
);
490 for (i
= 0; i
< n
; i
++)
491 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
493 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
497 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
499 COLORREF old_textground
= ::GetTextColor(GetHdc());
500 COLORREF old_background
= ::GetBkColor(GetHdc());
501 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
504 if (m_textForegroundColour
.Ok())
505 { //just the oposite from what is expected see help on pattern brush
506 // 1 in mask becomes bk color
507 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
509 if (m_textBackgroundColour
.Ok())
510 { //just the oposite from what is expected
511 // 0 in mask becomes text color
512 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
515 if (m_backgroundMode
== wxTRANSPARENT
)
516 SetBkMode(GetHdc(), TRANSPARENT
);
518 SetBkMode(GetHdc(), OPAQUE
);
521 wxCoord x2
= x
+ width
;
522 wxCoord y2
= y
+ height
;
524 /* MATTHEW: [6] new normalization */
525 #if WX_STANDARD_GRAPHICS
526 bool do_brush
, do_pen
;
528 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
529 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
532 HPEN orig_pen
= NULL
;
534 if (do_pen
|| !m_pen
.Ok())
535 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
537 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
538 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
540 if (do_pen
|| !m_pen
.Ok())
541 ::SelectObject(GetHdc() , orig_pen
);
544 HBRUSH orig_brush
= NULL
;
546 if (do_brush
|| !m_brush
.Ok())
547 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
549 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
550 XLOG2DEV(x2
), YLOG2DEV(y2
));
552 if (do_brush
|| !m_brush
.Ok())
553 ::SelectObject(GetHdc(), orig_brush
);
556 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
559 CalcBoundingBox(x
, y
);
560 CalcBoundingBox(x2
, y2
);
562 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
564 ::SetBkMode(GetHdc(), TRANSPARENT
);
565 ::SetTextColor(GetHdc(), old_textground
);
566 ::SetBkColor(GetHdc(), old_background
);
570 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
572 // Now, a negative radius value is interpreted to mean
573 // 'the proportion of the smallest X or Y dimension'
577 double smallest
= 0.0;
582 radius
= (- radius
* smallest
);
585 wxCoord x2
= (x
+width
);
586 wxCoord y2
= (y
+height
);
588 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
589 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
591 CalcBoundingBox(x
, y
);
592 CalcBoundingBox(x2
, y2
);
595 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
597 wxCoord x2
= (x
+width
);
598 wxCoord y2
= (y
+height
);
600 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
602 CalcBoundingBox(x
, y
);
603 CalcBoundingBox(x2
, y2
);
606 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
607 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
612 int rx1
= XLOG2DEV(x
+w
/2);
613 int ry1
= YLOG2DEV(y
+h
/2);
620 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
621 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
622 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
623 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
625 // draw pie with NULL_PEN first and then outline otherwise a line is
626 // drawn from the start and end points to the centre
627 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
630 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
635 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
636 rx1
, ry1
-1, rx2
, ry2
-1);
638 ::SelectObject(GetHdc(), orig_pen
);
639 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
642 CalcBoundingBox(x
, y
);
643 CalcBoundingBox(x2
, y2
);
646 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
648 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
650 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
652 CalcBoundingBox(x
, y
);
653 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
656 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
658 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
660 int width
= bmp
.GetWidth(),
661 height
= bmp
.GetHeight();
666 HDC memdc
= ::CreateCompatibleDC( cdc
);
667 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
669 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
671 COLORREF old_textground
= ::GetTextColor(GetHdc());
672 COLORREF old_background
= ::GetBkColor(GetHdc());
673 if (m_textForegroundColour
.Ok())
675 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
677 if (m_textBackgroundColour
.Ok())
679 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
682 ::SelectObject( memdc
, hbitmap
);
683 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
686 ::SetTextColor(GetHdc(), old_textground
);
687 ::SetBkColor(GetHdc(), old_background
);
691 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
693 memDC
.SelectObject(bmp
);
695 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
697 memDC
.SelectObject(wxNullBitmap
);
701 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
703 DrawAnyText(text
, x
, y
);
705 // update the bounding box
706 CalcBoundingBox(x
, y
);
709 GetTextExtent(text
, &w
, &h
);
710 CalcBoundingBox(x
+ w
, y
+ h
);
713 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
715 // prepare for drawing the text
716 if ( m_textForegroundColour
.Ok() )
717 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
719 DWORD old_background
= 0;
720 if ( m_textBackgroundColour
.Ok() )
722 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
725 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
728 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
729 text
.c_str(), text
.length()) == 0 )
731 wxLogLastError("TextOut");
734 // restore the old parameters (text foreground colour may be left because
735 // it never is set to anything else, but background should remain
736 // transparent even if we just drew an opaque string)
737 if ( m_textBackgroundColour
.Ok() )
738 (void)SetBkColor(GetHdc(), old_background
);
740 SetBkMode(GetHdc(), TRANSPARENT
);
743 void wxDC::DoDrawRotatedText(const wxString
& text
,
744 wxCoord x
, wxCoord y
,
747 // we test that we have some font because otherwise we should still use the
748 // "else" part below to avoid that DrawRotatedText(angle = 180) and
749 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
750 // font for drawing rotated fonts unfortunately)
751 if ( (angle
== 0.0) && m_font
.Ok() )
753 DoDrawText(text
, x
, y
);
757 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
758 // can't have non zero orientation/escapement
759 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
760 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
762 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
764 wxLogLastError("GetObject(hfont)");
767 // GDI wants the angle in tenth of degree
768 long angle10
= (long)(angle
* 10);
769 lf
.lfEscapement
= angle10
;
770 lf
. lfOrientation
= angle10
;
772 hfont
= ::CreateFontIndirect(&lf
);
775 wxLogLastError("CreateFont");
779 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
781 DrawAnyText(text
, x
, y
);
783 (void)::SelectObject(GetHdc(), hfontOld
);
786 // call the bounding box by adding all four vertices of the rectangle
787 // containing the text to it (simpler and probably not slower than
788 // determining which of them is really topmost/leftmost/...)
790 GetTextExtent(text
, &w
, &h
);
792 double rad
= DegToRad(angle
);
794 // "upper left" and "upper right"
795 CalcBoundingBox(x
, y
);
796 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
798 // "bottom left" and "bottom right"
799 x
+= (wxCoord
)(h
*sin(rad
));
800 y
+= (wxCoord
)(h
*cos(rad
));
801 CalcBoundingBox(x
, y
);
802 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
806 // ---------------------------------------------------------------------------
808 // ---------------------------------------------------------------------------
810 void wxDC::SetPalette(const wxPalette
& palette
)
812 // Set the old object temporarily, in case the assignment deletes an object
813 // that's not yet selected out.
816 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
824 // Setting a NULL colourmap is a way of restoring
825 // the original colourmap
828 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
835 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
837 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
839 m_oldPalette
= (WXHPALETTE
) oldPal
;
841 ::RealizePalette(GetHdc());
845 void wxDC::SetFont(const wxFont
& the_font
)
847 // Set the old object temporarily, in case the assignment deletes an object
848 // that's not yet selected out.
851 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
860 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
864 if (m_font
.Ok() && m_font
.GetResourceHandle())
866 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
867 if (f
== (HFONT
) NULL
)
869 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
872 m_oldFont
= (WXHFONT
) f
;
876 void wxDC::SetPen(const wxPen
& pen
)
878 // Set the old object temporarily, in case the assignment deletes an object
879 // that's not yet selected out.
882 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
891 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
897 if (m_pen
.GetResourceHandle())
899 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
901 m_oldPen
= (WXHPEN
) p
;
906 void wxDC::SetBrush(const wxBrush
& brush
)
908 // Set the old object temporarily, in case the assignment deletes an object
909 // that's not yet selected out.
912 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
921 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
927 if (m_brush
.GetResourceHandle())
930 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
932 m_oldBrush
= (WXHBRUSH
) b
;
937 void wxDC::SetBackground(const wxBrush
& brush
)
939 m_backgroundBrush
= brush
;
941 if (!m_backgroundBrush
.Ok())
946 bool customColours
= TRUE
;
947 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
948 // change background colours from the control-panel specified colours.
949 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
950 customColours
= FALSE
;
954 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
956 m_canvas
->SetTransparent(TRUE
);
960 // New behaviour, 10/2/99: setting the background brush of a DC
961 // doesn't affect the window background colour. However,
962 // I'm leaving in the transparency setting because it's needed by
963 // various controls (e.g. wxStaticText) to determine whether to draw
964 // transparently or not. TODO: maybe this should be a new function
965 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
967 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
968 m_canvas
->SetTransparent(FALSE
);
972 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
974 (void)SetBkColor(GetHdc(), new_color
);
978 void wxDC::SetBackgroundMode(int mode
)
980 m_backgroundMode
= mode
;
982 // SetBackgroundColour now only refers to text background
983 // and m_backgroundMode is used there
986 if (m_backgroundMode == wxTRANSPARENT)
987 ::SetBkMode(GetHdc(), TRANSPARENT);
989 ::SetBkMode(GetHdc(), OPAQUE);
993 void wxDC::SetLogicalFunction(int function
)
995 m_logicalFunction
= function
;
997 SetRop((WXHDC
) m_hDC
);
1000 void wxDC::SetRop(WXHDC dc
)
1002 if (!dc
|| m_logicalFunction
< 0)
1006 // These may be wrong
1007 switch (m_logicalFunction
)
1009 // case wxXOR: c_rop = R2_XORPEN; break;
1010 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
1011 case wxINVERT
: c_rop
= R2_NOT
; break;
1012 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
1013 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
1014 case wxCLEAR
: c_rop
= R2_WHITE
; break;
1015 case wxSET
: c_rop
= R2_BLACK
; break;
1016 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
1017 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
1018 case wxAND
: c_rop
= R2_MASKPEN
; break;
1019 case wxOR
: c_rop
= R2_MERGEPEN
; break;
1020 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
1025 c_rop
= R2_COPYPEN
; break;
1027 SetROP2((HDC
) dc
, c_rop
);
1030 bool wxDC::StartDoc(const wxString
& message
)
1032 // We might be previewing, so return TRUE to let it continue.
1040 void wxDC::StartPage()
1044 void wxDC::EndPage()
1048 // ---------------------------------------------------------------------------
1050 // ---------------------------------------------------------------------------
1052 wxCoord
wxDC::GetCharHeight() const
1054 TEXTMETRIC lpTextMetric
;
1056 GetTextMetrics(GetHdc(), &lpTextMetric
);
1058 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1061 wxCoord
wxDC::GetCharWidth() const
1063 TEXTMETRIC lpTextMetric
;
1065 GetTextMetrics(GetHdc(), &lpTextMetric
);
1067 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1070 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1071 wxCoord
*descent
, wxCoord
*externalLeading
,
1072 wxFont
*theFont
) const
1074 wxFont
*fontToUse
= (wxFont
*) theFont
;
1076 fontToUse
= (wxFont
*) &m_font
;
1081 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1082 GetTextMetrics(GetHdc(), &tm
);
1084 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1085 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1086 if (descent
) *descent
= tm
.tmDescent
;
1087 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1090 void wxDC::SetMapMode(int mode
)
1092 m_mappingMode
= mode
;
1094 int pixel_width
= 0;
1095 int pixel_height
= 0;
1099 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1100 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1101 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1102 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1104 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1109 double mm2pixelsX
= pixel_width
/mm_width
;
1110 double mm2pixelsY
= pixel_height
/mm_height
;
1116 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1117 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1122 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1123 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1128 m_logicalScaleX
= mm2pixelsX
;
1129 m_logicalScaleY
= mm2pixelsY
;
1134 m_logicalScaleX
= (mm2pixelsX
/10.0);
1135 m_logicalScaleY
= (mm2pixelsY
/10.0);
1141 m_logicalScaleX
= 1.0;
1142 m_logicalScaleY
= 1.0;
1147 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1148 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1150 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1151 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1152 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1153 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1154 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1155 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1158 void wxDC::SetUserScale(double x
, double y
)
1163 SetMapMode(m_mappingMode
);
1166 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1168 m_signX
= xLeftRight
? 1 : -1;
1169 m_signY
= yBottomUp
? -1 : 1;
1171 SetMapMode(m_mappingMode
);
1174 void wxDC::SetSystemScale(double x
, double y
)
1179 SetMapMode(m_mappingMode
);
1182 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1184 m_logicalOriginX
= x
;
1185 m_logicalOriginY
= y
;
1187 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1190 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1192 m_deviceOriginX
= x
;
1193 m_deviceOriginY
= y
;
1195 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1198 // ---------------------------------------------------------------------------
1199 // coordinates transformations
1200 // ---------------------------------------------------------------------------
1202 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1204 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1207 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1209 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1212 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1214 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1217 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1219 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1222 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1224 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1227 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1229 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1232 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1234 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1237 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1239 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1242 // ---------------------------------------------------------------------------
1244 // ---------------------------------------------------------------------------
1246 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1247 wxCoord width
, wxCoord height
,
1248 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1249 int rop
, bool useMask
)
1251 wxMask
*mask
= NULL
;
1254 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1255 mask
= bmp
.GetMask();
1257 wxCHECK_MSG( bmp
.Ok() && mask
, FALSE
,
1258 _T("can't blit with mask without mask") );
1261 COLORREF old_textground
= ::GetTextColor(GetHdc());
1262 COLORREF old_background
= ::GetBkColor(GetHdc());
1263 if (m_textForegroundColour
.Ok())
1265 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1267 if (m_textBackgroundColour
.Ok())
1269 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1272 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1273 rop
== wxCLEAR
? WHITENESS
:
1274 rop
== wxSET
? BLACKNESS
:
1275 rop
== wxINVERT
? DSTINVERT
:
1276 rop
== wxAND
? MERGECOPY
:
1277 rop
== wxOR
? MERGEPAINT
:
1278 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1279 rop
== wxXOR
? SRCINVERT
:
1280 rop
== wxOR_REVERSE
? MERGEPAINT
:
1281 rop
== wxAND_REVERSE
? SRCERASE
:
1282 rop
== wxSRC_OR
? SRCPAINT
:
1283 rop
== wxSRC_AND
? SRCAND
:
1291 if ( ::MaskBlt(GetHdc(), xdest
, ydest
,
1292 (int)width
, (int)height
,
1293 GetHdcOf(*source
), xsrc
, ysrc
,
1294 (HBITMAP
) mask
->GetMaskBitmap(),
1295 0, 0, MAKEROP4(SRCCOPY
, PATCOPY
)) != 0 )
1303 // Blit bitmap with mask
1305 // create a temp buffer bitmap and DCs to access it and the mask
1306 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1307 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1308 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1309 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1310 ::SelectObject(dc_buffer
, buffer_bmap
);
1312 // copy dest to buffer
1313 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1314 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1316 wxLogLastError("BitBlt");
1319 // copy src to buffer using selected raster op
1320 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1321 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1323 wxLogLastError("BitBlt");
1326 // set masked area in buffer to BLACK (pixel value 0)
1327 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1328 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1329 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1330 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1332 wxLogLastError("BitBlt");
1335 // set unmasked area in dest to BLACK
1336 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1337 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1338 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1339 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1341 wxLogLastError("BitBlt");
1343 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1344 ::SetTextColor(GetHdc(), prevCol
);
1346 // OR buffer to dest
1347 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1348 (int)width
, (int)height
,
1349 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1352 wxLogLastError("BitBlt");
1355 // tidy up temporary DCs and bitmap
1356 ::SelectObject(dc_mask
, 0);
1357 ::DeleteDC(dc_mask
);
1358 ::SelectObject(dc_buffer
, 0);
1359 ::DeleteDC(dc_buffer
);
1360 ::DeleteObject(buffer_bmap
);
1363 else // no mask, just BitBlt() it
1365 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1366 (int)width
, (int)height
,
1367 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1370 wxLogLastError("BitBlt");
1374 ::SetTextColor(GetHdc(), old_textground
);
1375 ::SetBkColor(GetHdc(), old_background
);
1380 void wxDC::DoGetSize(int *w
, int *h
) const
1382 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1383 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1386 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1388 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1389 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1392 wxSize
wxDC::GetPPI() const
1394 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1395 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1397 return wxSize(x
, y
);
1400 // For use by wxWindows only, unless custom units are required.
1401 void wxDC::SetLogicalScale(double x
, double y
)
1403 m_logicalScaleX
= x
;
1404 m_logicalScaleY
= y
;
1407 #if WXWIN_COMPATIBILITY
1408 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1409 float *descent
, float *externalLeading
,
1410 wxFont
*theFont
, bool use16bit
) const
1412 wxCoord x1
, y1
, descent1
, externalLeading1
;
1413 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1416 *descent
= descent1
;
1417 if (externalLeading
)
1418 *externalLeading
= externalLeading1
;
1422 // ---------------------------------------------------------------------------
1423 // spline drawing code
1424 // ---------------------------------------------------------------------------
1428 class wxSpline
: public wxObject
1434 wxSpline(wxList
*list
);
1435 void DeletePoints();
1437 // Doesn't delete points
1441 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1443 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1444 double a3
, double b3
, double a4
, double b4
);
1445 void wx_clear_stack();
1446 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1447 double *y3
, double *x4
, double *y4
);
1448 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1449 double x4
, double y4
);
1450 static bool wx_spline_add_point(double x
, double y
);
1451 static void wx_spline_draw_point_array(wxDC
*dc
);
1452 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1454 void wxDC::DoDrawSpline(wxList
*list
)
1456 wxSpline
spline(list
);
1458 wx_draw_open_spline(this, &spline
);
1461 wxList wx_spline_point_list
;
1463 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1466 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1467 double x1
, y1
, x2
, y2
;
1469 wxNode
*node
= spline
->points
->First();
1470 p
= (wxPoint
*)node
->Data();
1475 node
= node
->Next();
1476 p
= (wxPoint
*)node
->Data();
1480 cx1
= (double)((x1
+ x2
) / 2);
1481 cy1
= (double)((y1
+ y2
) / 2);
1482 cx2
= (double)((cx1
+ x2
) / 2);
1483 cy2
= (double)((cy1
+ y2
) / 2);
1485 wx_spline_add_point(x1
, y1
);
1487 while ((node
= node
->Next()) != NULL
)
1489 p
= (wxPoint
*)node
->Data();
1494 cx4
= (double)(x1
+ x2
) / 2;
1495 cy4
= (double)(y1
+ y2
) / 2;
1496 cx3
= (double)(x1
+ cx4
) / 2;
1497 cy3
= (double)(y1
+ cy4
) / 2;
1499 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1503 cx2
= (double)(cx1
+ x2
) / 2;
1504 cy2
= (double)(cy1
+ y2
) / 2;
1507 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1508 wx_spline_add_point(x2
, y2
);
1510 wx_spline_draw_point_array(dc
);
1514 /********************* CURVES FOR SPLINES *****************************
1516 The following spline drawing routine is from
1518 "An Algorithm for High-Speed Curve Generation"
1519 by George Merrill Chaikin,
1520 Computer Graphics and Image Processing, 3, Academic Press,
1525 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1526 Computer Graphics and Image Processing, 4, Academic Press,
1529 ***********************************************************************/
1531 #define half(z1, z2) ((z1+z2)/2.0)
1534 /* iterative version */
1536 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1539 register double xmid
, ymid
;
1540 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1543 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1545 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1546 xmid
= (double)half(x2
, x3
);
1547 ymid
= (double)half(y2
, y3
);
1548 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1549 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1550 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1551 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1553 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1554 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1555 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1556 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1562 /* utilities used by spline drawing routines */
1565 typedef struct wx_spline_stack_struct
{
1566 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1570 #define SPLINE_STACK_DEPTH 20
1571 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1572 static Stack
*wx_stack_top
;
1573 static int wx_stack_count
;
1575 void wx_clear_stack()
1577 wx_stack_top
= wx_spline_stack
;
1581 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1583 wx_stack_top
->x1
= x1
;
1584 wx_stack_top
->y1
= y1
;
1585 wx_stack_top
->x2
= x2
;
1586 wx_stack_top
->y2
= y2
;
1587 wx_stack_top
->x3
= x3
;
1588 wx_stack_top
->y3
= y3
;
1589 wx_stack_top
->x4
= x4
;
1590 wx_stack_top
->y4
= y4
;
1595 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1596 double *x3
, double *y3
, double *x4
, double *y4
)
1598 if (wx_stack_count
== 0)
1602 *x1
= wx_stack_top
->x1
;
1603 *y1
= wx_stack_top
->y1
;
1604 *x2
= wx_stack_top
->x2
;
1605 *y2
= wx_stack_top
->y2
;
1606 *x3
= wx_stack_top
->x3
;
1607 *y3
= wx_stack_top
->y3
;
1608 *x4
= wx_stack_top
->x4
;
1609 *y4
= wx_stack_top
->y4
;
1613 static bool wx_spline_add_point(double x
, double y
)
1615 wxPoint
*point
= new wxPoint
;
1618 wx_spline_point_list
.Append((wxObject
*)point
);
1622 static void wx_spline_draw_point_array(wxDC
*dc
)
1624 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1625 wxNode
*node
= wx_spline_point_list
.First();
1628 wxPoint
*point
= (wxPoint
*)node
->Data();
1631 node
= wx_spline_point_list
.First();
1635 wxSpline::wxSpline(wxList
*list
)
1640 wxSpline::~wxSpline()
1644 void wxSpline::DeletePoints()
1646 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1648 wxPoint
*point
= (wxPoint
*)node
->Data();
1656 #endif // wxUSE_SPLINES