1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.h"
30 #include "wx/dcscreen.h"
31 #include "wx/dcprint.h"
32 #include "wx/prntbase.h"
36 #include "wx/module.h"
40 #include "wx/msw/dcclient.h"
41 #include "wx/msw/dcmemory.h"
42 #include "wx/msw/dcscreen.h"
46 #include "wx/gtk/dcclient.h"
47 #include "wx/gtk/dcmemory.h"
48 #include "wx/gtk/dcscreen.h"
49 #elif defined(__WXGTK__)
50 #include "wx/gtk1/dcclient.h"
51 #include "wx/gtk1/dcmemory.h"
52 #include "wx/gtk1/dcscreen.h"
56 #include "wx/osx/dcclient.h"
57 #include "wx/osx/dcmemory.h"
58 #include "wx/osx/dcscreen.h"
62 #include "wx/os2/dcclient.h"
63 #include "wx/os2/dcmemory.h"
64 #include "wx/os2/dcscreen.h"
68 #include "wx/cocoa/dcclient.h"
69 #include "wx/cocoa/dcmemory.h"
70 #include "wx/cocoa/dcscreen.h"
74 #include "wx/motif/dcclient.h"
75 #include "wx/motif/dcmemory.h"
76 #include "wx/motif/dcscreen.h"
80 #include "wx/x11/dcclient.h"
81 #include "wx/x11/dcmemory.h"
82 #include "wx/x11/dcscreen.h"
86 #include "wx/dfb/dcclient.h"
87 #include "wx/dfb/dcmemory.h"
88 #include "wx/dfb/dcscreen.h"
92 #include "wx/palmos/dcclient.h"
93 #include "wx/palmos/dcmemory.h"
94 #include "wx/palmos/dcscreen.h"
97 //----------------------------------------------------------------------------
99 //----------------------------------------------------------------------------
101 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
103 void wxDCFactory::Set(wxDCFactory
*factory
)
110 wxDCFactory
*wxDCFactory::Get()
113 m_factory
= new wxNativeDCFactory
;
118 class wxDCFactoryCleanupModule
: public wxModule
121 virtual bool OnInit() { return true; }
122 virtual void OnExit() { wxDCFactory::Set(NULL
); }
125 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
128 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
134 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
136 wxDCImpl
* const impl
= new wxWindowDCImpl( owner
, window
);
137 impl
->InheritAttributes(window
);
141 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
143 wxDCImpl
* const impl
= new wxClientDCImpl( owner
, window
);
144 impl
->InheritAttributes(window
);
148 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
150 wxDCImpl
* const impl
= new wxPaintDCImpl( owner
, window
);
151 impl
->InheritAttributes(window
);
155 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
157 return new wxMemoryDCImpl( owner
);
160 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC
*owner
, wxBitmap
& bitmap
)
162 // the bitmap may be modified when it's selected into a memory DC so make
163 // sure changing this bitmap doesn't affect any other shallow copies of it
164 // (see wxMemoryDC::SelectObject())
166 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
167 // method because this should be rarely needed and easy to work around by
168 // using the default ctor and calling SelectObjectAsSource itself
172 return new wxMemoryDCImpl(owner
, bitmap
);
175 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
177 return new wxMemoryDCImpl( owner
, dc
);
180 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
182 return new wxScreenDCImpl( owner
);
185 #if wxUSE_PRINTING_ARCHITECTURE
186 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
188 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
189 return factory
->CreatePrinterDCImpl( owner
, data
);
193 //-----------------------------------------------------------------------------
195 //-----------------------------------------------------------------------------
197 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
199 wxWindowDC::wxWindowDC(wxWindow
*win
)
200 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
204 //-----------------------------------------------------------------------------
206 //-----------------------------------------------------------------------------
208 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
210 wxClientDC::wxClientDC(wxWindow
*win
)
211 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
215 //-----------------------------------------------------------------------------
217 //-----------------------------------------------------------------------------
219 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
221 wxMemoryDC::wxMemoryDC()
222 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
226 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
227 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
231 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
232 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
236 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
238 // make sure that the given wxBitmap is not sharing its data with other
239 // wxBitmap instances as its contents will be modified by any drawing
240 // operation done on this DC
244 GetImpl()->DoSelect(bmp
);
247 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
249 GetImpl()->DoSelect(bmp
);
252 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
254 return GetImpl()->GetSelectedBitmap();
257 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
259 return GetImpl()->GetSelectedBitmap();
263 //-----------------------------------------------------------------------------
265 //-----------------------------------------------------------------------------
267 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
269 wxPaintDC::wxPaintDC(wxWindow
*win
)
270 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
274 //-----------------------------------------------------------------------------
276 //-----------------------------------------------------------------------------
278 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
280 wxScreenDC::wxScreenDC()
281 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
285 //-----------------------------------------------------------------------------
287 //-----------------------------------------------------------------------------
289 #if wxUSE_PRINTING_ARCHITECTURE
291 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
293 wxPrinterDC::wxPrinterDC()
294 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
298 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
299 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
303 wxRect
wxPrinterDC::GetPaperRect()
305 return GetImpl()->GetPaperRect();
308 int wxPrinterDC::GetResolution()
310 return GetImpl()->GetResolution();
313 #endif // wxUSE_PRINTING_ARCHITECTURE
315 //-----------------------------------------------------------------------------
317 //-----------------------------------------------------------------------------
319 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
321 wxDCImpl::wxDCImpl( wxDC
*owner
)
323 , m_colour(wxColourDisplay())
327 , m_isBBoxValid(false)
328 , m_logicalOriginX(0), m_logicalOriginY(0)
329 , m_deviceOriginX(0), m_deviceOriginY(0)
330 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
331 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
332 , m_userScaleX(1.0), m_userScaleY(1.0)
333 , m_scaleX(1.0), m_scaleY(1.0)
334 , m_signX(1), m_signY(1)
335 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
336 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
337 , m_logicalFunction(wxCOPY
)
338 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
339 , m_mappingMode(wxMM_TEXT
)
342 , m_backgroundBrush()
343 , m_textForegroundColour(*wxBLACK
)
344 , m_textBackgroundColour(*wxWHITE
)
348 , m_hasCustomPalette(false)
349 #endif // wxUSE_PALETTE
353 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
354 (double)wxGetDisplaySizeMM().GetWidth();
355 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
356 (double)wxGetDisplaySizeMM().GetHeight();
362 wxDCImpl::~wxDCImpl()
366 // ----------------------------------------------------------------------------
367 // coordinate conversions and transforms
368 // ----------------------------------------------------------------------------
370 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
372 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
375 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
377 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
380 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
382 return wxRound((double)(x
) / m_scaleX
);
385 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
387 return wxRound((double)(y
) / m_scaleY
);
390 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
392 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
395 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
397 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
400 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
402 return wxRound((double)(x
) * m_scaleX
);
405 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
407 return wxRound((double)(y
) * m_scaleY
);
410 void wxDCImpl::ComputeScaleAndOrigin()
412 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
413 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
416 void wxDCImpl::SetMapMode( int mode
)
421 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
424 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
427 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
430 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
434 SetLogicalScale( 1.0, 1.0 );
437 m_mappingMode
= mode
;
440 void wxDCImpl::SetUserScale( double x
, double y
)
442 // allow negative ? -> no
445 ComputeScaleAndOrigin();
448 void wxDCImpl::SetLogicalScale( double x
, double y
)
453 ComputeScaleAndOrigin();
456 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
458 m_logicalOriginX
= x
* m_signX
;
459 m_logicalOriginY
= y
* m_signY
;
460 ComputeScaleAndOrigin();
463 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
467 ComputeScaleAndOrigin();
470 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
472 m_deviceLocalOriginX
= x
;
473 m_deviceLocalOriginY
= y
;
474 ComputeScaleAndOrigin();
477 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
479 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
480 // wxWidgets 2.9: no longer override it
481 m_signX
= (xLeftRight
? 1 : -1);
482 m_signY
= (yBottomUp
? -1 : 1);
483 ComputeScaleAndOrigin();
487 // Each element of the widths array will be the width of the string up to and
488 // including the corresponding character in text. This is the generic
489 // implementation, the port-specific classes should do this with native APIs
490 // if available and if faster. Note: pango_layout_index_to_pos is much slower
491 // than calling GetTextExtent!!
498 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
499 ~FontWidthCache() { delete []m_widths
; }
504 m_widths
= new int[FWC_SIZE
];
506 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
514 static FontWidthCache s_fontWidthCache
;
516 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
520 const size_t len
= text
.length();
524 // reset the cache if font or horizontal scale have changed
525 if ( !s_fontWidthCache
.m_widths
||
526 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
527 (s_fontWidthCache
.m_font
!= GetFont()) )
529 s_fontWidthCache
.Reset();
530 s_fontWidthCache
.m_font
= GetFont();
531 s_fontWidthCache
.m_scaleX
= m_scaleX
;
534 // Calculate the position of each character based on the widths of
535 // the previous characters
537 for ( size_t i
= 0; i
< len
; i
++ )
539 const wxChar c
= text
[i
];
540 unsigned int c_int
= (unsigned int)c
;
542 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
544 w
= s_fontWidthCache
.m_widths
[c_int
];
548 DoGetTextExtent(c
, &w
, &h
);
549 if (c_int
< FWC_SIZE
)
550 s_fontWidthCache
.m_widths
[c_int
] = w
;
554 widths
[i
] = totalWidth
;
560 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
564 const wxFont
*font
) const
566 wxCoord widthTextMax
= 0, widthLine
,
567 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
570 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
572 if ( pc
== text
.end() || *pc
== _T('\n') )
574 if ( curLine
.empty() )
576 // we can't use GetTextExtent - it will return 0 for both width
577 // and height and an empty line should count in height
580 // assume that this line has the same height as the previous
582 if ( !heightLineDefault
)
583 heightLineDefault
= heightLine
;
585 if ( !heightLineDefault
)
587 // but we don't know it yet - choose something reasonable
588 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
592 heightTextTotal
+= heightLineDefault
;
596 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
598 if ( widthLine
> widthTextMax
)
599 widthTextMax
= widthLine
;
600 heightTextTotal
+= heightLine
;
603 if ( pc
== text
.end() )
621 *y
= heightTextTotal
;
626 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
627 wxCoord width
, wxCoord height
)
629 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
631 wxCoord x2
= x1
+ width
,
634 // the pen width is calibrated to give 3 for width == height == 10
635 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
637 // we're drawing a scaled version of wx/generic/tick.xpm here
638 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
639 y3
= y1
+ height
/ 2; // y of the left tick branch
640 DoDrawLine(x1
, y3
, x3
, y2
);
641 DoDrawLine(x3
, y2
, x2
, y1
);
643 CalcBoundingBox(x1
, y1
);
644 CalcBoundingBox(x2
, y2
);
648 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
649 wxCoord dstWidth
, wxCoord dstHeight
,
651 wxCoord xsrc
, wxCoord ysrc
,
652 wxCoord srcWidth
, wxCoord srcHeight
,
658 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
659 _T("invalid blit size") );
661 // emulate the stretching by modifying the DC scale
662 double xscale
= (double)srcWidth
/dstWidth
,
663 yscale
= (double)srcHeight
/dstHeight
;
665 double xscaleOld
, yscaleOld
;
666 GetUserScale(&xscaleOld
, &yscaleOld
);
667 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
669 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
670 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
672 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
674 SetUserScale(xscaleOld
, yscaleOld
);
679 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
681 int n
= list
->GetCount();
682 wxPoint
*points
= new wxPoint
[n
];
685 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
687 wxPoint
*point
= node
->GetData();
688 points
[i
].x
= point
->x
;
689 points
[i
].y
= point
->y
;
692 DoDrawLines(n
, points
, xoffset
, yoffset
);
697 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
698 wxCoord xoffset
, wxCoord yoffset
,
701 int n
= list
->GetCount();
702 wxPoint
*points
= new wxPoint
[n
];
705 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
707 wxPoint
*point
= node
->GetData();
708 points
[i
].x
= point
->x
;
709 points
[i
].y
= point
->y
;
712 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
718 wxDCImpl::DoDrawPolyPolygon(int n
,
721 wxCoord xoffset
, wxCoord yoffset
,
726 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
734 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
739 pts
= new wxPoint
[j
+n
-1];
740 for (i
= 0; i
< j
; i
++)
742 for (i
= 2; i
<= n
; i
++)
744 lastOfs
-= count
[n
-i
];
745 pts
[j
++] = pts
[lastOfs
];
749 SetPen(wxPen(*wxBLACK
, 0, wxPENSTYLE_TRANSPARENT
));
750 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
752 for (i
= j
= 0; i
< n
; i
++)
754 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
762 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
763 wxCoord x2
, wxCoord y2
,
764 wxCoord x3
, wxCoord y3
)
766 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
767 DrawSpline(WXSIZEOF(points
), points
);
770 void wxDCImpl::DrawSpline(int n
, wxPoint points
[])
773 for ( int i
= 0; i
< n
; i
++ )
774 list
.Append(&points
[i
]);
779 // ----------------------------------- spline code ----------------------------------------
781 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
782 double a3
, double b3
, double a4
, double b4
);
783 void wx_clear_stack();
784 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
785 double *y3
, double *x4
, double *y4
);
786 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
787 double x4
, double y4
);
788 static bool wx_spline_add_point(double x
, double y
);
789 static void wx_spline_draw_point_array(wxDC
*dc
);
791 wxPointList wx_spline_point_list
;
793 #define half(z1, z2) ((z1+z2)/2.0)
796 /* iterative version */
798 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
801 register double xmid
, ymid
;
802 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
805 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
807 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
808 xmid
= (double)half(x2
, x3
);
809 ymid
= (double)half(y2
, y3
);
810 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
811 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
812 wx_spline_add_point( x1
, y1
);
813 wx_spline_add_point( xmid
, ymid
);
815 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
816 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
817 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
818 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
823 /* utilities used by spline drawing routines */
825 typedef struct wx_spline_stack_struct
{
826 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
829 #define SPLINE_STACK_DEPTH 20
830 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
831 static Stack
*wx_stack_top
;
832 static int wx_stack_count
;
834 void wx_clear_stack()
836 wx_stack_top
= wx_spline_stack
;
840 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
842 wx_stack_top
->x1
= x1
;
843 wx_stack_top
->y1
= y1
;
844 wx_stack_top
->x2
= x2
;
845 wx_stack_top
->y2
= y2
;
846 wx_stack_top
->x3
= x3
;
847 wx_stack_top
->y3
= y3
;
848 wx_stack_top
->x4
= x4
;
849 wx_stack_top
->y4
= y4
;
854 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
855 double *x3
, double *y3
, double *x4
, double *y4
)
857 if (wx_stack_count
== 0)
861 *x1
= wx_stack_top
->x1
;
862 *y1
= wx_stack_top
->y1
;
863 *x2
= wx_stack_top
->x2
;
864 *y2
= wx_stack_top
->y2
;
865 *x3
= wx_stack_top
->x3
;
866 *y3
= wx_stack_top
->y3
;
867 *x4
= wx_stack_top
->x4
;
868 *y4
= wx_stack_top
->y4
;
872 static bool wx_spline_add_point(double x
, double y
)
874 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
875 wx_spline_point_list
.Append(point
);
879 static void wx_spline_draw_point_array(wxDC
*dc
)
881 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
882 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
885 wxPoint
*point
= node
->GetData();
887 wx_spline_point_list
.Erase(node
);
888 node
= wx_spline_point_list
.GetFirst();
892 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
894 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
897 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
898 double x1
, y1
, x2
, y2
;
900 wxPointList::compatibility_iterator node
= points
->GetFirst();
905 p
= (wxPoint
*)node
->GetData();
910 node
= node
->GetNext();
915 cx1
= (double)((x1
+ x2
) / 2);
916 cy1
= (double)((y1
+ y2
) / 2);
917 cx2
= (double)((cx1
+ x2
) / 2);
918 cy2
= (double)((cy1
+ y2
) / 2);
920 wx_spline_add_point(x1
, y1
);
922 while ((node
= node
->GetNext())
933 cx4
= (double)(x1
+ x2
) / 2;
934 cy4
= (double)(y1
+ y2
) / 2;
935 cx3
= (double)(x1
+ cx4
) / 2;
936 cy3
= (double)(y1
+ cy4
) / 2;
938 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
942 cx2
= (double)(cx1
+ x2
) / 2;
943 cy2
= (double)(cy1
+ y2
) / 2;
946 wx_spline_add_point( cx1
, cy1
);
947 wx_spline_add_point( x2
, y2
);
949 wx_spline_draw_point_array( m_owner
);
952 #endif // wxUSE_SPLINES
956 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
957 const wxColour
& initialColour
,
958 const wxColour
& destColour
,
959 wxDirection nDirection
)
962 wxPen oldPen
= m_pen
;
963 wxBrush oldBrush
= m_brush
;
965 wxUint8 nR1
= initialColour
.Red();
966 wxUint8 nG1
= initialColour
.Green();
967 wxUint8 nB1
= initialColour
.Blue();
968 wxUint8 nR2
= destColour
.Red();
969 wxUint8 nG2
= destColour
.Green();
970 wxUint8 nB2
= destColour
.Blue();
973 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
975 wxInt32 x
= rect
.GetWidth();
976 wxInt32 w
= x
; // width of area to shade
977 wxInt32 xDelta
= w
/256; // height of one shade bend
985 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
987 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
990 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
992 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
995 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
997 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
999 wxColour
colour(nR
,nG
,nB
);
1000 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1001 SetBrush(wxBrush(colour
));
1002 if(nDirection
== wxEAST
)
1003 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1004 xDelta
, rect
.GetHeight());
1005 else //nDirection == wxWEST
1006 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1007 xDelta
, rect
.GetHeight());
1010 else // nDirection == wxNORTH || nDirection == wxSOUTH
1012 wxInt32 y
= rect
.GetHeight();
1013 wxInt32 w
= y
; // height of area to shade
1014 wxInt32 yDelta
= w
/255; // height of one shade bend
1022 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1024 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1027 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1029 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1032 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1034 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1036 wxColour
colour(nR
,nG
,nB
);
1037 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1038 SetBrush(wxBrush(colour
));
1039 if(nDirection
== wxNORTH
)
1040 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1041 rect
.GetWidth(), yDelta
);
1042 else //nDirection == wxSOUTH
1043 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1044 rect
.GetWidth(), yDelta
);
1052 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1053 const wxColour
& initialColour
,
1054 const wxColour
& destColour
,
1055 const wxPoint
& circleCenter
)
1057 //save the old pen color
1058 wxColour oldPenColour
= m_pen
.GetColour();
1060 wxUint8 nR1
= destColour
.Red();
1061 wxUint8 nG1
= destColour
.Green();
1062 wxUint8 nB1
= destColour
.Blue();
1063 wxUint8 nR2
= initialColour
.Red();
1064 wxUint8 nG2
= initialColour
.Green();
1065 wxUint8 nB2
= initialColour
.Blue();
1070 wxInt32 cx
= rect
.GetWidth() / 2;
1071 wxInt32 cy
= rect
.GetHeight() / 2;
1079 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1080 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1082 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1084 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1086 //get color difference
1087 wxInt32 nGradient
= ((nRadius
-
1089 pow((double)(x
- cx
- nCircleOffX
), 2) +
1090 pow((double)(y
- cy
- nCircleOffY
), 2)
1091 )) * 100) / nRadius
;
1093 //normalize Gradient
1098 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1099 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1100 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1103 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1104 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1107 //return old pen color
1108 m_pen
.SetColour(oldPenColour
);
1111 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1113 wxCHECK_RET( win
, "window can't be NULL" );
1115 SetFont(win
->GetFont());
1116 SetTextForeground(win
->GetForegroundColour());
1117 SetTextBackground(win
->GetBackgroundColour());
1118 SetBackground(wxBrush(win
->GetBackgroundColour()));
1121 //-----------------------------------------------------------------------------
1123 //-----------------------------------------------------------------------------
1125 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1127 void wxDC::DrawLabel(const wxString
& text
,
1128 const wxBitmap
& bitmap
,
1132 wxRect
*rectBounding
)
1134 // find the text position
1135 wxCoord widthText
, heightText
, heightLine
;
1136 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1138 wxCoord width
, height
;
1141 width
= widthText
+ bitmap
.GetWidth();
1142 height
= bitmap
.GetHeight();
1147 height
= heightText
;
1151 if ( alignment
& wxALIGN_RIGHT
)
1153 x
= rect
.GetRight() - width
;
1155 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1157 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1159 else // alignment & wxALIGN_LEFT
1164 if ( alignment
& wxALIGN_BOTTOM
)
1166 y
= rect
.GetBottom() - height
;
1168 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1170 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1172 else // alignment & wxALIGN_TOP
1177 // draw the bitmap first
1183 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1185 wxCoord offset
= bitmap
.GetWidth() + 4;
1189 y
+= (height
- heightText
) / 2;
1192 // we will draw the underscore under the accel char later
1193 wxCoord startUnderscore
= 0,
1197 // split the string into lines and draw each of them separately
1199 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1201 if ( pc
== text
.end() || *pc
== '\n' )
1203 int xRealStart
= x
; // init it here to avoid compielr warnings
1205 if ( !curLine
.empty() )
1207 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1208 // wxALIGN_LEFT is 0
1209 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1212 GetTextExtent(curLine
, &widthLine
, NULL
);
1214 if ( alignment
& wxALIGN_RIGHT
)
1216 xRealStart
+= width
- widthLine
;
1218 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1220 xRealStart
+= (width
- widthLine
) / 2;
1223 //else: left aligned, nothing to do
1225 DrawText(curLine
, xRealStart
, y
);
1230 // do we have underscore in this line? we can check yUnderscore
1231 // because it is set below to just y + heightLine if we do
1232 if ( y
== yUnderscore
)
1234 // adjust the horz positions to account for the shift
1235 startUnderscore
+= xRealStart
;
1236 endUnderscore
+= xRealStart
;
1239 if ( pc
== text
.end() )
1244 else // not end of line
1246 if ( pc
- text
.begin() == indexAccel
)
1248 // remeber to draw underscore here
1249 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1251 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1253 yUnderscore
= y
+ heightLine
;
1262 // draw the underscore if found
1263 if ( startUnderscore
!= endUnderscore
)
1265 // it should be of the same colour as text
1266 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1270 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1273 // return bounding rect if requested
1276 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1279 CalcBoundingBox(x0
, y0
);
1280 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1283 #if WXWIN_COMPATIBILITY_2_8
1284 // for compatibility with the old code when wxCoord was long everywhere
1285 void wxDC::GetTextExtent(const wxString
& string
,
1288 long *externalLeading
,
1289 const wxFont
*theFont
) const
1291 wxCoord x2
, y2
, descent2
, externalLeading2
;
1292 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1293 &descent2
, &externalLeading2
,
1300 *descent
= descent2
;
1301 if ( externalLeading
)
1302 *externalLeading
= externalLeading2
;
1305 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1308 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1315 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1318 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1325 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1327 wxCoord xx
,yy
,ww
,hh
;
1328 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1335 #endif // WXWIN_COMPATIBILITY_2_8
1338 Notes for wxWidgets DrawEllipticArcRot(...)
1340 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1341 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1344 All methods are generic, so they can be implemented in wxDCBase.
1345 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1346 methods like (WinCE) wxDC::DoDrawArc(...).
1348 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1349 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1350 parts) or every column (in steep parts) only one pixel is calculated.
1351 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1352 starting angle is not equal to the ending angle. The calculation of the
1353 pixels is done using simple arithmetic only and should perform not too
1354 bad even on devices without floating point processor. I didn't test this yet.
1356 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1357 For instance: an ellipse rotated 180 degrees is drawn
1358 slightly different from the original.
1360 The points are then moved to an array and used to draw a polyline and/or polygon
1361 (with center added, the pie).
1362 The result looks quite similar to the native ellipse, only e few pixels differ.
1364 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1365 slower as DrawEllipse(...), which calls the native API.
1366 An rotated ellipse outside the clipping region takes nearly the same time,
1367 while an native ellipse outside takes nearly no time to draw.
1369 If you draw an arc with this new method, you will see the starting and ending angles
1370 are calculated properly.
1371 If you use DrawEllipticArc(...), you will see they are only correct for circles
1372 and not properly calculated for ellipses.
1375 p.lenhard@t-online.de
1379 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1380 wxCoord w
, wxCoord h
,
1381 double sa
, double ea
, double angle
)
1385 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1386 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1388 // Add center (for polygon/pie)
1389 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1391 // copy list into array and delete list elements
1392 int n
= list
.GetCount();
1393 wxPoint
*points
= new wxPoint
[n
];
1395 wxPointList::compatibility_iterator node
;
1396 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1398 wxPoint
*point
= node
->GetData();
1399 points
[i
].x
= point
->x
;
1400 points
[i
].y
= point
->y
;
1404 // first draw the pie without pen, if necessary
1405 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1407 wxPen
tempPen( GetPen() );
1408 SetPen( *wxTRANSPARENT_PEN
);
1409 DoDrawPolygon( n
, points
, 0, 0 );
1413 // then draw the arc without brush, if necessary
1414 if( GetPen() != *wxTRANSPARENT_PEN
)
1417 DoDrawLines( n
-1, points
, 0, 0 );
1422 } // DrawEllipticArcRot
1424 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1429 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1430 double dCosA
= cos(angle
*2.0*pi
/360.0);
1431 wxPointList::compatibility_iterator node
;
1432 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1434 wxPoint
* point
= node
->GetData();
1436 // transform coordinates, if necessary
1437 if( center
.x
) point
->x
-= center
.x
;
1438 if( center
.y
) point
->y
-= center
.y
;
1440 // calculate rotation, rounding simply by implicit cast to integer
1441 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1442 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1445 // back transform coordinates, if necessary
1446 if( center
.x
) point
->x
+= center
.x
;
1447 if( center
.y
) point
->y
+= center
.y
;
1452 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1453 wxCoord xStart
, wxCoord yStart
,
1454 wxCoord w
, wxCoord h
,
1455 double sa
, double ea
)
1466 bool bUseAngles
= false;
1472 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1474 if( 2*a
== w
) decrX
= 1;
1476 if( 2*b
== h
) decrY
= 1;
1478 wxCoord xCenter
= xStart
+ a
;
1479 wxCoord yCenter
= yStart
+ b
;
1480 // calculate data for start and end, if necessary
1484 // normalisation of angles
1485 while( sa
<0 ) sa
+= 360;
1486 while( ea
<0 ) ea
+= 360;
1487 while( sa
>=360 ) sa
-= 360;
1488 while( ea
>=360 ) ea
-= 360;
1489 // calculate quadrant numbers
1490 if( sa
> 270 ) sq
= 3;
1491 else if( sa
> 180 ) sq
= 2;
1492 else if( sa
> 90 ) sq
= 1;
1493 if( ea
> 270 ) eq
= 3;
1494 else if( ea
> 180 ) eq
= 2;
1495 else if( ea
> 90 ) eq
= 1;
1496 sar
= sa
* pi
/ 180.0;
1497 ear
= ea
* pi
/ 180.0;
1498 // correct angle circle -> ellipse
1499 sar
= atan( -a
/(double)b
* tan( sar
) );
1500 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1501 ear
= atan( -a
/(double)b
* tan( ear
) );
1502 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1503 // coordinates of points
1504 xsa
= xCenter
+ a
* cos( sar
);
1505 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1506 ysa
= yCenter
+ b
* sin( sar
);
1507 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1508 xea
= xCenter
+ a
* cos( ear
);
1509 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1510 yea
= yCenter
+ b
* sin( ear
);
1511 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1513 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1515 double c2
= 2.0 / w
;
1524 // Lists for quadrant 1 to 4
1525 wxPointList pointsarray
[4];
1526 // Calculate points for first quadrant and set in all quadrants
1527 for( x
= 0; x
<= a
; ++x
)
1532 bool bNewPoint
= false;
1533 while( y2
> c1
- c2
* x2
&& y
> 0 )
1539 // old y now to big: set point with old y, old x
1540 if( bNewPoint
&& x
>1)
1543 // remove points on the same line
1544 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1545 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1546 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1547 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1549 } // calculate point
1551 // Starting and/or ending points for the quadrants, first quadrant gets both.
1552 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1553 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1554 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1555 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1556 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1558 // copy quadrants in original list
1561 // Copy the right part of the points in the lists
1562 // and delete the wxPoints, because they do not leave this method.
1563 points
->Append( new wxPoint( xsa
, ysa
) );
1565 bool bStarted
= false;
1566 bool bReady
= false;
1567 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1570 wxPointList::compatibility_iterator node
;
1571 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1573 // once: go to starting point in start quadrant
1576 node
->GetData()->x
< xsa
+1 && q
<= 1
1578 node
->GetData()->x
> xsa
-1 && q
>= 2
1585 // copy point, if not at ending point
1588 if( q
!= eq
|| bForceTurn
1590 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1592 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1596 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1597 points
->Append( pPoint
);
1599 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1609 } // while not bReady
1610 points
->Append( new wxPoint( xea
, yea
) );
1613 for( q
= 0; q
< 4; ++q
)
1615 wxPointList::compatibility_iterator node
;
1616 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1618 wxPoint
*p
= node
->GetData();
1625 wxPointList::compatibility_iterator node
;
1626 // copy whole ellipse, wxPoints will be deleted outside
1627 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1629 wxPoint
*p
= node
->GetData();
1630 points
->Append( p
);
1632 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1634 wxPoint
*p
= node
->GetData();
1635 points
->Append( p
);
1637 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1639 wxPoint
*p
= node
->GetData();
1640 points
->Append( p
);
1642 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1644 wxPoint
*p
= node
->GetData();
1645 points
->Append( p
);
1648 } // CalculateEllipticPoints
1650 #endif // __WXWINCE__