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"
60 #include "wx/x11/dcclient.h"
61 #include "wx/x11/dcmemory.h"
62 #include "wx/x11/dcscreen.h"
65 //----------------------------------------------------------------------------
67 //----------------------------------------------------------------------------
69 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
71 void wxDCFactory::SetDCFactory( wxDCFactory
*factory
)
73 if (wxDCFactory::m_factory
)
74 delete wxDCFactory::m_factory
;
76 wxDCFactory::m_factory
= factory
;
79 wxDCFactory
*wxDCFactory::GetFactory()
81 if (!wxDCFactory::m_factory
)
82 wxDCFactory::m_factory
= new wxNativeDCFactory
;
84 return wxDCFactory::m_factory
;
87 //-----------------------------------------------------------------------------
89 //-----------------------------------------------------------------------------
91 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
)
93 return new wxWindowDCImpl( owner
);
96 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
98 return new wxWindowDCImpl( owner
, window
);
101 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
)
103 return new wxClientDCImpl( owner
);
106 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
108 return new wxClientDCImpl( owner
, window
);
111 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
)
113 return new wxPaintDCImpl( owner
);
116 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
118 return new wxPaintDCImpl( owner
, window
);
121 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
123 return new wxMemoryDCImpl( owner
);
126 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxBitmap
&bitmap
)
128 return new wxMemoryDCImpl( owner
, bitmap
);
131 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
133 return new wxMemoryDCImpl( owner
, dc
);
136 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
138 return new wxScreenDCImpl( owner
);
141 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
143 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
144 return factory
->CreatePrinterDCImpl( owner
, data
);
147 //-----------------------------------------------------------------------------
149 //-----------------------------------------------------------------------------
151 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
153 wxWindowDC::wxWindowDC()
157 wxWindowDC::wxWindowDC( wxWindow
*win
)
159 wxDCFactory
*factory
= wxDCFactory::GetFactory();
160 m_pimpl
= factory
->CreateWindowDC( this, win
);
163 //-----------------------------------------------------------------------------
165 //-----------------------------------------------------------------------------
167 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxWindowDC
)
169 wxClientDC::wxClientDC()
173 wxClientDC::wxClientDC( wxWindow
*win
)
175 wxDCFactory
*factory
= wxDCFactory::GetFactory();
176 m_pimpl
= factory
->CreateClientDC( this, win
);
179 //-----------------------------------------------------------------------------
181 //-----------------------------------------------------------------------------
183 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
185 wxMemoryDC::wxMemoryDC()
187 wxDCFactory
*factory
= wxDCFactory::GetFactory();
188 m_pimpl
= factory
->CreateMemoryDC( this );
191 wxMemoryDC::wxMemoryDC( wxBitmap
& bitmap
)
193 wxDCFactory
*factory
= wxDCFactory::GetFactory();
194 m_pimpl
= factory
->CreateMemoryDC( this, bitmap
);
197 wxMemoryDC::wxMemoryDC( wxDC
*dc
)
199 wxDCFactory
*factory
= wxDCFactory::GetFactory();
200 m_pimpl
= factory
->CreateMemoryDC( this, dc
);
203 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
205 // make sure that the given wxBitmap is not sharing its data with other
206 // wxBitmap instances as its contents will be modified by any drawing
207 // operation done on this DC
211 GetImpl()->DoSelect(bmp
);
214 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
216 GetImpl()->DoSelect(bmp
);
219 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
221 return GetImpl()->GetSelectedBitmap();
224 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
226 return GetImpl()->GetSelectedBitmap();
230 //-----------------------------------------------------------------------------
232 //-----------------------------------------------------------------------------
234 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxClientDC
)
236 wxPaintDC::wxPaintDC()
240 wxPaintDC::wxPaintDC( wxWindow
*win
)
242 wxDCFactory
*factory
= wxDCFactory::GetFactory();
243 m_pimpl
= factory
->CreatePaintDC( this, win
);
246 //-----------------------------------------------------------------------------
248 //-----------------------------------------------------------------------------
250 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
252 wxScreenDC::wxScreenDC()
254 wxDCFactory
*factory
= wxDCFactory::GetFactory();
255 m_pimpl
= factory
->CreateScreenDC( this );
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
262 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
264 wxPrinterDC::wxPrinterDC()
266 wxPrintData data
; // Does this make sense?
267 wxDCFactory
*factory
= wxDCFactory::GetFactory();
268 m_pimpl
= factory
->CreatePrinterDC( this, data
);
271 wxPrinterDC::wxPrinterDC( const wxPrintData
&data
)
273 wxDCFactory
*factory
= wxDCFactory::GetFactory();
274 m_pimpl
= factory
->CreatePrinterDC( this, data
);
277 wxPrinterDC::~wxPrinterDC()
281 wxRect
wxPrinterDC::GetPaperRect()
283 return GetImpl()->GetPaperRect();
286 int wxPrinterDC::GetResolution()
288 return GetImpl()->GetResolution();
292 //-----------------------------------------------------------------------------
294 //-----------------------------------------------------------------------------
296 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
298 wxDCImpl::wxDCImpl( wxDC
*owner
)
300 , m_colour(wxColourDisplay())
304 , m_isBBoxValid(false)
305 , m_logicalOriginX(0), m_logicalOriginY(0)
306 , m_deviceOriginX(0), m_deviceOriginY(0)
307 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
308 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
309 , m_userScaleX(1.0), m_userScaleY(1.0)
310 , m_scaleX(1.0), m_scaleY(1.0)
311 , m_signX(1), m_signY(1)
312 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
313 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
314 , m_logicalFunction(wxCOPY
)
315 , m_backgroundMode(wxTRANSPARENT
)
316 , m_mappingMode(wxMM_TEXT
)
319 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
320 , m_textForegroundColour(*wxBLACK
)
321 , m_textBackgroundColour(*wxWHITE
)
325 , m_hasCustomPalette(false)
326 #endif // wxUSE_PALETTE
330 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
331 (double)wxGetDisplaySizeMM().GetWidth();
332 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
333 (double)wxGetDisplaySizeMM().GetHeight();
339 wxDCImpl::~wxDCImpl()
343 // ----------------------------------------------------------------------------
344 // coordinate conversions and transforms
345 // ----------------------------------------------------------------------------
347 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
349 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
352 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
354 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
357 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
359 return wxRound((double)(x
) / m_scaleX
);
362 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
364 return wxRound((double)(y
) / m_scaleY
);
367 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
369 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
372 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
374 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ m_deviceLocalOriginY
;
377 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
379 return wxRound((double)(x
) * m_scaleX
);
382 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
384 return wxRound((double)(y
) * m_scaleY
);
387 void wxDCImpl::ComputeScaleAndOrigin()
389 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
390 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
393 void wxDCImpl::SetMapMode( int mode
)
398 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
401 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
404 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
407 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
411 SetLogicalScale( 1.0, 1.0 );
414 m_mappingMode
= mode
;
417 void wxDCImpl::SetUserScale( double x
, double y
)
419 // allow negative ? -> no
422 ComputeScaleAndOrigin();
425 void wxDCImpl::SetLogicalScale( double x
, double y
)
430 ComputeScaleAndOrigin();
433 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
435 m_logicalOriginX
= x
* m_signX
;
436 m_logicalOriginY
= y
* m_signY
;
437 ComputeScaleAndOrigin();
440 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
444 ComputeScaleAndOrigin();
447 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
449 m_deviceLocalOriginX
= x
;
450 m_deviceLocalOriginY
= y
;
451 ComputeScaleAndOrigin();
454 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
456 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
457 // wxWidgets 2.9: no longer override it
458 m_signX
= (xLeftRight
? 1 : -1);
459 m_signY
= (yBottomUp
? -1 : 1);
460 ComputeScaleAndOrigin();
464 // Each element of the widths array will be the width of the string up to and
465 // including the corresponding character in text. This is the generic
466 // implementation, the port-specific classes should do this with native APIs
467 // if available and if faster. Note: pango_layout_index_to_pos is much slower
468 // than calling GetTextExtent!!
475 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
476 ~FontWidthCache() { delete []m_widths
; }
481 m_widths
= new int[FWC_SIZE
];
483 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
491 static FontWidthCache s_fontWidthCache
;
493 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
497 const size_t len
= text
.length();
501 // reset the cache if font or horizontal scale have changed
502 if ( !s_fontWidthCache
.m_widths
||
503 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
504 (s_fontWidthCache
.m_font
!= GetFont()) )
506 s_fontWidthCache
.Reset();
507 s_fontWidthCache
.m_font
= GetFont();
508 s_fontWidthCache
.m_scaleX
= m_scaleX
;
511 // Calculate the position of each character based on the widths of
512 // the previous characters
514 for ( size_t i
= 0; i
< len
; i
++ )
516 const wxChar c
= text
[i
];
517 unsigned int c_int
= (unsigned int)c
;
519 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
521 w
= s_fontWidthCache
.m_widths
[c_int
];
525 DoGetTextExtent(c
, &w
, &h
);
526 if (c_int
< FWC_SIZE
)
527 s_fontWidthCache
.m_widths
[c_int
] = w
;
531 widths
[i
] = totalWidth
;
537 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
541 const wxFont
*font
) const
543 wxCoord widthTextMax
= 0, widthLine
,
544 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
547 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
549 if ( pc
== text
.end() || *pc
== _T('\n') )
551 if ( curLine
.empty() )
553 // we can't use GetTextExtent - it will return 0 for both width
554 // and height and an empty line should count in height
557 // assume that this line has the same height as the previous
559 if ( !heightLineDefault
)
560 heightLineDefault
= heightLine
;
562 if ( !heightLineDefault
)
564 // but we don't know it yet - choose something reasonable
565 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
569 heightTextTotal
+= heightLineDefault
;
573 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
575 if ( widthLine
> widthTextMax
)
576 widthTextMax
= widthLine
;
577 heightTextTotal
+= heightLine
;
580 if ( pc
== text
.end() )
598 *y
= heightTextTotal
;
603 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
604 wxCoord width
, wxCoord height
)
606 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
608 wxCoord x2
= x1
+ width
,
611 // the pen width is calibrated to give 3 for width == height == 10
612 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
614 // we're drawing a scaled version of wx/generic/tick.xpm here
615 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
616 y3
= y1
+ height
/ 2; // y of the left tick branch
617 DoDrawLine(x1
, y3
, x3
, y2
);
618 DoDrawLine(x3
, y2
, x2
, y1
);
620 CalcBoundingBox(x1
, y1
);
621 CalcBoundingBox(x2
, y2
);
625 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
626 wxCoord dstWidth
, wxCoord dstHeight
,
628 wxCoord xsrc
, wxCoord ysrc
,
629 wxCoord srcWidth
, wxCoord srcHeight
,
635 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
636 _T("invalid blit size") );
638 // emulate the stretching by modifying the DC scale
639 double xscale
= (double)srcWidth
/dstWidth
,
640 yscale
= (double)srcHeight
/dstHeight
;
642 double xscaleOld
, yscaleOld
;
643 GetUserScale(&xscaleOld
, &yscaleOld
);
644 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
646 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
647 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
649 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
651 SetUserScale(xscaleOld
, yscaleOld
);
656 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
658 int n
= list
->GetCount();
659 wxPoint
*points
= new wxPoint
[n
];
662 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
664 wxPoint
*point
= node
->GetData();
665 points
[i
].x
= point
->x
;
666 points
[i
].y
= point
->y
;
669 DoDrawLines(n
, points
, xoffset
, yoffset
);
674 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
675 wxCoord xoffset
, wxCoord yoffset
,
678 int n
= list
->GetCount();
679 wxPoint
*points
= new wxPoint
[n
];
682 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
684 wxPoint
*point
= node
->GetData();
685 points
[i
].x
= point
->x
;
686 points
[i
].y
= point
->y
;
689 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
695 wxDCImpl::DoDrawPolyPolygon(int n
,
698 wxCoord xoffset
, wxCoord yoffset
,
703 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
711 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
716 pts
= new wxPoint
[j
+n
-1];
717 for (i
= 0; i
< j
; i
++)
719 for (i
= 2; i
<= n
; i
++)
721 lastOfs
-= count
[n
-i
];
722 pts
[j
++] = pts
[lastOfs
];
726 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
727 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
729 for (i
= j
= 0; i
< n
; i
++)
731 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
739 void wxDCImpl::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
741 wxPointList point_list
;
743 wxPoint
*point1
= new wxPoint
;
744 point1
->x
= x1
; point1
->y
= y1
;
745 point_list
.Append( point1
);
747 wxPoint
*point2
= new wxPoint
;
748 point2
->x
= x2
; point2
->y
= y2
;
749 point_list
.Append( point2
);
751 wxPoint
*point3
= new wxPoint
;
752 point3
->x
= x3
; point3
->y
= y3
;
753 point_list
.Append( point3
);
755 DoDrawSpline(&point_list
);
757 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
759 wxPoint
*p
= node
->GetData();
764 void wxDCImpl::DoDrawSpline(int n
, wxPoint points
[])
767 for (int i
=0; i
< n
; i
++)
768 list
.Append( &points
[i
] );
773 // ----------------------------------- spline code ----------------------------------------
775 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
776 double a3
, double b3
, double a4
, double b4
);
777 void wx_clear_stack();
778 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
779 double *y3
, double *x4
, double *y4
);
780 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
781 double x4
, double y4
);
782 static bool wx_spline_add_point(double x
, double y
);
783 static void wx_spline_draw_point_array(wxDC
*dc
);
785 wxPointList wx_spline_point_list
;
787 #define half(z1, z2) ((z1+z2)/2.0)
790 /* iterative version */
792 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
795 register double xmid
, ymid
;
796 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
799 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
801 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
802 xmid
= (double)half(x2
, x3
);
803 ymid
= (double)half(y2
, y3
);
804 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
805 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
806 wx_spline_add_point( x1
, y1
);
807 wx_spline_add_point( xmid
, ymid
);
809 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
810 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
811 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
812 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
817 /* utilities used by spline drawing routines */
819 typedef struct wx_spline_stack_struct
{
820 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
823 #define SPLINE_STACK_DEPTH 20
824 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
825 static Stack
*wx_stack_top
;
826 static int wx_stack_count
;
828 void wx_clear_stack()
830 wx_stack_top
= wx_spline_stack
;
834 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
836 wx_stack_top
->x1
= x1
;
837 wx_stack_top
->y1
= y1
;
838 wx_stack_top
->x2
= x2
;
839 wx_stack_top
->y2
= y2
;
840 wx_stack_top
->x3
= x3
;
841 wx_stack_top
->y3
= y3
;
842 wx_stack_top
->x4
= x4
;
843 wx_stack_top
->y4
= y4
;
848 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
849 double *x3
, double *y3
, double *x4
, double *y4
)
851 if (wx_stack_count
== 0)
855 *x1
= wx_stack_top
->x1
;
856 *y1
= wx_stack_top
->y1
;
857 *x2
= wx_stack_top
->x2
;
858 *y2
= wx_stack_top
->y2
;
859 *x3
= wx_stack_top
->x3
;
860 *y3
= wx_stack_top
->y3
;
861 *x4
= wx_stack_top
->x4
;
862 *y4
= wx_stack_top
->y4
;
866 static bool wx_spline_add_point(double x
, double y
)
868 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
869 wx_spline_point_list
.Append(point
);
873 static void wx_spline_draw_point_array(wxDC
*dc
)
875 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
876 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
879 wxPoint
*point
= node
->GetData();
881 wx_spline_point_list
.Erase(node
);
882 node
= wx_spline_point_list
.GetFirst();
886 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
888 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
891 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
892 double x1
, y1
, x2
, y2
;
894 wxPointList::compatibility_iterator node
= points
->GetFirst();
899 p
= (wxPoint
*)node
->GetData();
904 node
= node
->GetNext();
909 cx1
= (double)((x1
+ x2
) / 2);
910 cy1
= (double)((y1
+ y2
) / 2);
911 cx2
= (double)((cx1
+ x2
) / 2);
912 cy2
= (double)((cy1
+ y2
) / 2);
914 wx_spline_add_point(x1
, y1
);
916 while ((node
= node
->GetNext())
927 cx4
= (double)(x1
+ x2
) / 2;
928 cy4
= (double)(y1
+ y2
) / 2;
929 cx3
= (double)(x1
+ cx4
) / 2;
930 cy3
= (double)(y1
+ cy4
) / 2;
932 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
936 cx2
= (double)(cx1
+ x2
) / 2;
937 cy2
= (double)(cy1
+ y2
) / 2;
940 wx_spline_add_point( cx1
, cy1
);
941 wx_spline_add_point( x2
, y2
);
943 wx_spline_draw_point_array( m_owner
);
946 #endif // wxUSE_SPLINES
950 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
951 const wxColour
& initialColour
,
952 const wxColour
& destColour
,
953 wxDirection nDirection
)
956 wxPen oldPen
= m_pen
;
957 wxBrush oldBrush
= m_brush
;
959 wxUint8 nR1
= initialColour
.Red();
960 wxUint8 nG1
= initialColour
.Green();
961 wxUint8 nB1
= initialColour
.Blue();
962 wxUint8 nR2
= destColour
.Red();
963 wxUint8 nG2
= destColour
.Green();
964 wxUint8 nB2
= destColour
.Blue();
967 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
969 wxInt32 x
= rect
.GetWidth();
970 wxInt32 w
= x
; // width of area to shade
971 wxInt32 xDelta
= w
/256; // height of one shade bend
979 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
981 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
984 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
986 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
989 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
991 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
993 wxColour
colour(nR
,nG
,nB
);
994 SetPen(wxPen(colour
, 1, wxSOLID
));
995 SetBrush(wxBrush(colour
));
996 if(nDirection
== wxEAST
)
997 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
998 xDelta
, rect
.GetHeight());
999 else //nDirection == wxWEST
1000 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1001 xDelta
, rect
.GetHeight());
1004 else // nDirection == wxNORTH || nDirection == wxSOUTH
1006 wxInt32 y
= rect
.GetHeight();
1007 wxInt32 w
= y
; // height of area to shade
1008 wxInt32 yDelta
= w
/255; // height of one shade bend
1016 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1018 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1021 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1023 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1026 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1028 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1030 wxColour
colour(nR
,nG
,nB
);
1031 SetPen(wxPen(colour
, 1, wxSOLID
));
1032 SetBrush(wxBrush(colour
));
1033 if(nDirection
== wxNORTH
)
1034 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1035 rect
.GetWidth(), yDelta
);
1036 else //nDirection == wxSOUTH
1037 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1038 rect
.GetWidth(), yDelta
);
1046 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1047 const wxColour
& initialColour
,
1048 const wxColour
& destColour
,
1049 const wxPoint
& circleCenter
)
1051 //save the old pen color
1052 wxColour oldPenColour
= m_pen
.GetColour();
1054 wxUint8 nR1
= destColour
.Red();
1055 wxUint8 nG1
= destColour
.Green();
1056 wxUint8 nB1
= destColour
.Blue();
1057 wxUint8 nR2
= initialColour
.Red();
1058 wxUint8 nG2
= initialColour
.Green();
1059 wxUint8 nB2
= initialColour
.Blue();
1064 wxInt32 cx
= rect
.GetWidth() / 2;
1065 wxInt32 cy
= rect
.GetHeight() / 2;
1073 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1074 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1076 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1078 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1080 //get color difference
1081 wxInt32 nGradient
= ((nRadius
-
1083 pow((double)(x
- cx
- nCircleOffX
), 2) +
1084 pow((double)(y
- cy
- nCircleOffY
), 2)
1085 )) * 100) / nRadius
;
1087 //normalize Gradient
1092 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1093 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1094 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1097 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1098 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1101 //return old pen color
1102 m_pen
.SetColour(oldPenColour
);
1105 //-----------------------------------------------------------------------------
1107 //-----------------------------------------------------------------------------
1109 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1111 void wxDC::DrawLabel(const wxString
& text
,
1112 const wxBitmap
& bitmap
,
1116 wxRect
*rectBounding
)
1118 // find the text position
1119 wxCoord widthText
, heightText
, heightLine
;
1120 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1122 wxCoord width
, height
;
1125 width
= widthText
+ bitmap
.GetWidth();
1126 height
= bitmap
.GetHeight();
1131 height
= heightText
;
1135 if ( alignment
& wxALIGN_RIGHT
)
1137 x
= rect
.GetRight() - width
;
1139 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1141 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1143 else // alignment & wxALIGN_LEFT
1148 if ( alignment
& wxALIGN_BOTTOM
)
1150 y
= rect
.GetBottom() - height
;
1152 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1154 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1156 else // alignment & wxALIGN_TOP
1161 // draw the bitmap first
1167 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1169 wxCoord offset
= bitmap
.GetWidth() + 4;
1173 y
+= (height
- heightText
) / 2;
1176 // we will draw the underscore under the accel char later
1177 wxCoord startUnderscore
= 0,
1181 // split the string into lines and draw each of them separately
1183 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1185 if ( *pc
== _T('\n') || pc
== text
.end() )
1187 int xRealStart
= x
; // init it here to avoid compielr warnings
1189 if ( !curLine
.empty() )
1191 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1192 // wxALIGN_LEFT is 0
1193 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1196 GetTextExtent(curLine
, &widthLine
, NULL
);
1198 if ( alignment
& wxALIGN_RIGHT
)
1200 xRealStart
+= width
- widthLine
;
1202 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1204 xRealStart
+= (width
- widthLine
) / 2;
1207 //else: left aligned, nothing to do
1209 DrawText(curLine
, xRealStart
, y
);
1214 // do we have underscore in this line? we can check yUnderscore
1215 // because it is set below to just y + heightLine if we do
1216 if ( y
== yUnderscore
)
1218 // adjust the horz positions to account for the shift
1219 startUnderscore
+= xRealStart
;
1220 endUnderscore
+= xRealStart
;
1223 if ( pc
== text
.end() )
1228 else // not end of line
1230 if ( pc
- text
.begin() == indexAccel
)
1232 // remeber to draw underscore here
1233 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1235 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1237 yUnderscore
= y
+ heightLine
;
1246 // draw the underscore if found
1247 if ( startUnderscore
!= endUnderscore
)
1249 // it should be of the same colour as text
1250 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1254 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1257 // return bounding rect if requested
1260 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1263 CalcBoundingBox(x0
, y0
);
1264 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1267 #if WXWIN_COMPATIBILITY_2_8
1268 // for compatibility with the old code when wxCoord was long everywhere
1269 void wxDC::GetTextExtent(const wxString
& string
,
1272 long *externalLeading
,
1273 const wxFont
*theFont
) const
1275 wxCoord x2
, y2
, descent2
, externalLeading2
;
1276 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1277 &descent2
, &externalLeading2
,
1284 *descent
= descent2
;
1285 if ( externalLeading
)
1286 *externalLeading
= externalLeading2
;
1289 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1292 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1299 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1302 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1309 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1311 wxCoord xx
,yy
,ww
,hh
;
1312 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1319 #endif // WXWIN_COMPATIBILITY_2_8
1322 #else // wxUSE_NEW_DC
1325 // bool wxDCBase::sm_cacheing = false;
1327 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1329 // ============================================================================
1331 // ============================================================================
1333 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1334 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1336 wxDCBase::wxDCBase()
1337 : m_colour(wxColourDisplay())
1340 , m_isInteractive(0)
1341 , m_isBBoxValid(false)
1342 , m_logicalOriginX(0), m_logicalOriginY(0)
1343 , m_deviceOriginX(0), m_deviceOriginY(0)
1344 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1345 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1346 , m_userScaleX(1.0), m_userScaleY(1.0)
1347 , m_scaleX(1.0), m_scaleY(1.0)
1348 , m_signX(1), m_signY(1)
1349 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1350 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1351 , m_logicalFunction(wxCOPY
)
1352 , m_backgroundMode(wxTRANSPARENT
)
1353 , m_mappingMode(wxMM_TEXT
)
1356 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1357 , m_textForegroundColour(*wxBLACK
)
1358 , m_textBackgroundColour(*wxWHITE
)
1362 , m_hasCustomPalette(false)
1363 #endif // wxUSE_PALETTE
1365 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1366 (double)wxGetDisplaySizeMM().GetWidth();
1367 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1368 (double)wxGetDisplaySizeMM().GetHeight();
1374 wxDCBase::~wxDCBase()
1378 #if WXWIN_COMPATIBILITY_2_6
1379 void wxDCBase::BeginDrawing()
1383 void wxDCBase::EndDrawing()
1386 #endif // WXWIN_COMPATIBILITY_2_6
1388 #if WXWIN_COMPATIBILITY_2_8
1389 // for compatibility with the old code when wxCoord was long everywhere
1390 void wxDCBase::GetTextExtent(const wxString
& string
,
1393 long *externalLeading
,
1394 const wxFont
*theFont
) const
1396 wxCoord x2
, y2
, descent2
, externalLeading2
;
1397 DoGetTextExtent(string
, &x2
, &y2
,
1398 &descent2
, &externalLeading2
,
1405 *descent
= descent2
;
1406 if ( externalLeading
)
1407 *externalLeading
= externalLeading2
;
1410 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1413 DoGetLogicalOrigin(&x2
, &y2
);
1420 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1423 DoGetDeviceOrigin(&x2
, &y2
);
1430 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1432 wxCoord xx
,yy
,ww
,hh
;
1433 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1439 #endif // WXWIN_COMPATIBILITY_2_8
1443 // ----------------------------------------------------------------------------
1444 // coordinate conversions and transforms
1445 // ----------------------------------------------------------------------------
1447 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1449 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1452 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1454 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1457 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1459 return wxRound((double)(x
) / m_scaleX
);
1462 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1464 return wxRound((double)(y
) / m_scaleY
);
1467 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1469 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1472 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1474 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1477 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1479 return wxRound((double)(x
) * m_scaleX
);
1482 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1484 return wxRound((double)(y
) * m_scaleY
);
1487 void wxDCBase::ComputeScaleAndOrigin()
1489 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1490 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1493 void wxDCBase::SetMapMode( int mode
)
1498 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1501 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1504 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1507 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1511 SetLogicalScale( 1.0, 1.0 );
1514 m_mappingMode
= mode
;
1517 void wxDCBase::SetUserScale( double x
, double y
)
1519 // allow negative ? -> no
1522 ComputeScaleAndOrigin();
1525 void wxDCBase::SetLogicalScale( double x
, double y
)
1528 m_logicalScaleX
= x
;
1529 m_logicalScaleY
= y
;
1530 ComputeScaleAndOrigin();
1533 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1535 m_logicalOriginX
= x
* m_signX
;
1536 m_logicalOriginY
= y
* m_signY
;
1537 ComputeScaleAndOrigin();
1540 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1542 m_deviceOriginX
= x
;
1543 m_deviceOriginY
= y
;
1544 ComputeScaleAndOrigin();
1547 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1549 m_deviceLocalOriginX
= x
;
1550 m_deviceLocalOriginY
= y
;
1551 ComputeScaleAndOrigin();
1554 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1556 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1557 // wxWidgets 2.9: no longer override it
1558 m_signX
= (xLeftRight
? 1 : -1);
1559 m_signY
= (yBottomUp
? -1 : 1);
1560 ComputeScaleAndOrigin();
1563 // ----------------------------------------------------------------------------
1565 // ----------------------------------------------------------------------------
1567 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1568 wxCoord width
, wxCoord height
)
1570 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1572 wxCoord x2
= x1
+ width
,
1575 // the pen width is calibrated to give 3 for width == height == 10
1576 wxDCPenChanger
pen((wxDC
&)*this,
1577 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1579 // we're drawing a scaled version of wx/generic/tick.xpm here
1580 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1581 y3
= y1
+ height
/ 2; // y of the left tick branch
1582 DoDrawLine(x1
, y3
, x3
, y2
);
1583 DoDrawLine(x3
, y2
, x2
, y1
);
1585 CalcBoundingBox(x1
, y1
);
1586 CalcBoundingBox(x2
, y2
);
1589 // ----------------------------------------------------------------------------
1590 // stubs for functions not implemented in all ports
1591 // ----------------------------------------------------------------------------
1594 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1595 wxCoord dstWidth
, wxCoord dstHeight
,
1597 wxCoord xsrc
, wxCoord ysrc
,
1598 wxCoord srcWidth
, wxCoord srcHeight
,
1604 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1605 _T("invalid blit size") );
1607 // emulate the stretching by modifying the DC scale
1608 double xscale
= (double)srcWidth
/dstWidth
,
1609 yscale
= (double)srcHeight
/dstHeight
;
1611 double xscaleOld
, yscaleOld
;
1612 GetUserScale(&xscaleOld
, &yscaleOld
);
1613 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1615 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1616 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1618 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1620 SetUserScale(xscaleOld
, yscaleOld
);
1625 // ----------------------------------------------------------------------------
1627 // ----------------------------------------------------------------------------
1629 void wxDCBase::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1631 unsigned int n
= list
->GetCount();
1632 wxPoint
*points
= new wxPoint
[n
];
1635 wxPointList::compatibility_iterator node
;
1636 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1638 wxPoint
*point
= node
->GetData();
1639 points
[i
].x
= point
->x
;
1640 points
[i
].y
= point
->y
;
1643 DoDrawLines(n
, points
, xoffset
, yoffset
);
1648 #if WXWIN_COMPATIBILITY_2_8
1649 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1651 unsigned int n
= list
->GetCount();
1652 wxPoint
*points
= new wxPoint
[n
];
1655 wxObjectList::compatibility_iterator node
;
1656 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1658 wxPoint
*point
= (wxPoint
*) node
->GetData();
1659 points
[i
].x
= point
->x
;
1660 points
[i
].y
= point
->y
;
1663 DoDrawLines(n
, points
, xoffset
, yoffset
);
1667 #endif // WXWIN_COMPATIBILITY_2_8
1670 void wxDCBase::DrawPolygon(const wxPointList
*list
,
1671 wxCoord xoffset
, wxCoord yoffset
,
1674 unsigned int n
= list
->GetCount();
1675 wxPoint
*points
= new wxPoint
[n
];
1678 wxPointList::compatibility_iterator node
;
1679 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1681 wxPoint
*point
= node
->GetData();
1682 points
[i
].x
= point
->x
;
1683 points
[i
].y
= point
->y
;
1686 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1692 #if WXWIN_COMPATIBILITY_2_8
1693 void wxDCBase::DrawPolygon(const wxList
*list
,
1694 wxCoord xoffset
, wxCoord yoffset
,
1697 unsigned int n
= list
->GetCount();
1698 wxPoint
*points
= new wxPoint
[n
];
1701 wxObjectList::compatibility_iterator node
;
1702 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1704 wxPoint
*point
= (wxPoint
*) node
->GetData();
1705 points
[i
].x
= point
->x
;
1706 points
[i
].y
= point
->y
;
1709 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1713 #endif // WXWIN_COMPATIBILITY_2_8
1716 wxDCBase::DoDrawPolyPolygon(int n
,
1719 wxCoord xoffset
, wxCoord yoffset
,
1724 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1732 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1737 pts
= new wxPoint
[j
+n
-1];
1738 for (i
= 0; i
< j
; i
++)
1740 for (i
= 2; i
<= n
; i
++)
1742 lastOfs
-= count
[n
-i
];
1743 pts
[j
++] = pts
[lastOfs
];
1747 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1748 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1750 for (i
= j
= 0; i
< n
; i
++)
1752 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1758 // ----------------------------------------------------------------------------
1760 // ----------------------------------------------------------------------------
1764 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1766 wxPointList point_list
;
1768 wxPoint
*point1
= new wxPoint
;
1769 point1
->x
= x1
; point1
->y
= y1
;
1770 point_list
.Append( point1
);
1772 wxPoint
*point2
= new wxPoint
;
1773 point2
->x
= x2
; point2
->y
= y2
;
1774 point_list
.Append( point2
);
1776 wxPoint
*point3
= new wxPoint
;
1777 point3
->x
= x3
; point3
->y
= y3
;
1778 point_list
.Append( point3
);
1780 DrawSpline(&point_list
);
1782 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
1784 wxPoint
*p
= node
->GetData();
1789 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
1792 for (int i
=0; i
< n
; i
++)
1793 list
.Append( &points
[i
] );
1798 // ----------------------------------- spline code ----------------------------------------
1800 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1801 double a3
, double b3
, double a4
, double b4
);
1802 void wx_clear_stack();
1803 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1804 double *y3
, double *x4
, double *y4
);
1805 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1806 double x4
, double y4
);
1807 static bool wx_spline_add_point(double x
, double y
);
1808 static void wx_spline_draw_point_array(wxDCBase
*dc
);
1810 wxPointList wx_spline_point_list
;
1812 #define half(z1, z2) ((z1+z2)/2.0)
1815 /* iterative version */
1817 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1820 register double xmid
, ymid
;
1821 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1824 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1826 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1827 xmid
= (double)half(x2
, x3
);
1828 ymid
= (double)half(y2
, y3
);
1829 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1830 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1831 wx_spline_add_point( x1
, y1
);
1832 wx_spline_add_point( xmid
, ymid
);
1834 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1835 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1836 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1837 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1842 /* utilities used by spline drawing routines */
1844 typedef struct wx_spline_stack_struct
{
1845 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1848 #define SPLINE_STACK_DEPTH 20
1849 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1850 static Stack
*wx_stack_top
;
1851 static int wx_stack_count
;
1853 void wx_clear_stack()
1855 wx_stack_top
= wx_spline_stack
;
1859 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1861 wx_stack_top
->x1
= x1
;
1862 wx_stack_top
->y1
= y1
;
1863 wx_stack_top
->x2
= x2
;
1864 wx_stack_top
->y2
= y2
;
1865 wx_stack_top
->x3
= x3
;
1866 wx_stack_top
->y3
= y3
;
1867 wx_stack_top
->x4
= x4
;
1868 wx_stack_top
->y4
= y4
;
1873 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1874 double *x3
, double *y3
, double *x4
, double *y4
)
1876 if (wx_stack_count
== 0)
1880 *x1
= wx_stack_top
->x1
;
1881 *y1
= wx_stack_top
->y1
;
1882 *x2
= wx_stack_top
->x2
;
1883 *y2
= wx_stack_top
->y2
;
1884 *x3
= wx_stack_top
->x3
;
1885 *y3
= wx_stack_top
->y3
;
1886 *x4
= wx_stack_top
->x4
;
1887 *y4
= wx_stack_top
->y4
;
1891 static bool wx_spline_add_point(double x
, double y
)
1893 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
1894 wx_spline_point_list
.Append( point
);
1898 static void wx_spline_draw_point_array(wxDCBase
*dc
)
1900 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1901 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1904 wxPoint
*point
= node
->GetData();
1906 wx_spline_point_list
.Erase(node
);
1907 node
= wx_spline_point_list
.GetFirst();
1911 #if WXWIN_COMPATIBILITY_2_8
1912 void wxDCBase::DrawSpline(const wxList
*points
)
1915 wxObjectList::compatibility_iterator node
= points
->GetFirst();
1918 list
.Append( (wxPoint
*) node
->GetData() );
1919 node
= node
->GetNext();
1921 DoDrawSpline( &list
);
1923 #endif // WXWIN_COMPATIBILITY_2_8
1925 void wxDCBase::DoDrawSpline( const wxPointList
*points
)
1927 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1930 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1931 double x1
, y1
, x2
, y2
;
1933 wxPointList::compatibility_iterator node
= points
->GetFirst();
1938 p
= node
->GetData();
1943 node
= node
->GetNext();
1944 p
= node
->GetData();
1948 cx1
= (double)((x1
+ x2
) / 2);
1949 cy1
= (double)((y1
+ y2
) / 2);
1950 cx2
= (double)((cx1
+ x2
) / 2);
1951 cy2
= (double)((cy1
+ y2
) / 2);
1953 wx_spline_add_point(x1
, y1
);
1955 while ((node
= node
->GetNext())
1958 #endif // !wxUSE_STL
1961 p
= node
->GetData();
1966 cx4
= (double)(x1
+ x2
) / 2;
1967 cy4
= (double)(y1
+ y2
) / 2;
1968 cx3
= (double)(x1
+ cx4
) / 2;
1969 cy3
= (double)(y1
+ cy4
) / 2;
1971 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1975 cx2
= (double)(cx1
+ x2
) / 2;
1976 cy2
= (double)(cy1
+ y2
) / 2;
1979 wx_spline_add_point( cx1
, cy1
);
1980 wx_spline_add_point( x2
, y2
);
1982 wx_spline_draw_point_array( this );
1985 #endif // wxUSE_SPLINES
1987 // ----------------------------------------------------------------------------
1988 // Partial Text Extents
1989 // ----------------------------------------------------------------------------
1992 // Each element of the widths array will be the width of the string up to and
1993 // including the corresponding character in text. This is the generic
1994 // implementation, the port-specific classes should do this with native APIs
1995 // if available and if faster. Note: pango_layout_index_to_pos is much slower
1996 // than calling GetTextExtent!!
1998 #define FWC_SIZE 256
2000 class FontWidthCache
2003 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
2004 ~FontWidthCache() { delete []m_widths
; }
2009 m_widths
= new int[FWC_SIZE
];
2011 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2019 static FontWidthCache s_fontWidthCache
;
2021 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2025 const size_t len
= text
.length();
2029 // reset the cache if font or horizontal scale have changed
2030 if ( !s_fontWidthCache
.m_widths
||
2031 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2032 (s_fontWidthCache
.m_font
!= GetFont()) )
2034 s_fontWidthCache
.Reset();
2035 s_fontWidthCache
.m_font
= GetFont();
2036 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2039 // Calculate the position of each character based on the widths of
2040 // the previous characters
2042 for ( size_t i
= 0; i
< len
; i
++ )
2044 const wxChar c
= text
[i
];
2045 unsigned int c_int
= (unsigned int)c
;
2047 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2049 w
= s_fontWidthCache
.m_widths
[c_int
];
2053 GetTextExtent(c
, &w
, &h
);
2054 if (c_int
< FWC_SIZE
)
2055 s_fontWidthCache
.m_widths
[c_int
] = w
;
2059 widths
[i
] = totalWidth
;
2066 // ----------------------------------------------------------------------------
2067 // enhanced text drawing
2068 // ----------------------------------------------------------------------------
2070 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2074 const wxFont
*font
) const
2076 wxCoord widthTextMax
= 0, widthLine
,
2077 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2080 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2082 if ( pc
== text
.end() || *pc
== _T('\n') )
2084 if ( curLine
.empty() )
2086 // we can't use GetTextExtent - it will return 0 for both width
2087 // and height and an empty line should count in height
2090 // assume that this line has the same height as the previous
2092 if ( !heightLineDefault
)
2093 heightLineDefault
= heightLine
;
2095 if ( !heightLineDefault
)
2097 // but we don't know it yet - choose something reasonable
2098 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2102 heightTextTotal
+= heightLineDefault
;
2106 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2108 if ( widthLine
> widthTextMax
)
2109 widthTextMax
= widthLine
;
2110 heightTextTotal
+= heightLine
;
2113 if ( pc
== text
.end() )
2131 *y
= heightTextTotal
;
2136 void wxDCBase::DrawLabel(const wxString
& text
,
2137 const wxBitmap
& bitmap
,
2141 wxRect
*rectBounding
)
2143 // find the text position
2144 wxCoord widthText
, heightText
, heightLine
;
2145 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2147 wxCoord width
, height
;
2150 width
= widthText
+ bitmap
.GetWidth();
2151 height
= bitmap
.GetHeight();
2156 height
= heightText
;
2160 if ( alignment
& wxALIGN_RIGHT
)
2162 x
= rect
.GetRight() - width
;
2164 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2166 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2168 else // alignment & wxALIGN_LEFT
2173 if ( alignment
& wxALIGN_BOTTOM
)
2175 y
= rect
.GetBottom() - height
;
2177 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2179 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2181 else // alignment & wxALIGN_TOP
2186 // draw the bitmap first
2192 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2194 wxCoord offset
= bitmap
.GetWidth() + 4;
2198 y
+= (height
- heightText
) / 2;
2201 // we will draw the underscore under the accel char later
2202 wxCoord startUnderscore
= 0,
2206 // split the string into lines and draw each of them separately
2208 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2210 if ( pc
== text
.end() || *pc
== _T('\n') )
2212 int xRealStart
= x
; // init it here to avoid compielr warnings
2214 if ( !curLine
.empty() )
2216 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2217 // wxALIGN_LEFT is 0
2218 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2221 GetTextExtent(curLine
, &widthLine
, NULL
);
2223 if ( alignment
& wxALIGN_RIGHT
)
2225 xRealStart
+= width
- widthLine
;
2227 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2229 xRealStart
+= (width
- widthLine
) / 2;
2232 //else: left aligned, nothing to do
2234 DrawText(curLine
, xRealStart
, y
);
2239 // do we have underscore in this line? we can check yUnderscore
2240 // because it is set below to just y + heightLine if we do
2241 if ( y
== yUnderscore
)
2243 // adjust the horz positions to account for the shift
2244 startUnderscore
+= xRealStart
;
2245 endUnderscore
+= xRealStart
;
2248 if ( pc
== text
.end() )
2253 else // not end of line
2255 if ( pc
- text
.begin() == indexAccel
)
2257 // remeber to draw underscore here
2258 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2260 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2262 yUnderscore
= y
+ heightLine
;
2271 // draw the underscore if found
2272 if ( startUnderscore
!= endUnderscore
)
2274 // it should be of the same colour as text
2275 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2279 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2282 // return bounding rect if requested
2285 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2288 CalcBoundingBox(x0
, y0
);
2289 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2293 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2294 const wxColour
& initialColour
,
2295 const wxColour
& destColour
,
2296 wxDirection nDirection
)
2299 wxPen oldPen
= m_pen
;
2300 wxBrush oldBrush
= m_brush
;
2302 wxUint8 nR1
= initialColour
.Red();
2303 wxUint8 nG1
= initialColour
.Green();
2304 wxUint8 nB1
= initialColour
.Blue();
2305 wxUint8 nR2
= destColour
.Red();
2306 wxUint8 nG2
= destColour
.Green();
2307 wxUint8 nB2
= destColour
.Blue();
2310 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2312 wxInt32 x
= rect
.GetWidth();
2313 wxInt32 w
= x
; // width of area to shade
2314 wxInt32 xDelta
= w
/256; // height of one shade bend
2322 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2324 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2327 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2329 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2332 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2334 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2336 wxColour
colour(nR
,nG
,nB
);
2337 SetPen(wxPen(colour
, 1, wxSOLID
));
2338 SetBrush(wxBrush(colour
));
2339 if(nDirection
== wxEAST
)
2340 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
2341 xDelta
, rect
.GetHeight());
2342 else //nDirection == wxWEST
2343 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2344 xDelta
, rect
.GetHeight());
2347 else // nDirection == wxNORTH || nDirection == wxSOUTH
2349 wxInt32 y
= rect
.GetHeight();
2350 wxInt32 w
= y
; // height of area to shade
2351 wxInt32 yDelta
= w
/255; // height of one shade bend
2359 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2361 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2364 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2366 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2369 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2371 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2373 wxColour
colour(nR
,nG
,nB
);
2374 SetPen(wxPen(colour
, 1, wxSOLID
));
2375 SetBrush(wxBrush(colour
));
2376 if(nDirection
== wxNORTH
)
2377 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2378 rect
.GetWidth(), yDelta
);
2379 else //nDirection == wxSOUTH
2380 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
2381 rect
.GetWidth(), yDelta
);
2389 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2390 const wxColour
& initialColour
,
2391 const wxColour
& destColour
,
2392 const wxPoint
& circleCenter
)
2394 //save the old pen color
2395 wxColour oldPenColour
= m_pen
.GetColour();
2397 wxUint8 nR1
= destColour
.Red();
2398 wxUint8 nG1
= destColour
.Green();
2399 wxUint8 nB1
= destColour
.Blue();
2400 wxUint8 nR2
= initialColour
.Red();
2401 wxUint8 nG2
= initialColour
.Green();
2402 wxUint8 nB2
= initialColour
.Blue();
2407 wxInt32 cx
= rect
.GetWidth() / 2;
2408 wxInt32 cy
= rect
.GetHeight() / 2;
2416 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2417 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2419 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2421 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2423 //get color difference
2424 wxInt32 nGradient
= ((nRadius
-
2426 pow((double)(x
- cx
- nCircleOffX
), 2) +
2427 pow((double)(y
- cy
- nCircleOffY
), 2)
2428 )) * 100) / nRadius
;
2430 //normalize Gradient
2435 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2436 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2437 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2440 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2441 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2444 //return old pen color
2445 m_pen
.SetColour(oldPenColour
);
2449 Notes for wxWidgets DrawEllipticArcRot(...)
2451 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2452 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2455 All methods are generic, so they can be implemented in wxDCBase.
2456 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2457 methods like (WinCE) wxDC::DoDrawArc(...).
2459 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2460 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2461 parts) or every column (in steep parts) only one pixel is calculated.
2462 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2463 starting angle is not equal to the ending angle. The calculation of the
2464 pixels is done using simple arithmetic only and should perform not too
2465 bad even on devices without floating point processor. I didn't test this yet.
2467 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2468 For instance: an ellipse rotated 180 degrees is drawn
2469 slightly different from the original.
2471 The points are then moved to an array and used to draw a polyline and/or polygon
2472 (with center added, the pie).
2473 The result looks quite similar to the native ellipse, only e few pixels differ.
2475 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2476 slower as DrawEllipse(...), which calls the native API.
2477 An rotated ellipse outside the clipping region takes nearly the same time,
2478 while an native ellipse outside takes nearly no time to draw.
2480 If you draw an arc with this new method, you will see the starting and ending angles
2481 are calculated properly.
2482 If you use DrawEllipticArc(...), you will see they are only correct for circles
2483 and not properly calculated for ellipses.
2486 p.lenhard@t-online.de
2490 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2491 wxCoord w
, wxCoord h
,
2492 double sa
, double ea
, double angle
)
2496 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2497 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2499 // Add center (for polygon/pie)
2500 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
2502 // copy list into array and delete list elements
2503 int n
= list
.GetCount();
2504 wxPoint
*points
= new wxPoint
[n
];
2506 wxPointList::compatibility_iterator node
;
2507 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2509 wxPoint
*point
= node
->GetData();
2510 points
[i
].x
= point
->x
;
2511 points
[i
].y
= point
->y
;
2515 // first draw the pie without pen, if necessary
2516 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2518 wxPen
tempPen( GetPen() );
2519 SetPen( *wxTRANSPARENT_PEN
);
2520 DoDrawPolygon( n
, points
, 0, 0 );
2524 // then draw the arc without brush, if necessary
2525 if( GetPen() != *wxTRANSPARENT_PEN
)
2528 DoDrawLines( n
-1, points
, 0, 0 );
2533 } // DrawEllipticArcRot
2535 void wxDCBase::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
2540 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2541 double dCosA
= cos(angle
*2.0*pi
/360.0);
2542 wxPointList::compatibility_iterator node
;
2543 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2545 wxPoint
* point
= node
->GetData();
2547 // transform coordinates, if necessary
2548 if( center
.x
) point
->x
-= center
.x
;
2549 if( center
.y
) point
->y
-= center
.y
;
2551 // calculate rotation, rounding simply by implicit cast to integer
2552 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2553 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2556 // back transform coordinates, if necessary
2557 if( center
.x
) point
->x
+= center
.x
;
2558 if( center
.y
) point
->y
+= center
.y
;
2563 void wxDCBase::CalculateEllipticPoints( wxPointList
* points
,
2564 wxCoord xStart
, wxCoord yStart
,
2565 wxCoord w
, wxCoord h
,
2566 double sa
, double ea
)
2577 bool bUseAngles
= false;
2583 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2585 if( 2*a
== w
) decrX
= 1;
2587 if( 2*b
== h
) decrY
= 1;
2589 wxCoord xCenter
= xStart
+ a
;
2590 wxCoord yCenter
= yStart
+ b
;
2591 // calculate data for start and end, if necessary
2595 // normalisation of angles
2596 while( sa
<0 ) sa
+= 360;
2597 while( ea
<0 ) ea
+= 360;
2598 while( sa
>=360 ) sa
-= 360;
2599 while( ea
>=360 ) ea
-= 360;
2600 // calculate quadrant numbers
2601 if( sa
> 270 ) sq
= 3;
2602 else if( sa
> 180 ) sq
= 2;
2603 else if( sa
> 90 ) sq
= 1;
2604 if( ea
> 270 ) eq
= 3;
2605 else if( ea
> 180 ) eq
= 2;
2606 else if( ea
> 90 ) eq
= 1;
2607 sar
= sa
* pi
/ 180.0;
2608 ear
= ea
* pi
/ 180.0;
2609 // correct angle circle -> ellipse
2610 sar
= atan( -a
/(double)b
* tan( sar
) );
2611 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2612 ear
= atan( -a
/(double)b
* tan( ear
) );
2613 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2614 // coordinates of points
2615 xsa
= xCenter
+ a
* cos( sar
);
2616 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2617 ysa
= yCenter
+ b
* sin( sar
);
2618 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2619 xea
= xCenter
+ a
* cos( ear
);
2620 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2621 yea
= yCenter
+ b
* sin( ear
);
2622 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2624 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2626 double c2
= 2.0 / w
;
2635 // Lists for quadrant 1 to 4
2636 wxPointList pointsarray
[4];
2637 // Calculate points for first quadrant and set in all quadrants
2638 for( x
= 0; x
<= a
; ++x
)
2643 bool bNewPoint
= false;
2644 while( y2
> c1
- c2
* x2
&& y
> 0 )
2650 // old y now to big: set point with old y, old x
2651 if( bNewPoint
&& x
>1)
2654 // remove points on the same line
2655 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2656 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2657 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2658 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2660 } // calculate point
2662 // Starting and/or ending points for the quadrants, first quadrant gets both.
2663 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2664 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
2665 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
2666 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2667 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2669 // copy quadrants in original list
2672 // Copy the right part of the points in the lists
2673 // and delete the wxPoints, because they do not leave this method.
2674 points
->Append( new wxPoint( xsa
, ysa
) );
2676 bool bStarted
= false;
2677 bool bReady
= false;
2678 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2681 wxPointList::compatibility_iterator node
;
2682 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2684 // once: go to starting point in start quadrant
2687 node
->GetData()->x
< xsa
+1 && q
<= 1
2689 node
->GetData()->x
> xsa
-1 && q
>= 2
2696 // copy point, if not at ending point
2699 if( q
!= eq
|| bForceTurn
2701 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2703 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2707 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
2708 points
->Append( pPoint
);
2710 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
2720 } // while not bReady
2721 points
->Append( new wxPoint( xea
, yea
) );
2724 for( q
= 0; q
< 4; ++q
)
2726 wxPointList::compatibility_iterator node
;
2727 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2729 wxPoint
*p
= node
->GetData();
2736 wxPointList::compatibility_iterator node
;
2737 // copy whole ellipse, wxPoints will be deleted outside
2738 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2740 wxPoint
*p
= node
->GetData();
2741 points
->Append( p
);
2743 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2745 wxPoint
*p
= node
->GetData();
2746 points
->Append( p
);
2748 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2750 wxPoint
*p
= node
->GetData();
2751 points
->Append( p
);
2753 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2755 wxPoint
*p
= node
->GetData();
2756 points
->Append( p
);
2759 } // CalculateEllipticPoints
2761 #endif // __WXWINCE__
2763 #endif // wxUSE_NEW_DC