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
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
60 // ---------------------------------------------------------------------------
62 // ---------------------------------------------------------------------------
64 static const int VIEWPORT_EXTENT
= 1000;
66 static const int MM_POINTS
= 9;
67 static const int MM_METRIC
= 10;
69 // usually this is defined in math.h
71 static const double M_PI
= 3.14159265358979323846;
74 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
75 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
76 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
78 // ---------------------------------------------------------------------------
80 // ---------------------------------------------------------------------------
82 // convert degrees to radians
83 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
85 // ===========================================================================
87 // ===========================================================================
89 // ---------------------------------------------------------------------------
91 // ---------------------------------------------------------------------------
93 // Default constructor
107 m_windowExtX
= VIEWPORT_EXTENT
;
108 m_windowExtY
= VIEWPORT_EXTENT
;
117 SelectOldObjects(m_hDC
);
119 if ( m_canvas
== NULL
)
120 ::DeleteDC(GetHdc());
122 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
128 // This will select current objects out of the DC,
129 // which is what you have to do before deleting the
131 void wxDC::SelectOldObjects(WXHDC dc
)
137 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
138 if (m_selectedBitmap
.Ok())
140 m_selectedBitmap
.SetSelectedInto(NULL
);
146 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
151 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
156 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
161 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
166 m_brush
= wxNullBrush
;
168 m_palette
= wxNullPalette
;
170 m_backgroundBrush
= wxNullBrush
;
171 m_selectedBitmap
= wxNullBitmap
;
174 // ---------------------------------------------------------------------------
176 // ---------------------------------------------------------------------------
178 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
183 m_clipX2
= (int)(cx
+ cw
);
184 m_clipY2
= (int)(cy
+ ch
);
186 DoClipping((WXHDC
) m_hDC
);
189 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
191 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
193 wxRect box
= region
.GetBox();
198 m_clipX2
= box
.x
+ box
.width
;
199 m_clipY2
= box
.y
+ box
.height
;
202 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
204 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
208 void wxDC::DoClipping(WXHDC dc
)
210 if (m_clipping
&& dc
)
212 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
213 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
217 void wxDC::DestroyClippingRegion()
219 if (m_clipping
&& m_hDC
)
221 // TODO: this should restore the previous clipping region,
222 // so that OnPaint processing works correctly, and the update clipping region
223 // doesn't get destroyed after the first DestroyClippingRegion.
224 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
225 SelectClipRgn(GetHdc(), rgn
);
231 // ---------------------------------------------------------------------------
232 // query capabilities
233 // ---------------------------------------------------------------------------
235 bool wxDC::CanDrawBitmap() const
240 bool wxDC::CanGetTextExtent() const
242 // What sort of display is it?
243 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
245 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
248 int wxDC::GetDepth() const
250 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
253 // ---------------------------------------------------------------------------
255 // ---------------------------------------------------------------------------
262 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
266 // No, I think we should simply ignore this if printing on e.g.
268 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
269 if (!m_selectedBitmap
.Ok())
272 rect
.left
= 0; rect
.top
= 0;
273 rect
.right
= m_selectedBitmap
.GetWidth();
274 rect
.bottom
= m_selectedBitmap
.GetHeight();
277 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
279 DWORD colour
= GetBkColor(GetHdc());
280 HBRUSH brush
= CreateSolidBrush(colour
);
281 FillRect(GetHdc(), &rect
, brush
);
284 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
285 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
286 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
287 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
288 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
291 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
293 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
295 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
298 // quoting from the MSDN docs:
300 // Following are some of the reasons this function might fail:
302 // * The filling could not be completed.
303 // * The specified point has the boundary color specified by the
304 // crColor parameter (if FLOODFILLBORDER was requested).
305 // * The specified point does not have the color specified by
306 // crColor (if FLOODFILLSURFACE was requested)
307 // * The point is outside the clipping region that is, it is not
308 // visible on the device.
310 wxLogLastError("ExtFloodFill");
313 CalcBoundingBox(x
, y
);
316 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
318 // get the color of the pixel
319 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
321 // get the color of the pen
322 COLORREF pencolor
= 0x00ffffff;
325 pencolor
= m_pen
.GetColour().GetPixel();
328 // return the color of the pixel
331 col
->Set(GetRValue(pixelcolor
),
332 GetGValue(pixelcolor
),
333 GetBValue(pixelcolor
));
336 // check, if color of the pixels is the same as the color of the current
337 // pen and return TRUE if it is, FALSE otherwise
338 return pixelcolor
== pencolor
;
341 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
343 wxCoord x1
= x
-VIEWPORT_EXTENT
;
344 wxCoord y1
= y
-VIEWPORT_EXTENT
;
345 wxCoord x2
= x
+VIEWPORT_EXTENT
;
346 wxCoord y2
= y
+VIEWPORT_EXTENT
;
348 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
349 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
351 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
352 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
354 CalcBoundingBox(x1
, y1
);
355 CalcBoundingBox(x2
, y2
);
358 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
360 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
361 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
363 /* MATTHEW: [6] New normalization */
364 #if WX_STANDARD_GRAPHICS
365 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
368 CalcBoundingBox(x1
, y1
);
369 CalcBoundingBox(x2
, y2
);
372 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
376 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
377 if (x1
==x2
&& x2
==y2
)
379 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
383 wxCoord xx1
= XLOG2DEV(x1
);
384 wxCoord yy1
= YLOG2DEV(y1
);
385 wxCoord xx2
= XLOG2DEV(x2
);
386 wxCoord yy2
= YLOG2DEV(y2
);
387 wxCoord xxc
= XLOG2DEV(xc
);
388 wxCoord yyc
= YLOG2DEV(yc
);
389 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
391 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
392 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
393 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
394 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
395 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
396 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
398 // Have to add 1 to bottom-right corner of rectangle
399 // to make semi-circles look right (crooked line otherwise).
400 // Unfortunately this is not a reliable method, depends
401 // on the size of shape.
402 // TODO: figure out why this happens!
403 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
407 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
410 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
411 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
414 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
416 COLORREF color
= 0x00ffffff;
419 color
= m_pen
.GetColour().GetPixel();
422 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
424 CalcBoundingBox(x
, y
);
427 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
429 COLORREF old_textground
= ::GetTextColor(GetHdc());
430 COLORREF old_background
= ::GetBkColor(GetHdc());
431 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
434 if (m_textForegroundColour
.Ok())
435 { //just the oposite from what is expected see help on pattern brush
436 // 1 in mask becomes bk color
437 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
439 if (m_textBackgroundColour
.Ok())
440 { //just the oposite from what is expected
441 // 0 in mask becomes text color
442 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
445 if (m_backgroundMode
== wxTRANSPARENT
)
446 SetBkMode(GetHdc(), TRANSPARENT
);
448 SetBkMode(GetHdc(), OPAQUE
);
451 // Do things less efficiently if we have offsets
452 if (xoffset
!= 0 || yoffset
!= 0)
454 POINT
*cpoints
= new POINT
[n
];
456 for (i
= 0; i
< n
; i
++)
458 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
459 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
461 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
463 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
464 (void)Polygon(GetHdc(), cpoints
, n
);
465 SetPolyFillMode(GetHdc(),prev
);
471 for (i
= 0; i
< n
; i
++)
472 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
474 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
475 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
476 SetPolyFillMode(GetHdc(),prev
);
479 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
481 ::SetBkMode(GetHdc(), TRANSPARENT
);
482 ::SetTextColor(GetHdc(), old_textground
);
483 ::SetBkColor(GetHdc(), old_background
);
487 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
489 // Do things less efficiently if we have offsets
490 if (xoffset
!= 0 || yoffset
!= 0)
492 POINT
*cpoints
= new POINT
[n
];
494 for (i
= 0; i
< n
; i
++)
496 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
497 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
499 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
501 (void)Polyline(GetHdc(), cpoints
, n
);
507 for (i
= 0; i
< n
; i
++)
508 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
510 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
514 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
516 COLORREF colFgOld
= 0,
519 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
521 colFgOld
= ::GetTextColor(GetHdc());
522 colBgOld
= ::GetBkColor(GetHdc());
524 if ( m_textForegroundColour
.Ok() )
526 // just the oposite from what is expected see help on pattern brush
527 // 1 in mask becomes bk color
528 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
531 if ( m_textBackgroundColour
.Ok() )
533 // 0 in mask becomes text color
534 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
537 // VZ: IMHO this does strictly nothing here
538 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
542 wxCoord x2
= x
+ width
;
543 wxCoord y2
= y
+ height
;
545 // Windows draws the filled rectangles without outline (i.e. drawn with a
546 // transparent pen) one pixel smaller in both directions and we want them
547 // to have the same size regardless of which pen is used - adjust
548 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
554 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
556 CalcBoundingBox(x
, y
);
557 CalcBoundingBox(x2
, y2
);
559 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
561 // restore the colours we changed
562 ::SetBkMode(GetHdc(), TRANSPARENT
);
563 ::SetTextColor(GetHdc(), colFgOld
);
564 ::SetBkColor(GetHdc(), colBgOld
);
568 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
570 // Now, a negative radius value is interpreted to mean
571 // 'the proportion of the smallest X or Y dimension'
575 double smallest
= 0.0;
580 radius
= (- radius
* smallest
);
583 wxCoord x2
= (x
+width
);
584 wxCoord y2
= (y
+height
);
586 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
587 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
589 CalcBoundingBox(x
, y
);
590 CalcBoundingBox(x2
, y2
);
593 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
595 wxCoord x2
= (x
+width
);
596 wxCoord y2
= (y
+height
);
598 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
600 CalcBoundingBox(x
, y
);
601 CalcBoundingBox(x2
, y2
);
604 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
605 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
610 int rx1
= XLOG2DEV(x
+w
/2);
611 int ry1
= YLOG2DEV(y
+h
/2);
618 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
619 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
620 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
621 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
623 // draw pie with NULL_PEN first and then outline otherwise a line is
624 // drawn from the start and end points to the centre
625 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
628 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
633 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
634 rx1
, ry1
-1, rx2
, ry2
-1);
636 ::SelectObject(GetHdc(), orig_pen
);
637 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
640 CalcBoundingBox(x
, y
);
641 CalcBoundingBox(x2
, y2
);
644 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
646 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
648 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
650 CalcBoundingBox(x
, y
);
651 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
654 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
656 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
658 int width
= bmp
.GetWidth(),
659 height
= bmp
.GetHeight();
661 HBITMAP hbmpMask
= 0;
665 wxMask
*mask
= bmp
.GetMask();
667 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
671 // don't give assert here because this would break existing
672 // programs - just silently ignore useMask parameter
680 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
681 ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
683 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
685 bool ok
= ::MaskBlt(GetHdc(), x
, y
, width
, height
,
688 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
694 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
697 memDC
.SelectObject(bmp
);
699 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
701 memDC
.SelectObject(wxNullBitmap
);
704 else // no mask, just use BitBlt()
707 HDC memdc
= ::CreateCompatibleDC( cdc
);
708 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
710 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
712 COLORREF old_textground
= ::GetTextColor(GetHdc());
713 COLORREF old_background
= ::GetBkColor(GetHdc());
714 if (m_textForegroundColour
.Ok())
716 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
718 if (m_textBackgroundColour
.Ok())
720 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
723 ::SelectObject( memdc
, hbitmap
);
724 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
727 ::SetTextColor(GetHdc(), old_textground
);
728 ::SetBkColor(GetHdc(), old_background
);
732 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
734 DrawAnyText(text
, x
, y
);
736 // update the bounding box
737 CalcBoundingBox(x
, y
);
740 GetTextExtent(text
, &w
, &h
);
741 CalcBoundingBox(x
+ w
, y
+ h
);
744 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
746 // prepare for drawing the text
747 if ( m_textForegroundColour
.Ok() )
748 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
750 DWORD old_background
= 0;
751 if ( m_textBackgroundColour
.Ok() )
753 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
756 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
759 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
760 text
.c_str(), text
.length()) == 0 )
762 wxLogLastError("TextOut");
765 // restore the old parameters (text foreground colour may be left because
766 // it never is set to anything else, but background should remain
767 // transparent even if we just drew an opaque string)
768 if ( m_textBackgroundColour
.Ok() )
769 (void)SetBkColor(GetHdc(), old_background
);
771 SetBkMode(GetHdc(), TRANSPARENT
);
774 void wxDC::DoDrawRotatedText(const wxString
& text
,
775 wxCoord x
, wxCoord y
,
778 // we test that we have some font because otherwise we should still use the
779 // "else" part below to avoid that DrawRotatedText(angle = 180) and
780 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
781 // font for drawing rotated fonts unfortunately)
782 if ( (angle
== 0.0) && m_font
.Ok() )
784 DoDrawText(text
, x
, y
);
788 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
789 // can't have non zero orientation/escapement
790 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
791 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
793 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
795 wxLogLastError("GetObject(hfont)");
798 // GDI wants the angle in tenth of degree
799 long angle10
= (long)(angle
* 10);
800 lf
.lfEscapement
= angle10
;
801 lf
. lfOrientation
= angle10
;
803 hfont
= ::CreateFontIndirect(&lf
);
806 wxLogLastError("CreateFont");
810 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
812 DrawAnyText(text
, x
, y
);
814 (void)::SelectObject(GetHdc(), hfontOld
);
815 (void)::DeleteObject(hfont
);
818 // call the bounding box by adding all four vertices of the rectangle
819 // containing the text to it (simpler and probably not slower than
820 // determining which of them is really topmost/leftmost/...)
822 GetTextExtent(text
, &w
, &h
);
824 double rad
= DegToRad(angle
);
826 // "upper left" and "upper right"
827 CalcBoundingBox(x
, y
);
828 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
830 // "bottom left" and "bottom right"
831 x
+= (wxCoord
)(h
*sin(rad
));
832 y
+= (wxCoord
)(h
*cos(rad
));
833 CalcBoundingBox(x
, y
);
834 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
838 // ---------------------------------------------------------------------------
840 // ---------------------------------------------------------------------------
842 void wxDC::SetPalette(const wxPalette
& palette
)
844 // Set the old object temporarily, in case the assignment deletes an object
845 // that's not yet selected out.
848 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
856 // Setting a NULL colourmap is a way of restoring
857 // the original colourmap
860 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
867 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
869 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
871 m_oldPalette
= (WXHPALETTE
) oldPal
;
873 ::RealizePalette(GetHdc());
877 void wxDC::SetFont(const wxFont
& the_font
)
879 // Set the old object temporarily, in case the assignment deletes an object
880 // that's not yet selected out.
883 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
892 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
896 if (m_font
.Ok() && m_font
.GetResourceHandle())
898 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
899 if (f
== (HFONT
) NULL
)
901 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
904 m_oldFont
= (WXHFONT
) f
;
908 void wxDC::SetPen(const wxPen
& pen
)
910 // Set the old object temporarily, in case the assignment deletes an object
911 // that's not yet selected out.
914 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
923 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
929 if (m_pen
.GetResourceHandle())
931 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
933 m_oldPen
= (WXHPEN
) p
;
938 void wxDC::SetBrush(const wxBrush
& brush
)
940 // Set the old object temporarily, in case the assignment deletes an object
941 // that's not yet selected out.
944 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
953 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
959 if (m_brush
.GetResourceHandle())
962 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
964 m_oldBrush
= (WXHBRUSH
) b
;
969 void wxDC::SetBackground(const wxBrush
& brush
)
971 m_backgroundBrush
= brush
;
973 if (!m_backgroundBrush
.Ok())
978 bool customColours
= TRUE
;
979 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
980 // change background colours from the control-panel specified colours.
981 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
982 customColours
= FALSE
;
986 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
988 m_canvas
->SetTransparent(TRUE
);
992 // New behaviour, 10/2/99: setting the background brush of a DC
993 // doesn't affect the window background colour. However,
994 // I'm leaving in the transparency setting because it's needed by
995 // various controls (e.g. wxStaticText) to determine whether to draw
996 // transparently or not. TODO: maybe this should be a new function
997 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
999 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1000 m_canvas
->SetTransparent(FALSE
);
1004 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1006 (void)SetBkColor(GetHdc(), new_color
);
1010 void wxDC::SetBackgroundMode(int mode
)
1012 m_backgroundMode
= mode
;
1014 // SetBackgroundColour now only refers to text background
1015 // and m_backgroundMode is used there
1018 if (m_backgroundMode == wxTRANSPARENT)
1019 ::SetBkMode(GetHdc(), TRANSPARENT);
1021 ::SetBkMode(GetHdc(), OPAQUE);
1025 void wxDC::SetLogicalFunction(int function
)
1027 m_logicalFunction
= function
;
1032 void wxDC::SetRop(WXHDC dc
)
1034 if ( !dc
|| m_logicalFunction
< 0 )
1039 switch (m_logicalFunction
)
1041 case wxCLEAR
: rop
= R2_BLACK
; break;
1042 case wxXOR
: rop
= R2_XORPEN
; break;
1043 case wxINVERT
: rop
= R2_NOT
; break;
1044 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1045 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1046 case wxCOPY
: rop
= R2_COPYPEN
; break;
1047 case wxAND
: rop
= R2_MASKPEN
; break;
1048 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1049 case wxNO_OP
: rop
= R2_NOP
; break;
1050 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1051 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1052 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1053 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1054 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1055 case wxOR
: rop
= R2_MERGEPEN
; break;
1056 case wxSET
: rop
= R2_WHITE
; break;
1059 wxFAIL_MSG( wxT("unsupported logical function") );
1063 SetROP2(GetHdc(), rop
);
1066 bool wxDC::StartDoc(const wxString
& message
)
1068 // We might be previewing, so return TRUE to let it continue.
1076 void wxDC::StartPage()
1080 void wxDC::EndPage()
1084 // ---------------------------------------------------------------------------
1086 // ---------------------------------------------------------------------------
1088 wxCoord
wxDC::GetCharHeight() const
1090 TEXTMETRIC lpTextMetric
;
1092 GetTextMetrics(GetHdc(), &lpTextMetric
);
1094 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1097 wxCoord
wxDC::GetCharWidth() const
1099 TEXTMETRIC lpTextMetric
;
1101 GetTextMetrics(GetHdc(), &lpTextMetric
);
1103 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1106 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1107 wxCoord
*descent
, wxCoord
*externalLeading
,
1108 wxFont
*theFont
) const
1110 wxFont
*fontToUse
= (wxFont
*) theFont
;
1112 fontToUse
= (wxFont
*) &m_font
;
1117 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1118 GetTextMetrics(GetHdc(), &tm
);
1120 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1121 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1122 if (descent
) *descent
= tm
.tmDescent
;
1123 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1126 void wxDC::SetMapMode(int mode
)
1128 m_mappingMode
= mode
;
1130 int pixel_width
= 0;
1131 int pixel_height
= 0;
1135 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1136 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1137 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1138 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1140 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1145 double mm2pixelsX
= pixel_width
/mm_width
;
1146 double mm2pixelsY
= pixel_height
/mm_height
;
1152 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1153 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1158 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1159 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1164 m_logicalScaleX
= mm2pixelsX
;
1165 m_logicalScaleY
= mm2pixelsY
;
1170 m_logicalScaleX
= (mm2pixelsX
/10.0);
1171 m_logicalScaleY
= (mm2pixelsY
/10.0);
1177 m_logicalScaleX
= 1.0;
1178 m_logicalScaleY
= 1.0;
1183 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1184 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1186 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1187 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1188 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1189 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1190 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1191 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1194 void wxDC::SetUserScale(double x
, double y
)
1199 SetMapMode(m_mappingMode
);
1202 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1204 m_signX
= xLeftRight
? 1 : -1;
1205 m_signY
= yBottomUp
? -1 : 1;
1207 SetMapMode(m_mappingMode
);
1210 void wxDC::SetSystemScale(double x
, double y
)
1215 SetMapMode(m_mappingMode
);
1218 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1220 m_logicalOriginX
= x
;
1221 m_logicalOriginY
= y
;
1223 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1226 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1228 m_deviceOriginX
= x
;
1229 m_deviceOriginY
= y
;
1231 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1234 // ---------------------------------------------------------------------------
1235 // coordinates transformations
1236 // ---------------------------------------------------------------------------
1238 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1240 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1243 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1245 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1248 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1250 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1253 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1255 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1258 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1260 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1263 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1265 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1268 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1270 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1273 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1275 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1278 // ---------------------------------------------------------------------------
1280 // ---------------------------------------------------------------------------
1282 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1283 wxCoord width
, wxCoord height
,
1284 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1285 int rop
, bool useMask
)
1287 wxMask
*mask
= NULL
;
1290 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1291 mask
= bmp
.GetMask();
1293 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1295 // don't give assert here because this would break existing
1296 // programs - just silently ignore useMask parameter
1301 COLORREF old_textground
= ::GetTextColor(GetHdc());
1302 COLORREF old_background
= ::GetBkColor(GetHdc());
1303 if (m_textForegroundColour
.Ok())
1305 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1307 if (m_textBackgroundColour
.Ok())
1309 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1312 DWORD dwRop
= SRCCOPY
;
1315 case wxXOR
: dwRop
= SRCINVERT
; break;
1316 case wxINVERT
: dwRop
= DSTINVERT
; break;
1317 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1318 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1319 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1320 case wxSET
: dwRop
= WHITENESS
; break;
1321 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1322 case wxAND
: dwRop
= SRCAND
; break;
1323 case wxOR
: dwRop
= SRCPAINT
; break;
1324 case wxEQUIV
: dwRop
= 0x00990066; break;
1325 case wxNAND
: dwRop
= 0x007700E6; break;
1326 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1327 case wxCOPY
: dwRop
= SRCCOPY
; break;
1328 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1329 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1330 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1332 wxFAIL_MSG( wxT("unsupported logical function") );
1341 // we want the part of the image corresponding to the mask to be
1342 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1343 // meaning of fg and bg is inverted which corresponds to wxWin notion
1344 // of the mask which is also contrary to the Windows one)
1345 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1346 GetHdcOf(*source
), xsrc
, ysrc
,
1347 (HBITMAP
)mask
->GetMaskBitmap(), 0, 0,
1348 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1353 // Blit bitmap with mask
1355 // create a temp buffer bitmap and DCs to access it and the mask
1356 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1357 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1358 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1359 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1360 ::SelectObject(dc_buffer
, buffer_bmap
);
1362 // copy dest to buffer
1363 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1364 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1366 wxLogLastError("BitBlt");
1369 // copy src to buffer using selected raster op
1370 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1371 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1373 wxLogLastError("BitBlt");
1376 // set masked area in buffer to BLACK (pixel value 0)
1377 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1378 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1379 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1380 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1382 wxLogLastError("BitBlt");
1385 // set unmasked area in dest to BLACK
1386 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1387 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1388 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1389 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1391 wxLogLastError("BitBlt");
1393 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1394 ::SetTextColor(GetHdc(), prevCol
);
1396 // OR buffer to dest
1397 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1398 (int)width
, (int)height
,
1399 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1402 wxLogLastError("BitBlt");
1405 // tidy up temporary DCs and bitmap
1406 ::SelectObject(dc_mask
, 0);
1407 ::DeleteDC(dc_mask
);
1408 ::SelectObject(dc_buffer
, 0);
1409 ::DeleteDC(dc_buffer
);
1410 ::DeleteObject(buffer_bmap
);
1413 else // no mask, just BitBlt() it
1415 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1416 (int)width
, (int)height
,
1417 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1420 wxLogLastError("BitBlt");
1423 ::SetTextColor(GetHdc(), old_textground
);
1424 ::SetBkColor(GetHdc(), old_background
);
1429 void wxDC::DoGetSize(int *w
, int *h
) const
1431 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1432 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1435 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1437 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1438 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1441 wxSize
wxDC::GetPPI() const
1443 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1444 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1446 return wxSize(x
, y
);
1449 // For use by wxWindows only, unless custom units are required.
1450 void wxDC::SetLogicalScale(double x
, double y
)
1452 m_logicalScaleX
= x
;
1453 m_logicalScaleY
= y
;
1456 #if WXWIN_COMPATIBILITY
1457 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1458 float *descent
, float *externalLeading
,
1459 wxFont
*theFont
, bool use16bit
) const
1461 wxCoord x1
, y1
, descent1
, externalLeading1
;
1462 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1465 *descent
= descent1
;
1466 if (externalLeading
)
1467 *externalLeading
= externalLeading1
;
1471 // ---------------------------------------------------------------------------
1472 // spline drawing code
1473 // ---------------------------------------------------------------------------
1477 class wxSpline
: public wxObject
1483 wxSpline(wxList
*list
);
1484 void DeletePoints();
1486 // Doesn't delete points
1490 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1492 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1493 double a3
, double b3
, double a4
, double b4
);
1494 void wx_clear_stack();
1495 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1496 double *y3
, double *x4
, double *y4
);
1497 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1498 double x4
, double y4
);
1499 static bool wx_spline_add_point(double x
, double y
);
1500 static void wx_spline_draw_point_array(wxDC
*dc
);
1501 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1503 void wxDC::DoDrawSpline(wxList
*list
)
1505 wxSpline
spline(list
);
1507 wx_draw_open_spline(this, &spline
);
1510 wxList wx_spline_point_list
;
1512 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1515 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1516 double x1
, y1
, x2
, y2
;
1518 wxNode
*node
= spline
->points
->First();
1519 p
= (wxPoint
*)node
->Data();
1524 node
= node
->Next();
1525 p
= (wxPoint
*)node
->Data();
1529 cx1
= (double)((x1
+ x2
) / 2);
1530 cy1
= (double)((y1
+ y2
) / 2);
1531 cx2
= (double)((cx1
+ x2
) / 2);
1532 cy2
= (double)((cy1
+ y2
) / 2);
1534 wx_spline_add_point(x1
, y1
);
1536 while ((node
= node
->Next()) != NULL
)
1538 p
= (wxPoint
*)node
->Data();
1543 cx4
= (double)(x1
+ x2
) / 2;
1544 cy4
= (double)(y1
+ y2
) / 2;
1545 cx3
= (double)(x1
+ cx4
) / 2;
1546 cy3
= (double)(y1
+ cy4
) / 2;
1548 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1552 cx2
= (double)(cx1
+ x2
) / 2;
1553 cy2
= (double)(cy1
+ y2
) / 2;
1556 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1557 wx_spline_add_point(x2
, y2
);
1559 wx_spline_draw_point_array(dc
);
1563 /********************* CURVES FOR SPLINES *****************************
1565 The following spline drawing routine is from
1567 "An Algorithm for High-Speed Curve Generation"
1568 by George Merrill Chaikin,
1569 Computer Graphics and Image Processing, 3, Academic Press,
1574 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1575 Computer Graphics and Image Processing, 4, Academic Press,
1578 ***********************************************************************/
1580 #define half(z1, z2) ((z1+z2)/2.0)
1583 /* iterative version */
1585 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1588 register double xmid
, ymid
;
1589 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1592 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1594 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1595 xmid
= (double)half(x2
, x3
);
1596 ymid
= (double)half(y2
, y3
);
1597 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1598 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1599 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1600 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1602 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1603 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1604 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1605 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1611 /* utilities used by spline drawing routines */
1614 typedef struct wx_spline_stack_struct
{
1615 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1619 #define SPLINE_STACK_DEPTH 20
1620 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1621 static Stack
*wx_stack_top
;
1622 static int wx_stack_count
;
1624 void wx_clear_stack()
1626 wx_stack_top
= wx_spline_stack
;
1630 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1632 wx_stack_top
->x1
= x1
;
1633 wx_stack_top
->y1
= y1
;
1634 wx_stack_top
->x2
= x2
;
1635 wx_stack_top
->y2
= y2
;
1636 wx_stack_top
->x3
= x3
;
1637 wx_stack_top
->y3
= y3
;
1638 wx_stack_top
->x4
= x4
;
1639 wx_stack_top
->y4
= y4
;
1644 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1645 double *x3
, double *y3
, double *x4
, double *y4
)
1647 if (wx_stack_count
== 0)
1651 *x1
= wx_stack_top
->x1
;
1652 *y1
= wx_stack_top
->y1
;
1653 *x2
= wx_stack_top
->x2
;
1654 *y2
= wx_stack_top
->y2
;
1655 *x3
= wx_stack_top
->x3
;
1656 *y3
= wx_stack_top
->y3
;
1657 *x4
= wx_stack_top
->x4
;
1658 *y4
= wx_stack_top
->y4
;
1662 static bool wx_spline_add_point(double x
, double y
)
1664 wxPoint
*point
= new wxPoint
;
1667 wx_spline_point_list
.Append((wxObject
*)point
);
1671 static void wx_spline_draw_point_array(wxDC
*dc
)
1673 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1674 wxNode
*node
= wx_spline_point_list
.First();
1677 wxPoint
*point
= (wxPoint
*)node
->Data();
1680 node
= wx_spline_point_list
.First();
1684 wxSpline::wxSpline(wxList
*list
)
1689 wxSpline::~wxSpline()
1693 void wxSpline::DeletePoints()
1695 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1697 wxPoint
*point
= (wxPoint
*)node
->Data();
1705 #endif // wxUSE_SPLINES