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/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
33 #include "wx/prntbase.h"
42 #include "wx/msw/dcclient.h"
43 #include "wx/msw/dcmemory.h"
44 #include "wx/msw/dcscreen.h"
48 #include "wx/gtk/dcclient.h"
49 #include "wx/gtk/dcmemory.h"
50 #include "wx/gtk/dcscreen.h"
54 #include "wx/mac/dcclient.h"
55 #include "wx/mac/dcmemory.h"
56 #include "wx/mac/dcscreen.h"
59 //----------------------------------------------------------------------------
61 //----------------------------------------------------------------------------
63 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
65 void wxDCFactory::SetDCFactory( wxDCFactory
*factory
)
67 if (wxDCFactory::m_factory
)
68 delete wxDCFactory::m_factory
;
70 wxDCFactory::m_factory
= factory
;
73 wxDCFactory
*wxDCFactory::GetFactory()
75 if (!wxDCFactory::m_factory
)
76 wxDCFactory::m_factory
= new wxNativeDCFactory
;
78 return wxDCFactory::m_factory
;
81 //-----------------------------------------------------------------------------
83 //-----------------------------------------------------------------------------
85 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
)
87 return new wxWindowDCImpl( owner
);
90 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
92 return new wxWindowDCImpl( owner
, window
);
95 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
)
97 return new wxClientDCImpl( owner
);
100 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
102 return new wxClientDCImpl( owner
, window
);
105 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
)
107 return new wxPaintDCImpl( owner
);
110 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
112 return new wxPaintDCImpl( owner
, window
);
115 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
117 return new wxMemoryDCImpl( owner
);
120 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxBitmap
&bitmap
)
122 return new wxMemoryDCImpl( owner
, bitmap
);
125 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
127 return new wxMemoryDCImpl( owner
, dc
);
130 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
132 return new wxScreenDCImpl( owner
);
135 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
137 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
138 return factory
->CreatePrinterDCImpl( owner
, data
);
141 //-----------------------------------------------------------------------------
143 //-----------------------------------------------------------------------------
145 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
147 wxWindowDC::wxWindowDC()
151 wxWindowDC::wxWindowDC( wxWindow
*win
)
153 wxDCFactory
*factory
= wxDCFactory::GetFactory();
154 m_pimpl
= factory
->CreateWindowDC( this, win
);
157 //-----------------------------------------------------------------------------
159 //-----------------------------------------------------------------------------
161 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxWindowDC
)
163 wxClientDC::wxClientDC()
167 wxClientDC::wxClientDC( wxWindow
*win
)
169 wxDCFactory
*factory
= wxDCFactory::GetFactory();
170 m_pimpl
= factory
->CreateClientDC( this, win
);
173 //-----------------------------------------------------------------------------
175 //-----------------------------------------------------------------------------
177 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
179 wxMemoryDC::wxMemoryDC()
181 wxDCFactory
*factory
= wxDCFactory::GetFactory();
182 m_pimpl
= factory
->CreateMemoryDC( this );
185 wxMemoryDC::wxMemoryDC( wxBitmap
& bitmap
)
187 wxDCFactory
*factory
= wxDCFactory::GetFactory();
188 m_pimpl
= factory
->CreateMemoryDC( this, bitmap
);
191 wxMemoryDC::wxMemoryDC( wxDC
*dc
)
193 wxDCFactory
*factory
= wxDCFactory::GetFactory();
194 m_pimpl
= factory
->CreateMemoryDC( this, dc
);
197 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
199 // make sure that the given wxBitmap is not sharing its data with other
200 // wxBitmap instances as its contents will be modified by any drawing
201 // operation done on this DC
205 GetImpl()->DoSelect(bmp
);
208 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
210 GetImpl()->DoSelect(bmp
);
213 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
215 return GetImpl()->GetSelectedBitmap();
218 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
220 return GetImpl()->GetSelectedBitmap();
224 //-----------------------------------------------------------------------------
226 //-----------------------------------------------------------------------------
228 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxClientDC
)
230 wxPaintDC::wxPaintDC()
234 wxPaintDC::wxPaintDC( wxWindow
*win
)
236 wxDCFactory
*factory
= wxDCFactory::GetFactory();
237 m_pimpl
= factory
->CreatePaintDC( this, win
);
240 //-----------------------------------------------------------------------------
242 //-----------------------------------------------------------------------------
244 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
246 wxScreenDC::wxScreenDC()
248 wxDCFactory
*factory
= wxDCFactory::GetFactory();
249 m_pimpl
= factory
->CreateScreenDC( this );
252 //-----------------------------------------------------------------------------
254 //-----------------------------------------------------------------------------
256 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
258 wxPrinterDC::wxPrinterDC()
260 wxPrintData data
; // Does this make sense?
261 wxDCFactory
*factory
= wxDCFactory::GetFactory();
262 m_pimpl
= factory
->CreatePrinterDC( this, data
);
265 wxPrinterDC::wxPrinterDC( const wxPrintData
&data
)
267 wxDCFactory
*factory
= wxDCFactory::GetFactory();
268 m_pimpl
= factory
->CreatePrinterDC( this, data
);
271 wxPrinterDC::~wxPrinterDC()
275 wxRect
wxPrinterDC::GetPaperRect()
277 return GetImpl()->GetPaperRect();
280 int wxPrinterDC::GetResolution()
282 return GetImpl()->GetResolution();
286 //-----------------------------------------------------------------------------
288 //-----------------------------------------------------------------------------
290 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
292 wxDCImpl::wxDCImpl( wxDC
*owner
)
294 , m_colour(wxColourDisplay())
298 , m_isBBoxValid(false)
299 , m_logicalOriginX(0), m_logicalOriginY(0)
300 , m_deviceOriginX(0), m_deviceOriginY(0)
301 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
302 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
303 , m_userScaleX(1.0), m_userScaleY(1.0)
304 , m_scaleX(1.0), m_scaleY(1.0)
305 , m_signX(1), m_signY(1)
306 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
307 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
308 , m_logicalFunction(wxCOPY
)
309 , m_backgroundMode(wxTRANSPARENT
)
310 , m_mappingMode(wxMM_TEXT
)
313 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
314 , m_textForegroundColour(*wxBLACK
)
315 , m_textBackgroundColour(*wxWHITE
)
319 , m_hasCustomPalette(false)
320 #endif // wxUSE_PALETTE
324 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
325 (double)wxGetDisplaySizeMM().GetWidth();
326 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
327 (double)wxGetDisplaySizeMM().GetHeight();
333 wxDCImpl::~wxDCImpl()
337 // ----------------------------------------------------------------------------
338 // coordinate conversions and transforms
339 // ----------------------------------------------------------------------------
341 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
343 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
346 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
348 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
351 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
353 return wxRound((double)(x
) / m_scaleX
);
356 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
358 return wxRound((double)(y
) / m_scaleY
);
361 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
363 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
366 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
368 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ m_deviceLocalOriginY
;
371 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
373 return wxRound((double)(x
) * m_scaleX
);
376 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
378 return wxRound((double)(y
) * m_scaleY
);
381 void wxDCImpl::ComputeScaleAndOrigin()
383 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
384 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
387 void wxDCImpl::SetMapMode( int mode
)
392 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
395 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
398 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
401 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
405 SetLogicalScale( 1.0, 1.0 );
408 m_mappingMode
= mode
;
411 void wxDCImpl::SetUserScale( double x
, double y
)
413 // allow negative ? -> no
416 ComputeScaleAndOrigin();
419 void wxDCImpl::SetLogicalScale( double x
, double y
)
424 ComputeScaleAndOrigin();
427 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
429 m_logicalOriginX
= x
* m_signX
;
430 m_logicalOriginY
= y
* m_signY
;
431 ComputeScaleAndOrigin();
434 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
438 ComputeScaleAndOrigin();
441 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
443 m_deviceLocalOriginX
= x
;
444 m_deviceLocalOriginY
= y
;
445 ComputeScaleAndOrigin();
448 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
450 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
451 // wxWidgets 2.9: no longer override it
452 m_signX
= (xLeftRight
? 1 : -1);
453 m_signY
= (yBottomUp
? -1 : 1);
454 ComputeScaleAndOrigin();
458 // Each element of the widths array will be the width of the string up to and
459 // including the corresponding character in text. This is the generic
460 // implementation, the port-specific classes should do this with native APIs
461 // if available and if faster. Note: pango_layout_index_to_pos is much slower
462 // than calling GetTextExtent!!
469 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
470 ~FontWidthCache() { delete []m_widths
; }
475 m_widths
= new int[FWC_SIZE
];
477 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
485 static FontWidthCache s_fontWidthCache
;
487 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
491 const size_t len
= text
.length();
495 // reset the cache if font or horizontal scale have changed
496 if ( !s_fontWidthCache
.m_widths
||
497 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
498 (s_fontWidthCache
.m_font
!= GetFont()) )
500 s_fontWidthCache
.Reset();
501 s_fontWidthCache
.m_font
= GetFont();
502 s_fontWidthCache
.m_scaleX
= m_scaleX
;
505 // Calculate the position of each character based on the widths of
506 // the previous characters
508 for ( size_t i
= 0; i
< len
; i
++ )
510 const wxChar c
= text
[i
];
511 unsigned int c_int
= (unsigned int)c
;
513 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
515 w
= s_fontWidthCache
.m_widths
[c_int
];
519 DoGetTextExtent(c
, &w
, &h
);
520 if (c_int
< FWC_SIZE
)
521 s_fontWidthCache
.m_widths
[c_int
] = w
;
525 widths
[i
] = totalWidth
;
531 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
535 const wxFont
*font
) const
537 wxCoord widthTextMax
= 0, widthLine
,
538 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
541 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
543 if ( pc
== text
.end() || *pc
== _T('\n') )
545 if ( curLine
.empty() )
547 // we can't use GetTextExtent - it will return 0 for both width
548 // and height and an empty line should count in height
551 // assume that this line has the same height as the previous
553 if ( !heightLineDefault
)
554 heightLineDefault
= heightLine
;
556 if ( !heightLineDefault
)
558 // but we don't know it yet - choose something reasonable
559 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
563 heightTextTotal
+= heightLineDefault
;
567 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
569 if ( widthLine
> widthTextMax
)
570 widthTextMax
= widthLine
;
571 heightTextTotal
+= heightLine
;
574 if ( pc
== text
.end() )
592 *y
= heightTextTotal
;
597 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
598 wxCoord width
, wxCoord height
)
600 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
602 wxCoord x2
= x1
+ width
,
605 // the pen width is calibrated to give 3 for width == height == 10
606 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
608 // we're drawing a scaled version of wx/generic/tick.xpm here
609 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
610 y3
= y1
+ height
/ 2; // y of the left tick branch
611 DoDrawLine(x1
, y3
, x3
, y2
);
612 DoDrawLine(x3
, y2
, x2
, y1
);
614 CalcBoundingBox(x1
, y1
);
615 CalcBoundingBox(x2
, y2
);
619 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
620 wxCoord dstWidth
, wxCoord dstHeight
,
622 wxCoord xsrc
, wxCoord ysrc
,
623 wxCoord srcWidth
, wxCoord srcHeight
,
629 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
630 _T("invalid blit size") );
632 // emulate the stretching by modifying the DC scale
633 double xscale
= (double)srcWidth
/dstWidth
,
634 yscale
= (double)srcHeight
/dstHeight
;
636 double xscaleOld
, yscaleOld
;
637 GetUserScale(&xscaleOld
, &yscaleOld
);
638 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
640 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
641 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
643 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
645 SetUserScale(xscaleOld
, yscaleOld
);
650 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
652 int n
= list
->GetCount();
653 wxPoint
*points
= new wxPoint
[n
];
656 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
658 wxPoint
*point
= node
->GetData();
659 points
[i
].x
= point
->x
;
660 points
[i
].y
= point
->y
;
663 DoDrawLines(n
, points
, xoffset
, yoffset
);
668 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
669 wxCoord xoffset
, wxCoord yoffset
,
672 int n
= list
->GetCount();
673 wxPoint
*points
= new wxPoint
[n
];
676 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
678 wxPoint
*point
= node
->GetData();
679 points
[i
].x
= point
->x
;
680 points
[i
].y
= point
->y
;
683 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
689 wxDCImpl::DoDrawPolyPolygon(int n
,
692 wxCoord xoffset
, wxCoord yoffset
,
697 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
705 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
710 pts
= new wxPoint
[j
+n
-1];
711 for (i
= 0; i
< j
; i
++)
713 for (i
= 2; i
<= n
; i
++)
715 lastOfs
-= count
[n
-i
];
716 pts
[j
++] = pts
[lastOfs
];
720 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
721 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
723 for (i
= j
= 0; i
< n
; i
++)
725 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
733 void wxDCImpl::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
735 wxPointList point_list
;
737 wxPoint
*point1
= new wxPoint
;
738 point1
->x
= x1
; point1
->y
= y1
;
739 point_list
.Append( point1
);
741 wxPoint
*point2
= new wxPoint
;
742 point2
->x
= x2
; point2
->y
= y2
;
743 point_list
.Append( point2
);
745 wxPoint
*point3
= new wxPoint
;
746 point3
->x
= x3
; point3
->y
= y3
;
747 point_list
.Append( point3
);
749 DoDrawSpline(&point_list
);
751 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
753 wxPoint
*p
= node
->GetData();
758 void wxDCImpl::DoDrawSpline(int n
, wxPoint points
[])
761 for (int i
=0; i
< n
; i
++)
762 list
.Append( &points
[i
] );
767 // ----------------------------------- spline code ----------------------------------------
769 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
770 double a3
, double b3
, double a4
, double b4
);
771 void wx_clear_stack();
772 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
773 double *y3
, double *x4
, double *y4
);
774 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
775 double x4
, double y4
);
776 static bool wx_spline_add_point(double x
, double y
);
777 static void wx_spline_draw_point_array(wxDC
*dc
);
779 wxPointList wx_spline_point_list
;
781 #define half(z1, z2) ((z1+z2)/2.0)
784 /* iterative version */
786 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
789 register double xmid
, ymid
;
790 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
793 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
795 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
796 xmid
= (double)half(x2
, x3
);
797 ymid
= (double)half(y2
, y3
);
798 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
799 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
800 wx_spline_add_point( x1
, y1
);
801 wx_spline_add_point( xmid
, ymid
);
803 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
804 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
805 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
806 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
811 /* utilities used by spline drawing routines */
813 typedef struct wx_spline_stack_struct
{
814 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
817 #define SPLINE_STACK_DEPTH 20
818 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
819 static Stack
*wx_stack_top
;
820 static int wx_stack_count
;
822 void wx_clear_stack()
824 wx_stack_top
= wx_spline_stack
;
828 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
830 wx_stack_top
->x1
= x1
;
831 wx_stack_top
->y1
= y1
;
832 wx_stack_top
->x2
= x2
;
833 wx_stack_top
->y2
= y2
;
834 wx_stack_top
->x3
= x3
;
835 wx_stack_top
->y3
= y3
;
836 wx_stack_top
->x4
= x4
;
837 wx_stack_top
->y4
= y4
;
842 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
843 double *x3
, double *y3
, double *x4
, double *y4
)
845 if (wx_stack_count
== 0)
849 *x1
= wx_stack_top
->x1
;
850 *y1
= wx_stack_top
->y1
;
851 *x2
= wx_stack_top
->x2
;
852 *y2
= wx_stack_top
->y2
;
853 *x3
= wx_stack_top
->x3
;
854 *y3
= wx_stack_top
->y3
;
855 *x4
= wx_stack_top
->x4
;
856 *y4
= wx_stack_top
->y4
;
860 static bool wx_spline_add_point(double x
, double y
)
862 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
863 wx_spline_point_list
.Append(point
);
867 static void wx_spline_draw_point_array(wxDC
*dc
)
869 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
870 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
873 wxPoint
*point
= node
->GetData();
875 wx_spline_point_list
.Erase(node
);
876 node
= wx_spline_point_list
.GetFirst();
880 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
882 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
885 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
886 double x1
, y1
, x2
, y2
;
888 wxPointList::compatibility_iterator node
= points
->GetFirst();
893 p
= (wxPoint
*)node
->GetData();
898 node
= node
->GetNext();
903 cx1
= (double)((x1
+ x2
) / 2);
904 cy1
= (double)((y1
+ y2
) / 2);
905 cx2
= (double)((cx1
+ x2
) / 2);
906 cy2
= (double)((cy1
+ y2
) / 2);
908 wx_spline_add_point(x1
, y1
);
910 while ((node
= node
->GetNext())
921 cx4
= (double)(x1
+ x2
) / 2;
922 cy4
= (double)(y1
+ y2
) / 2;
923 cx3
= (double)(x1
+ cx4
) / 2;
924 cy3
= (double)(y1
+ cy4
) / 2;
926 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
930 cx2
= (double)(cx1
+ x2
) / 2;
931 cy2
= (double)(cy1
+ y2
) / 2;
934 wx_spline_add_point( cx1
, cy1
);
935 wx_spline_add_point( x2
, y2
);
937 wx_spline_draw_point_array( m_owner
);
940 #endif // wxUSE_SPLINES
944 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
945 const wxColour
& initialColour
,
946 const wxColour
& destColour
,
947 wxDirection nDirection
)
950 wxPen oldPen
= m_pen
;
951 wxBrush oldBrush
= m_brush
;
953 wxUint8 nR1
= initialColour
.Red();
954 wxUint8 nG1
= initialColour
.Green();
955 wxUint8 nB1
= initialColour
.Blue();
956 wxUint8 nR2
= destColour
.Red();
957 wxUint8 nG2
= destColour
.Green();
958 wxUint8 nB2
= destColour
.Blue();
961 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
963 wxInt32 x
= rect
.GetWidth();
964 wxInt32 w
= x
; // width of area to shade
965 wxInt32 xDelta
= w
/256; // height of one shade bend
973 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
975 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
978 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
980 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
983 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
985 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
987 wxColour
colour(nR
,nG
,nB
);
988 SetPen(wxPen(colour
, 1, wxSOLID
));
989 SetBrush(wxBrush(colour
));
990 if(nDirection
== wxEAST
)
991 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
992 xDelta
, rect
.GetHeight());
993 else //nDirection == wxWEST
994 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
995 xDelta
, rect
.GetHeight());
998 else // nDirection == wxNORTH || nDirection == wxSOUTH
1000 wxInt32 y
= rect
.GetHeight();
1001 wxInt32 w
= y
; // height of area to shade
1002 wxInt32 yDelta
= w
/255; // height of one shade bend
1010 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1012 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1015 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1017 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1020 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1022 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1024 wxColour
colour(nR
,nG
,nB
);
1025 SetPen(wxPen(colour
, 1, wxSOLID
));
1026 SetBrush(wxBrush(colour
));
1027 if(nDirection
== wxNORTH
)
1028 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1029 rect
.GetWidth(), yDelta
);
1030 else //nDirection == wxSOUTH
1031 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1032 rect
.GetWidth(), yDelta
);
1040 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1041 const wxColour
& initialColour
,
1042 const wxColour
& destColour
,
1043 const wxPoint
& circleCenter
)
1045 //save the old pen color
1046 wxColour oldPenColour
= m_pen
.GetColour();
1048 wxUint8 nR1
= destColour
.Red();
1049 wxUint8 nG1
= destColour
.Green();
1050 wxUint8 nB1
= destColour
.Blue();
1051 wxUint8 nR2
= initialColour
.Red();
1052 wxUint8 nG2
= initialColour
.Green();
1053 wxUint8 nB2
= initialColour
.Blue();
1058 wxInt32 cx
= rect
.GetWidth() / 2;
1059 wxInt32 cy
= rect
.GetHeight() / 2;
1067 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1068 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1070 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1072 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1074 //get color difference
1075 wxInt32 nGradient
= ((nRadius
-
1077 pow((double)(x
- cx
- nCircleOffX
), 2) +
1078 pow((double)(y
- cy
- nCircleOffY
), 2)
1079 )) * 100) / nRadius
;
1081 //normalize Gradient
1086 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1087 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1088 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1091 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1092 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1095 //return old pen color
1096 m_pen
.SetColour(oldPenColour
);
1099 //-----------------------------------------------------------------------------
1101 //-----------------------------------------------------------------------------
1103 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1105 void wxDC::DrawLabel(const wxString
& text
,
1106 const wxBitmap
& bitmap
,
1110 wxRect
*rectBounding
)
1112 // find the text position
1113 wxCoord widthText
, heightText
, heightLine
;
1114 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1116 wxCoord width
, height
;
1119 width
= widthText
+ bitmap
.GetWidth();
1120 height
= bitmap
.GetHeight();
1125 height
= heightText
;
1129 if ( alignment
& wxALIGN_RIGHT
)
1131 x
= rect
.GetRight() - width
;
1133 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1135 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1137 else // alignment & wxALIGN_LEFT
1142 if ( alignment
& wxALIGN_BOTTOM
)
1144 y
= rect
.GetBottom() - height
;
1146 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1148 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1150 else // alignment & wxALIGN_TOP
1155 // draw the bitmap first
1161 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1163 wxCoord offset
= bitmap
.GetWidth() + 4;
1167 y
+= (height
- heightText
) / 2;
1170 // we will draw the underscore under the accel char later
1171 wxCoord startUnderscore
= 0,
1175 // split the string into lines and draw each of them separately
1177 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1179 if ( *pc
== _T('\n') || pc
== text
.end() )
1181 int xRealStart
= x
; // init it here to avoid compielr warnings
1183 if ( !curLine
.empty() )
1185 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1186 // wxALIGN_LEFT is 0
1187 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1190 GetTextExtent(curLine
, &widthLine
, NULL
);
1192 if ( alignment
& wxALIGN_RIGHT
)
1194 xRealStart
+= width
- widthLine
;
1196 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1198 xRealStart
+= (width
- widthLine
) / 2;
1201 //else: left aligned, nothing to do
1203 DrawText(curLine
, xRealStart
, y
);
1208 // do we have underscore in this line? we can check yUnderscore
1209 // because it is set below to just y + heightLine if we do
1210 if ( y
== yUnderscore
)
1212 // adjust the horz positions to account for the shift
1213 startUnderscore
+= xRealStart
;
1214 endUnderscore
+= xRealStart
;
1217 if ( pc
== text
.end() )
1222 else // not end of line
1224 if ( pc
- text
.begin() == indexAccel
)
1226 // remeber to draw underscore here
1227 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1229 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1231 yUnderscore
= y
+ heightLine
;
1240 // draw the underscore if found
1241 if ( startUnderscore
!= endUnderscore
)
1243 // it should be of the same colour as text
1244 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1248 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1251 // return bounding rect if requested
1254 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1257 CalcBoundingBox(x0
, y0
);
1258 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1261 #if WXWIN_COMPATIBILITY_2_8
1262 // for compatibility with the old code when wxCoord was long everywhere
1263 void wxDC::GetTextExtent(const wxString
& string
,
1266 long *externalLeading
,
1267 const wxFont
*theFont
) const
1269 wxCoord x2
, y2
, descent2
, externalLeading2
;
1270 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1271 &descent2
, &externalLeading2
,
1278 *descent
= descent2
;
1279 if ( externalLeading
)
1280 *externalLeading
= externalLeading2
;
1283 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1286 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1293 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1296 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1303 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1305 wxCoord xx
,yy
,ww
,hh
;
1306 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1313 #endif // WXWIN_COMPATIBILITY_2_8
1316 #else // wxUSE_NEW_DC
1319 // bool wxDCBase::sm_cacheing = false;
1321 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1323 // ============================================================================
1325 // ============================================================================
1327 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1328 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1330 wxDCBase::wxDCBase()
1331 : m_colour(wxColourDisplay())
1334 , m_isInteractive(0)
1335 , m_isBBoxValid(false)
1336 , m_logicalOriginX(0), m_logicalOriginY(0)
1337 , m_deviceOriginX(0), m_deviceOriginY(0)
1338 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1339 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1340 , m_userScaleX(1.0), m_userScaleY(1.0)
1341 , m_scaleX(1.0), m_scaleY(1.0)
1342 , m_signX(1), m_signY(1)
1343 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1344 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1345 , m_logicalFunction(wxCOPY
)
1346 , m_backgroundMode(wxTRANSPARENT
)
1347 , m_mappingMode(wxMM_TEXT
)
1350 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1351 , m_textForegroundColour(*wxBLACK
)
1352 , m_textBackgroundColour(*wxWHITE
)
1356 , m_hasCustomPalette(false)
1357 #endif // wxUSE_PALETTE
1359 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1360 (double)wxGetDisplaySizeMM().GetWidth();
1361 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1362 (double)wxGetDisplaySizeMM().GetHeight();
1368 wxDCBase::~wxDCBase()
1372 #if WXWIN_COMPATIBILITY_2_6
1373 void wxDCBase::BeginDrawing()
1377 void wxDCBase::EndDrawing()
1380 #endif // WXWIN_COMPATIBILITY_2_6
1382 #if WXWIN_COMPATIBILITY_2_8
1383 // for compatibility with the old code when wxCoord was long everywhere
1384 void wxDCBase::GetTextExtent(const wxString
& string
,
1387 long *externalLeading
,
1388 const wxFont
*theFont
) const
1390 wxCoord x2
, y2
, descent2
, externalLeading2
;
1391 DoGetTextExtent(string
, &x2
, &y2
,
1392 &descent2
, &externalLeading2
,
1399 *descent
= descent2
;
1400 if ( externalLeading
)
1401 *externalLeading
= externalLeading2
;
1404 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1407 DoGetLogicalOrigin(&x2
, &y2
);
1414 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1417 DoGetDeviceOrigin(&x2
, &y2
);
1424 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1426 wxCoord xx
,yy
,ww
,hh
;
1427 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1433 #endif // WXWIN_COMPATIBILITY_2_8
1437 // ----------------------------------------------------------------------------
1438 // coordinate conversions and transforms
1439 // ----------------------------------------------------------------------------
1441 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1443 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1446 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1448 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1451 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1453 return wxRound((double)(x
) / m_scaleX
);
1456 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1458 return wxRound((double)(y
) / m_scaleY
);
1461 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1463 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1466 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1468 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1471 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1473 return wxRound((double)(x
) * m_scaleX
);
1476 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1478 return wxRound((double)(y
) * m_scaleY
);
1481 void wxDCBase::ComputeScaleAndOrigin()
1483 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1484 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1487 void wxDCBase::SetMapMode( int mode
)
1492 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1495 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1498 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1501 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1505 SetLogicalScale( 1.0, 1.0 );
1508 m_mappingMode
= mode
;
1511 void wxDCBase::SetUserScale( double x
, double y
)
1513 // allow negative ? -> no
1516 ComputeScaleAndOrigin();
1519 void wxDCBase::SetLogicalScale( double x
, double y
)
1522 m_logicalScaleX
= x
;
1523 m_logicalScaleY
= y
;
1524 ComputeScaleAndOrigin();
1527 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1529 m_logicalOriginX
= x
* m_signX
;
1530 m_logicalOriginY
= y
* m_signY
;
1531 ComputeScaleAndOrigin();
1534 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1536 m_deviceOriginX
= x
;
1537 m_deviceOriginY
= y
;
1538 ComputeScaleAndOrigin();
1541 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1543 m_deviceLocalOriginX
= x
;
1544 m_deviceLocalOriginY
= y
;
1545 ComputeScaleAndOrigin();
1548 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1550 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1551 // wxWidgets 2.9: no longer override it
1552 m_signX
= (xLeftRight
? 1 : -1);
1553 m_signY
= (yBottomUp
? -1 : 1);
1554 ComputeScaleAndOrigin();
1557 // ----------------------------------------------------------------------------
1559 // ----------------------------------------------------------------------------
1561 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1562 wxCoord width
, wxCoord height
)
1564 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1566 wxCoord x2
= x1
+ width
,
1569 // the pen width is calibrated to give 3 for width == height == 10
1570 wxDCPenChanger
pen((wxDC
&)*this,
1571 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1573 // we're drawing a scaled version of wx/generic/tick.xpm here
1574 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1575 y3
= y1
+ height
/ 2; // y of the left tick branch
1576 DoDrawLine(x1
, y3
, x3
, y2
);
1577 DoDrawLine(x3
, y2
, x2
, y1
);
1579 CalcBoundingBox(x1
, y1
);
1580 CalcBoundingBox(x2
, y2
);
1583 // ----------------------------------------------------------------------------
1584 // stubs for functions not implemented in all ports
1585 // ----------------------------------------------------------------------------
1588 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1589 wxCoord dstWidth
, wxCoord dstHeight
,
1591 wxCoord xsrc
, wxCoord ysrc
,
1592 wxCoord srcWidth
, wxCoord srcHeight
,
1598 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1599 _T("invalid blit size") );
1601 // emulate the stretching by modifying the DC scale
1602 double xscale
= (double)srcWidth
/dstWidth
,
1603 yscale
= (double)srcHeight
/dstHeight
;
1605 double xscaleOld
, yscaleOld
;
1606 GetUserScale(&xscaleOld
, &yscaleOld
);
1607 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1609 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1610 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1612 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1614 SetUserScale(xscaleOld
, yscaleOld
);
1619 // ----------------------------------------------------------------------------
1621 // ----------------------------------------------------------------------------
1623 void wxDCBase::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1625 unsigned int n
= list
->GetCount();
1626 wxPoint
*points
= new wxPoint
[n
];
1629 wxPointList::compatibility_iterator node
;
1630 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1632 wxPoint
*point
= node
->GetData();
1633 points
[i
].x
= point
->x
;
1634 points
[i
].y
= point
->y
;
1637 DoDrawLines(n
, points
, xoffset
, yoffset
);
1642 #if WXWIN_COMPATIBILITY_2_8
1643 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1645 unsigned int n
= list
->GetCount();
1646 wxPoint
*points
= new wxPoint
[n
];
1649 wxObjectList::compatibility_iterator node
;
1650 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1652 wxPoint
*point
= (wxPoint
*) node
->GetData();
1653 points
[i
].x
= point
->x
;
1654 points
[i
].y
= point
->y
;
1657 DoDrawLines(n
, points
, xoffset
, yoffset
);
1661 #endif // WXWIN_COMPATIBILITY_2_8
1664 void wxDCBase::DrawPolygon(const wxPointList
*list
,
1665 wxCoord xoffset
, wxCoord yoffset
,
1668 unsigned int n
= list
->GetCount();
1669 wxPoint
*points
= new wxPoint
[n
];
1672 wxPointList::compatibility_iterator node
;
1673 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1675 wxPoint
*point
= node
->GetData();
1676 points
[i
].x
= point
->x
;
1677 points
[i
].y
= point
->y
;
1680 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1686 #if WXWIN_COMPATIBILITY_2_8
1687 void wxDCBase::DrawPolygon(const wxList
*list
,
1688 wxCoord xoffset
, wxCoord yoffset
,
1691 unsigned int n
= list
->GetCount();
1692 wxPoint
*points
= new wxPoint
[n
];
1695 wxObjectList::compatibility_iterator node
;
1696 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1698 wxPoint
*point
= (wxPoint
*) node
->GetData();
1699 points
[i
].x
= point
->x
;
1700 points
[i
].y
= point
->y
;
1703 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1707 #endif // WXWIN_COMPATIBILITY_2_8
1710 wxDCBase::DoDrawPolyPolygon(int n
,
1713 wxCoord xoffset
, wxCoord yoffset
,
1718 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1726 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1731 pts
= new wxPoint
[j
+n
-1];
1732 for (i
= 0; i
< j
; i
++)
1734 for (i
= 2; i
<= n
; i
++)
1736 lastOfs
-= count
[n
-i
];
1737 pts
[j
++] = pts
[lastOfs
];
1741 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1742 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1744 for (i
= j
= 0; i
< n
; i
++)
1746 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1752 // ----------------------------------------------------------------------------
1754 // ----------------------------------------------------------------------------
1758 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1760 wxPointList point_list
;
1762 wxPoint
*point1
= new wxPoint
;
1763 point1
->x
= x1
; point1
->y
= y1
;
1764 point_list
.Append( point1
);
1766 wxPoint
*point2
= new wxPoint
;
1767 point2
->x
= x2
; point2
->y
= y2
;
1768 point_list
.Append( point2
);
1770 wxPoint
*point3
= new wxPoint
;
1771 point3
->x
= x3
; point3
->y
= y3
;
1772 point_list
.Append( point3
);
1774 DrawSpline(&point_list
);
1776 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
1778 wxPoint
*p
= node
->GetData();
1783 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
1786 for (int i
=0; i
< n
; i
++)
1787 list
.Append( &points
[i
] );
1792 // ----------------------------------- spline code ----------------------------------------
1794 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1795 double a3
, double b3
, double a4
, double b4
);
1796 void wx_clear_stack();
1797 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1798 double *y3
, double *x4
, double *y4
);
1799 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1800 double x4
, double y4
);
1801 static bool wx_spline_add_point(double x
, double y
);
1802 static void wx_spline_draw_point_array(wxDCBase
*dc
);
1804 wxPointList wx_spline_point_list
;
1806 #define half(z1, z2) ((z1+z2)/2.0)
1809 /* iterative version */
1811 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1814 register double xmid
, ymid
;
1815 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1818 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1820 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1821 xmid
= (double)half(x2
, x3
);
1822 ymid
= (double)half(y2
, y3
);
1823 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1824 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1825 wx_spline_add_point( x1
, y1
);
1826 wx_spline_add_point( xmid
, ymid
);
1828 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1829 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1830 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1831 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1836 /* utilities used by spline drawing routines */
1838 typedef struct wx_spline_stack_struct
{
1839 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1842 #define SPLINE_STACK_DEPTH 20
1843 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1844 static Stack
*wx_stack_top
;
1845 static int wx_stack_count
;
1847 void wx_clear_stack()
1849 wx_stack_top
= wx_spline_stack
;
1853 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1855 wx_stack_top
->x1
= x1
;
1856 wx_stack_top
->y1
= y1
;
1857 wx_stack_top
->x2
= x2
;
1858 wx_stack_top
->y2
= y2
;
1859 wx_stack_top
->x3
= x3
;
1860 wx_stack_top
->y3
= y3
;
1861 wx_stack_top
->x4
= x4
;
1862 wx_stack_top
->y4
= y4
;
1867 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1868 double *x3
, double *y3
, double *x4
, double *y4
)
1870 if (wx_stack_count
== 0)
1874 *x1
= wx_stack_top
->x1
;
1875 *y1
= wx_stack_top
->y1
;
1876 *x2
= wx_stack_top
->x2
;
1877 *y2
= wx_stack_top
->y2
;
1878 *x3
= wx_stack_top
->x3
;
1879 *y3
= wx_stack_top
->y3
;
1880 *x4
= wx_stack_top
->x4
;
1881 *y4
= wx_stack_top
->y4
;
1885 static bool wx_spline_add_point(double x
, double y
)
1887 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
1888 wx_spline_point_list
.Append( point
);
1892 static void wx_spline_draw_point_array(wxDCBase
*dc
)
1894 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1895 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1898 wxPoint
*point
= node
->GetData();
1900 wx_spline_point_list
.Erase(node
);
1901 node
= wx_spline_point_list
.GetFirst();
1905 #if WXWIN_COMPATIBILITY_2_8
1906 void wxDCBase::DrawSpline(const wxList
*points
)
1909 wxObjectList::compatibility_iterator node
= points
->GetFirst();
1912 list
.Append( (wxPoint
*) node
->GetData() );
1913 node
= node
->GetNext();
1915 DoDrawSpline( &list
);
1917 #endif // WXWIN_COMPATIBILITY_2_8
1919 void wxDCBase::DoDrawSpline( const wxPointList
*points
)
1921 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1924 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1925 double x1
, y1
, x2
, y2
;
1927 wxPointList::compatibility_iterator node
= points
->GetFirst();
1932 p
= node
->GetData();
1937 node
= node
->GetNext();
1938 p
= node
->GetData();
1942 cx1
= (double)((x1
+ x2
) / 2);
1943 cy1
= (double)((y1
+ y2
) / 2);
1944 cx2
= (double)((cx1
+ x2
) / 2);
1945 cy2
= (double)((cy1
+ y2
) / 2);
1947 wx_spline_add_point(x1
, y1
);
1949 while ((node
= node
->GetNext())
1952 #endif // !wxUSE_STL
1955 p
= node
->GetData();
1960 cx4
= (double)(x1
+ x2
) / 2;
1961 cy4
= (double)(y1
+ y2
) / 2;
1962 cx3
= (double)(x1
+ cx4
) / 2;
1963 cy3
= (double)(y1
+ cy4
) / 2;
1965 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1969 cx2
= (double)(cx1
+ x2
) / 2;
1970 cy2
= (double)(cy1
+ y2
) / 2;
1973 wx_spline_add_point( cx1
, cy1
);
1974 wx_spline_add_point( x2
, y2
);
1976 wx_spline_draw_point_array( this );
1979 #endif // wxUSE_SPLINES
1981 // ----------------------------------------------------------------------------
1982 // Partial Text Extents
1983 // ----------------------------------------------------------------------------
1986 // Each element of the widths array will be the width of the string up to and
1987 // including the corresponding character in text. This is the generic
1988 // implementation, the port-specific classes should do this with native APIs
1989 // if available and if faster. Note: pango_layout_index_to_pos is much slower
1990 // than calling GetTextExtent!!
1992 #define FWC_SIZE 256
1994 class FontWidthCache
1997 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
1998 ~FontWidthCache() { delete []m_widths
; }
2003 m_widths
= new int[FWC_SIZE
];
2005 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2013 static FontWidthCache s_fontWidthCache
;
2015 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2019 const size_t len
= text
.length();
2023 // reset the cache if font or horizontal scale have changed
2024 if ( !s_fontWidthCache
.m_widths
||
2025 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2026 (s_fontWidthCache
.m_font
!= GetFont()) )
2028 s_fontWidthCache
.Reset();
2029 s_fontWidthCache
.m_font
= GetFont();
2030 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2033 // Calculate the position of each character based on the widths of
2034 // the previous characters
2036 for ( size_t i
= 0; i
< len
; i
++ )
2038 const wxChar c
= text
[i
];
2039 unsigned int c_int
= (unsigned int)c
;
2041 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2043 w
= s_fontWidthCache
.m_widths
[c_int
];
2047 GetTextExtent(c
, &w
, &h
);
2048 if (c_int
< FWC_SIZE
)
2049 s_fontWidthCache
.m_widths
[c_int
] = w
;
2053 widths
[i
] = totalWidth
;
2060 // ----------------------------------------------------------------------------
2061 // enhanced text drawing
2062 // ----------------------------------------------------------------------------
2064 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2068 const wxFont
*font
) const
2070 wxCoord widthTextMax
= 0, widthLine
,
2071 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2074 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2076 if ( pc
== text
.end() || *pc
== _T('\n') )
2078 if ( curLine
.empty() )
2080 // we can't use GetTextExtent - it will return 0 for both width
2081 // and height and an empty line should count in height
2084 // assume that this line has the same height as the previous
2086 if ( !heightLineDefault
)
2087 heightLineDefault
= heightLine
;
2089 if ( !heightLineDefault
)
2091 // but we don't know it yet - choose something reasonable
2092 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2096 heightTextTotal
+= heightLineDefault
;
2100 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2102 if ( widthLine
> widthTextMax
)
2103 widthTextMax
= widthLine
;
2104 heightTextTotal
+= heightLine
;
2107 if ( pc
== text
.end() )
2125 *y
= heightTextTotal
;
2130 void wxDCBase::DrawLabel(const wxString
& text
,
2131 const wxBitmap
& bitmap
,
2135 wxRect
*rectBounding
)
2137 // find the text position
2138 wxCoord widthText
, heightText
, heightLine
;
2139 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2141 wxCoord width
, height
;
2144 width
= widthText
+ bitmap
.GetWidth();
2145 height
= bitmap
.GetHeight();
2150 height
= heightText
;
2154 if ( alignment
& wxALIGN_RIGHT
)
2156 x
= rect
.GetRight() - width
;
2158 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2160 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2162 else // alignment & wxALIGN_LEFT
2167 if ( alignment
& wxALIGN_BOTTOM
)
2169 y
= rect
.GetBottom() - height
;
2171 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2173 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2175 else // alignment & wxALIGN_TOP
2180 // draw the bitmap first
2186 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2188 wxCoord offset
= bitmap
.GetWidth() + 4;
2192 y
+= (height
- heightText
) / 2;
2195 // we will draw the underscore under the accel char later
2196 wxCoord startUnderscore
= 0,
2200 // split the string into lines and draw each of them separately
2202 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2204 if ( pc
== text
.end() || *pc
== _T('\n') )
2206 int xRealStart
= x
; // init it here to avoid compielr warnings
2208 if ( !curLine
.empty() )
2210 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2211 // wxALIGN_LEFT is 0
2212 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2215 GetTextExtent(curLine
, &widthLine
, NULL
);
2217 if ( alignment
& wxALIGN_RIGHT
)
2219 xRealStart
+= width
- widthLine
;
2221 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2223 xRealStart
+= (width
- widthLine
) / 2;
2226 //else: left aligned, nothing to do
2228 DrawText(curLine
, xRealStart
, y
);
2233 // do we have underscore in this line? we can check yUnderscore
2234 // because it is set below to just y + heightLine if we do
2235 if ( y
== yUnderscore
)
2237 // adjust the horz positions to account for the shift
2238 startUnderscore
+= xRealStart
;
2239 endUnderscore
+= xRealStart
;
2242 if ( pc
== text
.end() )
2247 else // not end of line
2249 if ( pc
- text
.begin() == indexAccel
)
2251 // remeber to draw underscore here
2252 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2254 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2256 yUnderscore
= y
+ heightLine
;
2265 // draw the underscore if found
2266 if ( startUnderscore
!= endUnderscore
)
2268 // it should be of the same colour as text
2269 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2273 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2276 // return bounding rect if requested
2279 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2282 CalcBoundingBox(x0
, y0
);
2283 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2287 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2288 const wxColour
& initialColour
,
2289 const wxColour
& destColour
,
2290 wxDirection nDirection
)
2293 wxPen oldPen
= m_pen
;
2294 wxBrush oldBrush
= m_brush
;
2296 wxUint8 nR1
= initialColour
.Red();
2297 wxUint8 nG1
= initialColour
.Green();
2298 wxUint8 nB1
= initialColour
.Blue();
2299 wxUint8 nR2
= destColour
.Red();
2300 wxUint8 nG2
= destColour
.Green();
2301 wxUint8 nB2
= destColour
.Blue();
2304 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2306 wxInt32 x
= rect
.GetWidth();
2307 wxInt32 w
= x
; // width of area to shade
2308 wxInt32 xDelta
= w
/256; // height of one shade bend
2316 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2318 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2321 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2323 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2326 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2328 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2330 wxColour
colour(nR
,nG
,nB
);
2331 SetPen(wxPen(colour
, 1, wxSOLID
));
2332 SetBrush(wxBrush(colour
));
2333 if(nDirection
== wxEAST
)
2334 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
2335 xDelta
, rect
.GetHeight());
2336 else //nDirection == wxWEST
2337 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2338 xDelta
, rect
.GetHeight());
2341 else // nDirection == wxNORTH || nDirection == wxSOUTH
2343 wxInt32 y
= rect
.GetHeight();
2344 wxInt32 w
= y
; // height of area to shade
2345 wxInt32 yDelta
= w
/255; // height of one shade bend
2353 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2355 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2358 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2360 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2363 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2365 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2367 wxColour
colour(nR
,nG
,nB
);
2368 SetPen(wxPen(colour
, 1, wxSOLID
));
2369 SetBrush(wxBrush(colour
));
2370 if(nDirection
== wxNORTH
)
2371 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2372 rect
.GetWidth(), yDelta
);
2373 else //nDirection == wxSOUTH
2374 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
2375 rect
.GetWidth(), yDelta
);
2383 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2384 const wxColour
& initialColour
,
2385 const wxColour
& destColour
,
2386 const wxPoint
& circleCenter
)
2388 //save the old pen color
2389 wxColour oldPenColour
= m_pen
.GetColour();
2391 wxUint8 nR1
= destColour
.Red();
2392 wxUint8 nG1
= destColour
.Green();
2393 wxUint8 nB1
= destColour
.Blue();
2394 wxUint8 nR2
= initialColour
.Red();
2395 wxUint8 nG2
= initialColour
.Green();
2396 wxUint8 nB2
= initialColour
.Blue();
2401 wxInt32 cx
= rect
.GetWidth() / 2;
2402 wxInt32 cy
= rect
.GetHeight() / 2;
2410 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2411 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2413 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2415 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2417 //get color difference
2418 wxInt32 nGradient
= ((nRadius
-
2420 pow((double)(x
- cx
- nCircleOffX
), 2) +
2421 pow((double)(y
- cy
- nCircleOffY
), 2)
2422 )) * 100) / nRadius
;
2424 //normalize Gradient
2429 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2430 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2431 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2434 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2435 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2438 //return old pen color
2439 m_pen
.SetColour(oldPenColour
);
2443 Notes for wxWidgets DrawEllipticArcRot(...)
2445 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2446 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2449 All methods are generic, so they can be implemented in wxDCBase.
2450 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2451 methods like (WinCE) wxDC::DoDrawArc(...).
2453 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2454 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2455 parts) or every column (in steep parts) only one pixel is calculated.
2456 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2457 starting angle is not equal to the ending angle. The calculation of the
2458 pixels is done using simple arithmetic only and should perform not too
2459 bad even on devices without floating point processor. I didn't test this yet.
2461 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2462 For instance: an ellipse rotated 180 degrees is drawn
2463 slightly different from the original.
2465 The points are then moved to an array and used to draw a polyline and/or polygon
2466 (with center added, the pie).
2467 The result looks quite similar to the native ellipse, only e few pixels differ.
2469 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2470 slower as DrawEllipse(...), which calls the native API.
2471 An rotated ellipse outside the clipping region takes nearly the same time,
2472 while an native ellipse outside takes nearly no time to draw.
2474 If you draw an arc with this new method, you will see the starting and ending angles
2475 are calculated properly.
2476 If you use DrawEllipticArc(...), you will see they are only correct for circles
2477 and not properly calculated for ellipses.
2480 p.lenhard@t-online.de
2484 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2485 wxCoord w
, wxCoord h
,
2486 double sa
, double ea
, double angle
)
2490 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2491 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2493 // Add center (for polygon/pie)
2494 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
2496 // copy list into array and delete list elements
2497 int n
= list
.GetCount();
2498 wxPoint
*points
= new wxPoint
[n
];
2500 wxPointList::compatibility_iterator node
;
2501 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2503 wxPoint
*point
= node
->GetData();
2504 points
[i
].x
= point
->x
;
2505 points
[i
].y
= point
->y
;
2509 // first draw the pie without pen, if necessary
2510 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2512 wxPen
tempPen( GetPen() );
2513 SetPen( *wxTRANSPARENT_PEN
);
2514 DoDrawPolygon( n
, points
, 0, 0 );
2518 // then draw the arc without brush, if necessary
2519 if( GetPen() != *wxTRANSPARENT_PEN
)
2522 DoDrawLines( n
-1, points
, 0, 0 );
2527 } // DrawEllipticArcRot
2529 void wxDCBase::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
2534 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2535 double dCosA
= cos(angle
*2.0*pi
/360.0);
2536 wxPointList::compatibility_iterator node
;
2537 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2539 wxPoint
* point
= node
->GetData();
2541 // transform coordinates, if necessary
2542 if( center
.x
) point
->x
-= center
.x
;
2543 if( center
.y
) point
->y
-= center
.y
;
2545 // calculate rotation, rounding simply by implicit cast to integer
2546 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2547 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2550 // back transform coordinates, if necessary
2551 if( center
.x
) point
->x
+= center
.x
;
2552 if( center
.y
) point
->y
+= center
.y
;
2557 void wxDCBase::CalculateEllipticPoints( wxPointList
* points
,
2558 wxCoord xStart
, wxCoord yStart
,
2559 wxCoord w
, wxCoord h
,
2560 double sa
, double ea
)
2571 bool bUseAngles
= false;
2577 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2579 if( 2*a
== w
) decrX
= 1;
2581 if( 2*b
== h
) decrY
= 1;
2583 wxCoord xCenter
= xStart
+ a
;
2584 wxCoord yCenter
= yStart
+ b
;
2585 // calculate data for start and end, if necessary
2589 // normalisation of angles
2590 while( sa
<0 ) sa
+= 360;
2591 while( ea
<0 ) ea
+= 360;
2592 while( sa
>=360 ) sa
-= 360;
2593 while( ea
>=360 ) ea
-= 360;
2594 // calculate quadrant numbers
2595 if( sa
> 270 ) sq
= 3;
2596 else if( sa
> 180 ) sq
= 2;
2597 else if( sa
> 90 ) sq
= 1;
2598 if( ea
> 270 ) eq
= 3;
2599 else if( ea
> 180 ) eq
= 2;
2600 else if( ea
> 90 ) eq
= 1;
2601 sar
= sa
* pi
/ 180.0;
2602 ear
= ea
* pi
/ 180.0;
2603 // correct angle circle -> ellipse
2604 sar
= atan( -a
/(double)b
* tan( sar
) );
2605 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2606 ear
= atan( -a
/(double)b
* tan( ear
) );
2607 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2608 // coordinates of points
2609 xsa
= xCenter
+ a
* cos( sar
);
2610 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2611 ysa
= yCenter
+ b
* sin( sar
);
2612 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2613 xea
= xCenter
+ a
* cos( ear
);
2614 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2615 yea
= yCenter
+ b
* sin( ear
);
2616 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2618 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2620 double c2
= 2.0 / w
;
2629 // Lists for quadrant 1 to 4
2630 wxPointList pointsarray
[4];
2631 // Calculate points for first quadrant and set in all quadrants
2632 for( x
= 0; x
<= a
; ++x
)
2637 bool bNewPoint
= false;
2638 while( y2
> c1
- c2
* x2
&& y
> 0 )
2644 // old y now to big: set point with old y, old x
2645 if( bNewPoint
&& x
>1)
2648 // remove points on the same line
2649 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2650 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2651 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2652 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2654 } // calculate point
2656 // Starting and/or ending points for the quadrants, first quadrant gets both.
2657 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2658 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
2659 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
2660 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2661 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2663 // copy quadrants in original list
2666 // Copy the right part of the points in the lists
2667 // and delete the wxPoints, because they do not leave this method.
2668 points
->Append( new wxPoint( xsa
, ysa
) );
2670 bool bStarted
= false;
2671 bool bReady
= false;
2672 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2675 wxPointList::compatibility_iterator node
;
2676 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2678 // once: go to starting point in start quadrant
2681 node
->GetData()->x
< xsa
+1 && q
<= 1
2683 node
->GetData()->x
> xsa
-1 && q
>= 2
2690 // copy point, if not at ending point
2693 if( q
!= eq
|| bForceTurn
2695 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2697 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2701 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
2702 points
->Append( pPoint
);
2704 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
2714 } // while not bReady
2715 points
->Append( new wxPoint( xea
, yea
) );
2718 for( q
= 0; q
< 4; ++q
)
2720 wxPointList::compatibility_iterator node
;
2721 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2723 wxPoint
*p
= node
->GetData();
2730 wxPointList::compatibility_iterator node
;
2731 // copy whole ellipse, wxPoints will be deleted outside
2732 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2734 wxPoint
*p
= node
->GetData();
2735 points
->Append( p
);
2737 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2739 wxPoint
*p
= node
->GetData();
2740 points
->Append( p
);
2742 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2744 wxPoint
*p
= node
->GetData();
2745 points
->Append( p
);
2747 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2749 wxPoint
*p
= node
->GetData();
2750 points
->Append( p
);
2753 } // CalculateEllipticPoints
2755 #endif // __WXWINCE__
2757 #endif // wxUSE_NEW_DC