1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.h"
30 #include "wx/dcscreen.h"
31 #include "wx/dcprint.h"
32 #include "wx/prntbase.h"
33 #include "wx/scopeguard.h"
37 #include "wx/module.h"
38 #include "wx/window.h"
42 #include "wx/msw/dcclient.h"
43 #include "wx/msw/dcmemory.h"
44 #include "wx/msw/dcscreen.h"
48 #include "wx/gtk/dc.h"
49 #elif defined __WXGTK20__
50 #include "wx/gtk/dcclient.h"
51 #include "wx/gtk/dcmemory.h"
52 #include "wx/gtk/dcscreen.h"
53 #elif defined(__WXGTK__)
54 #include "wx/gtk1/dcclient.h"
55 #include "wx/gtk1/dcmemory.h"
56 #include "wx/gtk1/dcscreen.h"
60 #include "wx/osx/dcclient.h"
61 #include "wx/osx/dcmemory.h"
62 #include "wx/osx/dcscreen.h"
66 #include "wx/os2/dcclient.h"
67 #include "wx/os2/dcmemory.h"
68 #include "wx/os2/dcscreen.h"
72 #include "wx/cocoa/dcclient.h"
73 #include "wx/cocoa/dcmemory.h"
74 #include "wx/cocoa/dcscreen.h"
78 #include "wx/motif/dcclient.h"
79 #include "wx/motif/dcmemory.h"
80 #include "wx/motif/dcscreen.h"
84 #include "wx/x11/dcclient.h"
85 #include "wx/x11/dcmemory.h"
86 #include "wx/x11/dcscreen.h"
90 #include "wx/dfb/dcclient.h"
91 #include "wx/dfb/dcmemory.h"
92 #include "wx/dfb/dcscreen.h"
95 //----------------------------------------------------------------------------
97 //----------------------------------------------------------------------------
99 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
101 void wxDCFactory::Set(wxDCFactory
*factory
)
108 wxDCFactory
*wxDCFactory::Get()
111 m_factory
= new wxNativeDCFactory
;
116 class wxDCFactoryCleanupModule
: public wxModule
119 virtual bool OnInit() { return true; }
120 virtual void OnExit() { wxDCFactory::Set(NULL
); }
123 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
126 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
128 //-----------------------------------------------------------------------------
130 //-----------------------------------------------------------------------------
132 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
134 wxDCImpl
* const impl
= new wxWindowDCImpl( owner
, window
);
135 impl
->InheritAttributes(window
);
139 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
141 wxDCImpl
* const impl
= new wxClientDCImpl( owner
, window
);
142 impl
->InheritAttributes(window
);
146 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
148 wxDCImpl
* const impl
= new wxPaintDCImpl( owner
, window
);
149 impl
->InheritAttributes(window
);
153 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
155 return new wxMemoryDCImpl( owner
);
158 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC
*owner
, wxBitmap
& bitmap
)
160 // the bitmap may be modified when it's selected into a memory DC so make
161 // sure changing this bitmap doesn't affect any other shallow copies of it
162 // (see wxMemoryDC::SelectObject())
164 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
165 // method because this should be rarely needed and easy to work around by
166 // using the default ctor and calling SelectObjectAsSource itself
170 return new wxMemoryDCImpl(owner
, bitmap
);
173 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
175 return new wxMemoryDCImpl( owner
, dc
);
178 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
180 return new wxScreenDCImpl( owner
);
183 #if wxUSE_PRINTING_ARCHITECTURE
184 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
186 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
187 return factory
->CreatePrinterDCImpl( owner
, data
);
191 //-----------------------------------------------------------------------------
193 //-----------------------------------------------------------------------------
195 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
197 wxWindowDC::wxWindowDC(wxWindow
*win
)
198 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
202 //-----------------------------------------------------------------------------
204 //-----------------------------------------------------------------------------
206 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
208 wxClientDC::wxClientDC(wxWindow
*win
)
209 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
213 //-----------------------------------------------------------------------------
215 //-----------------------------------------------------------------------------
217 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
219 wxMemoryDC::wxMemoryDC()
220 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
224 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
225 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
229 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
230 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
234 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
236 if ( bmp
.IsSameAs(GetSelectedBitmap()) )
238 // Nothing to do, this bitmap is already selected.
242 // make sure that the given wxBitmap is not sharing its data with other
243 // wxBitmap instances as its contents will be modified by any drawing
244 // operation done on this DC
248 GetImpl()->DoSelect(bmp
);
251 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
253 GetImpl()->DoSelect(bmp
);
256 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
258 return GetImpl()->GetSelectedBitmap();
261 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
263 return GetImpl()->GetSelectedBitmap();
267 //-----------------------------------------------------------------------------
269 //-----------------------------------------------------------------------------
271 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
273 wxPaintDC::wxPaintDC(wxWindow
*win
)
274 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
278 //-----------------------------------------------------------------------------
280 //-----------------------------------------------------------------------------
282 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
284 wxScreenDC::wxScreenDC()
285 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
289 //-----------------------------------------------------------------------------
291 //-----------------------------------------------------------------------------
293 #if wxUSE_PRINTING_ARCHITECTURE
295 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
297 wxPrinterDC::wxPrinterDC()
298 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
302 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
303 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
307 wxRect
wxPrinterDC::GetPaperRect() const
309 return GetImpl()->GetPaperRect();
312 int wxPrinterDC::GetResolution() const
314 return GetImpl()->GetResolution();
317 #endif // wxUSE_PRINTING_ARCHITECTURE
319 //-----------------------------------------------------------------------------
321 //-----------------------------------------------------------------------------
323 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
325 wxDCImpl::wxDCImpl( wxDC
*owner
)
327 , m_colour(wxColourDisplay())
331 , m_isBBoxValid(false)
332 , m_logicalOriginX(0), m_logicalOriginY(0)
333 , m_deviceOriginX(0), m_deviceOriginY(0)
334 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
335 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
336 , m_userScaleX(1.0), m_userScaleY(1.0)
337 , m_scaleX(1.0), m_scaleY(1.0)
338 , m_signX(1), m_signY(1)
339 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
340 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
341 , m_logicalFunction(wxCOPY
)
342 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
343 , m_mappingMode(wxMM_TEXT
)
346 , m_backgroundBrush()
347 , m_textForegroundColour(*wxBLACK
)
348 , m_textBackgroundColour(*wxWHITE
)
352 , m_hasCustomPalette(false)
353 #endif // wxUSE_PALETTE
357 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
358 (double)wxGetDisplaySizeMM().GetWidth();
359 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
360 (double)wxGetDisplaySizeMM().GetHeight();
366 wxDCImpl::~wxDCImpl()
370 // ----------------------------------------------------------------------------
372 // ----------------------------------------------------------------------------
374 void wxDCImpl::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
378 m_clipX1
= wxMax( m_clipX1
, x
);
379 m_clipY1
= wxMax( m_clipY1
, y
);
380 m_clipX2
= wxMin( m_clipX2
, (x
+ w
) );
381 m_clipY2
= wxMin( m_clipY2
, (y
+ h
) );
394 // ----------------------------------------------------------------------------
395 // coordinate conversions and transforms
396 // ----------------------------------------------------------------------------
398 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
400 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
403 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
405 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
408 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
410 return wxRound((double)(x
) / m_scaleX
);
413 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
415 return wxRound((double)(y
) / m_scaleY
);
418 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
420 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
423 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
425 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
428 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
430 return wxRound((double)(x
) * m_scaleX
);
433 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
435 return wxRound((double)(y
) * m_scaleY
);
438 void wxDCImpl::ComputeScaleAndOrigin()
440 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
441 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
444 void wxDCImpl::SetMapMode( wxMappingMode mode
)
449 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
452 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
455 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
458 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
462 SetLogicalScale( 1.0, 1.0 );
465 m_mappingMode
= mode
;
468 void wxDCImpl::SetUserScale( double x
, double y
)
470 // allow negative ? -> no
473 ComputeScaleAndOrigin();
476 void wxDCImpl::SetLogicalScale( double x
, double y
)
481 ComputeScaleAndOrigin();
484 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
486 m_logicalOriginX
= x
* m_signX
;
487 m_logicalOriginY
= y
* m_signY
;
488 ComputeScaleAndOrigin();
491 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
495 ComputeScaleAndOrigin();
498 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
500 m_deviceLocalOriginX
= x
;
501 m_deviceLocalOriginY
= y
;
502 ComputeScaleAndOrigin();
505 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
507 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
508 // wxWidgets 2.9: no longer override it
509 m_signX
= (xLeftRight
? 1 : -1);
510 m_signY
= (yBottomUp
? -1 : 1);
511 ComputeScaleAndOrigin();
515 // Each element of the widths array will be the width of the string up to and
516 // including the corresponding character in text. This is the generic
517 // implementation, the port-specific classes should do this with native APIs
518 // if available and if faster. Note: pango_layout_index_to_pos is much slower
519 // than calling GetTextExtent!!
526 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
527 ~FontWidthCache() { delete []m_widths
; }
532 m_widths
= new int[FWC_SIZE
];
534 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
542 static FontWidthCache s_fontWidthCache
;
544 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
548 const size_t len
= text
.length();
552 // reset the cache if font or horizontal scale have changed
553 if ( !s_fontWidthCache
.m_widths
||
554 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
555 (s_fontWidthCache
.m_font
!= GetFont()) )
557 s_fontWidthCache
.Reset();
558 s_fontWidthCache
.m_font
= GetFont();
559 s_fontWidthCache
.m_scaleX
= m_scaleX
;
562 // Calculate the position of each character based on the widths of
563 // the previous characters
565 for ( size_t i
= 0; i
< len
; i
++ )
567 const wxChar c
= text
[i
];
568 unsigned int c_int
= (unsigned int)c
;
570 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
572 w
= s_fontWidthCache
.m_widths
[c_int
];
576 DoGetTextExtent(c
, &w
, &h
);
577 if (c_int
< FWC_SIZE
)
578 s_fontWidthCache
.m_widths
[c_int
] = w
;
582 widths
[i
] = totalWidth
;
588 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
592 const wxFont
*font
) const
594 wxCoord widthTextMax
= 0, widthLine
,
595 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
598 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
600 if ( pc
== text
.end() || *pc
== wxT('\n') )
602 if ( curLine
.empty() )
604 // we can't use GetTextExtent - it will return 0 for both width
605 // and height and an empty line should count in height
608 // assume that this line has the same height as the previous
610 if ( !heightLineDefault
)
611 heightLineDefault
= heightLine
;
613 if ( !heightLineDefault
)
615 // but we don't know it yet - choose something reasonable
616 DoGetTextExtent(wxT("W"), NULL
, &heightLineDefault
,
620 heightTextTotal
+= heightLineDefault
;
624 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
626 if ( widthLine
> widthTextMax
)
627 widthTextMax
= widthLine
;
628 heightTextTotal
+= heightLine
;
631 if ( pc
== text
.end() )
649 *y
= heightTextTotal
;
654 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
655 wxCoord width
, wxCoord height
)
657 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
659 wxCoord x2
= x1
+ width
,
662 // the pen width is calibrated to give 3 for width == height == 10
663 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
665 // we're drawing a scaled version of wx/generic/tick.xpm here
666 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
667 y3
= y1
+ height
/ 2; // y of the left tick branch
668 DoDrawLine(x1
, y3
, x3
, y2
);
669 DoDrawLine(x3
, y2
, x2
, y1
);
671 CalcBoundingBox(x1
, y1
);
672 CalcBoundingBox(x2
, y2
);
676 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
677 wxCoord dstWidth
, wxCoord dstHeight
,
679 wxCoord xsrc
, wxCoord ysrc
,
680 wxCoord srcWidth
, wxCoord srcHeight
,
681 wxRasterOperationMode rop
,
686 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
687 wxT("invalid blit size") );
689 // emulate the stretching by modifying the DC scale
690 double xscale
= (double)srcWidth
/dstWidth
,
691 yscale
= (double)srcHeight
/dstHeight
;
693 double xscaleOld
, yscaleOld
;
694 GetUserScale(&xscaleOld
, &yscaleOld
);
695 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
697 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
698 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
700 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
702 SetUserScale(xscaleOld
, yscaleOld
);
707 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
709 int n
= list
->GetCount();
710 wxPoint
*points
= new wxPoint
[n
];
713 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
715 wxPoint
*point
= node
->GetData();
716 points
[i
].x
= point
->x
;
717 points
[i
].y
= point
->y
;
720 DoDrawLines(n
, points
, xoffset
, yoffset
);
725 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
726 wxCoord xoffset
, wxCoord yoffset
,
727 wxPolygonFillMode fillStyle
)
729 int n
= list
->GetCount();
730 wxPoint
*points
= new wxPoint
[n
];
733 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
735 wxPoint
*point
= node
->GetData();
736 points
[i
].x
= point
->x
;
737 points
[i
].y
= point
->y
;
740 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
746 wxDCImpl::DoDrawPolyPolygon(int n
,
749 wxCoord xoffset
, wxCoord yoffset
,
750 wxPolygonFillMode fillStyle
)
754 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
761 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
766 pts
= new wxPoint
[j
+n
-1];
767 for (i
= 0; i
< j
; i
++)
769 for (i
= 2; i
<= n
; i
++)
771 lastOfs
-= count
[n
-i
];
772 pts
[j
++] = pts
[lastOfs
];
776 wxDCPenChanger
setTransp(*m_owner
, *wxTRANSPARENT_PEN
);
777 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
780 for (i
= j
= 0; i
< n
; i
++)
782 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
790 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
791 wxCoord x2
, wxCoord y2
,
792 wxCoord x3
, wxCoord y3
)
794 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
795 DrawSpline(WXSIZEOF(points
), points
);
798 void wxDCImpl::DrawSpline(int n
, wxPoint points
[])
801 for ( int i
= 0; i
< n
; i
++ )
802 list
.Append(&points
[i
]);
807 // ----------------------------------- spline code ----------------------------------------
809 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
810 double a3
, double b3
, double a4
, double b4
);
811 void wx_clear_stack();
812 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
813 double *y3
, double *x4
, double *y4
);
814 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
815 double x4
, double y4
);
816 static bool wx_spline_add_point(double x
, double y
);
817 static void wx_spline_draw_point_array(wxDC
*dc
);
819 static wxPointList wx_spline_point_list
;
821 #define half(z1, z2) ((z1+z2)/2.0)
824 /* iterative version */
826 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
829 register double xmid
, ymid
;
830 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
833 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
835 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
836 xmid
= (double)half(x2
, x3
);
837 ymid
= (double)half(y2
, y3
);
838 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
839 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
840 wx_spline_add_point( x1
, y1
);
841 wx_spline_add_point( xmid
, ymid
);
843 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
844 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
845 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
846 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
851 /* utilities used by spline drawing routines */
853 typedef struct wx_spline_stack_struct
{
854 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
857 #define SPLINE_STACK_DEPTH 20
858 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
859 static Stack
*wx_stack_top
;
860 static int wx_stack_count
;
862 void wx_clear_stack()
864 wx_stack_top
= wx_spline_stack
;
868 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
870 wx_stack_top
->x1
= x1
;
871 wx_stack_top
->y1
= y1
;
872 wx_stack_top
->x2
= x2
;
873 wx_stack_top
->y2
= y2
;
874 wx_stack_top
->x3
= x3
;
875 wx_stack_top
->y3
= y3
;
876 wx_stack_top
->x4
= x4
;
877 wx_stack_top
->y4
= y4
;
882 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
883 double *x3
, double *y3
, double *x4
, double *y4
)
885 if (wx_stack_count
== 0)
889 *x1
= wx_stack_top
->x1
;
890 *y1
= wx_stack_top
->y1
;
891 *x2
= wx_stack_top
->x2
;
892 *y2
= wx_stack_top
->y2
;
893 *x3
= wx_stack_top
->x3
;
894 *y3
= wx_stack_top
->y3
;
895 *x4
= wx_stack_top
->x4
;
896 *y4
= wx_stack_top
->y4
;
900 static bool wx_spline_add_point(double x
, double y
)
902 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
903 wx_spline_point_list
.Append(point
);
907 static void wx_spline_draw_point_array(wxDC
*dc
)
909 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
910 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
913 wxPoint
*point
= node
->GetData();
915 wx_spline_point_list
.Erase(node
);
916 node
= wx_spline_point_list
.GetFirst();
920 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
922 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
925 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
926 double x1
, y1
, x2
, y2
;
928 wxPointList::compatibility_iterator node
= points
->GetFirst();
933 p
= (wxPoint
*)node
->GetData();
938 node
= node
->GetNext();
943 cx1
= (double)((x1
+ x2
) / 2);
944 cy1
= (double)((y1
+ y2
) / 2);
945 cx2
= (double)((cx1
+ x2
) / 2);
946 cy2
= (double)((cy1
+ y2
) / 2);
948 wx_spline_add_point(x1
, y1
);
950 while ((node
= node
->GetNext())
951 #if !wxUSE_STD_CONTAINERS
953 #endif // !wxUSE_STD_CONTAINERS
961 cx4
= (double)(x1
+ x2
) / 2;
962 cy4
= (double)(y1
+ y2
) / 2;
963 cx3
= (double)(x1
+ cx4
) / 2;
964 cy3
= (double)(y1
+ cy4
) / 2;
966 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
970 cx2
= (double)(cx1
+ x2
) / 2;
971 cy2
= (double)(cy1
+ y2
) / 2;
974 wx_spline_add_point( cx1
, cy1
);
975 wx_spline_add_point( x2
, y2
);
977 wx_spline_draw_point_array( m_owner
);
980 #endif // wxUSE_SPLINES
984 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
985 const wxColour
& initialColour
,
986 const wxColour
& destColour
,
987 wxDirection nDirection
)
990 wxPen oldPen
= m_pen
;
991 wxBrush oldBrush
= m_brush
;
993 wxUint8 nR1
= initialColour
.Red();
994 wxUint8 nG1
= initialColour
.Green();
995 wxUint8 nB1
= initialColour
.Blue();
996 wxUint8 nR2
= destColour
.Red();
997 wxUint8 nG2
= destColour
.Green();
998 wxUint8 nB2
= destColour
.Blue();
1001 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
1003 wxInt32 x
= rect
.GetWidth();
1004 wxInt32 w
= x
; // width of area to shade
1005 wxInt32 xDelta
= w
/256; // height of one shade bend
1013 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1015 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1018 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1020 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1023 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1025 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1027 wxColour
colour(nR
,nG
,nB
);
1028 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1029 SetBrush(wxBrush(colour
));
1030 if(nDirection
== wxEAST
)
1031 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1032 xDelta
, rect
.GetHeight());
1033 else //nDirection == wxWEST
1034 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1035 xDelta
, rect
.GetHeight());
1038 else // nDirection == wxNORTH || nDirection == wxSOUTH
1040 wxInt32 y
= rect
.GetHeight();
1041 wxInt32 w
= y
; // height of area to shade
1042 wxInt32 yDelta
= w
/255; // height of one shade bend
1050 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1052 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1055 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1057 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1060 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1062 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1064 wxColour
colour(nR
,nG
,nB
);
1065 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1066 SetBrush(wxBrush(colour
));
1067 if(nDirection
== wxNORTH
)
1068 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1069 rect
.GetWidth(), yDelta
);
1070 else //nDirection == wxSOUTH
1071 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1072 rect
.GetWidth(), yDelta
);
1080 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1081 const wxColour
& initialColour
,
1082 const wxColour
& destColour
,
1083 const wxPoint
& circleCenter
)
1085 // save the old pen and ensure it is restored on exit
1086 const wxPen penOrig
= m_pen
;
1087 wxON_BLOCK_EXIT_SET(m_pen
, penOrig
);
1089 wxUint8 nR1
= destColour
.Red();
1090 wxUint8 nG1
= destColour
.Green();
1091 wxUint8 nB1
= destColour
.Blue();
1092 wxUint8 nR2
= initialColour
.Red();
1093 wxUint8 nG2
= initialColour
.Green();
1094 wxUint8 nB2
= initialColour
.Blue();
1099 double cx
= rect
.GetWidth() / 2;
1100 double cy
= rect
.GetHeight() / 2;
1109 ptX
= circleCenter
.x
;
1110 ptY
= circleCenter
.y
;
1111 double nCircleOffX
= ptX
- cx
;
1112 double nCircleOffY
= ptY
- cy
;
1117 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1119 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1121 //get color difference
1125 dGradient
= ((dRadius
- sqrt( (dx
- cx
- nCircleOffX
) * (dx
- cx
- nCircleOffX
)
1126 +(dy
- cy
- nCircleOffY
) * (dy
- cy
- nCircleOffY
)
1131 //normalize Gradient
1136 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * dGradient
/ 100));
1137 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * dGradient
/ 100));
1138 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * dGradient
/ 100));
1141 SetPen(wxColour(nR
,nG
,nB
));
1142 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1147 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1149 wxCHECK_RET( win
, "window can't be NULL" );
1151 SetFont(win
->GetFont());
1152 SetTextForeground(win
->GetForegroundColour());
1153 SetTextBackground(win
->GetBackgroundColour());
1154 SetBackground(win
->GetBackgroundColour());
1155 SetLayoutDirection(win
->GetLayoutDirection());
1158 void wxDCImpl::DoGetFontMetrics(int *height
,
1161 int *internalLeading
,
1162 int *externalLeading
,
1163 int *averageWidth
) const
1165 // Average width is typically the same as width of 'x'.
1167 DoGetTextExtent("x", averageWidth
, &h
, &d
, externalLeading
);
1175 if ( internalLeading
)
1176 *internalLeading
= 0;
1179 //-----------------------------------------------------------------------------
1181 //-----------------------------------------------------------------------------
1183 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1185 void wxDC::CopyAttributes(const wxDC
& dc
)
1187 SetFont(dc
.GetFont());
1188 SetTextForeground(dc
.GetTextForeground());
1189 SetTextBackground(dc
.GetTextBackground());
1190 SetBackground(dc
.GetBackground());
1191 SetLayoutDirection(dc
.GetLayoutDirection());
1194 void wxDC::DrawLabel(const wxString
& text
,
1195 const wxBitmap
& bitmap
,
1199 wxRect
*rectBounding
)
1201 // find the text position
1202 wxCoord widthText
, heightText
, heightLine
;
1203 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1205 wxCoord width
, height
;
1206 if ( bitmap
.IsOk() )
1208 width
= widthText
+ bitmap
.GetWidth();
1209 height
= bitmap
.GetHeight();
1214 height
= heightText
;
1218 if ( alignment
& wxALIGN_RIGHT
)
1220 x
= rect
.GetRight() - width
;
1222 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1224 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1226 else // alignment & wxALIGN_LEFT
1231 if ( alignment
& wxALIGN_BOTTOM
)
1233 y
= rect
.GetBottom() - height
;
1235 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1237 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1239 else // alignment & wxALIGN_TOP
1244 // draw the bitmap first
1248 if ( bitmap
.IsOk() )
1250 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1252 wxCoord offset
= bitmap
.GetWidth() + 4;
1256 y
+= (height
- heightText
) / 2;
1259 // we will draw the underscore under the accel char later
1260 wxCoord startUnderscore
= 0,
1264 // split the string into lines and draw each of them separately
1266 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1267 // strings natively, this is not the case for all of them, notably not
1268 // wxMSW which uses this function for multi-line texts, so we may only
1269 // call DrawText() for single-line strings from here to avoid infinite
1272 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1274 if ( pc
== text
.end() || *pc
== '\n' )
1276 int xRealStart
= x
; // init it here to avoid compielr warnings
1278 if ( !curLine
.empty() )
1280 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1281 // wxALIGN_LEFT is 0
1282 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1285 GetTextExtent(curLine
, &widthLine
, NULL
);
1287 if ( alignment
& wxALIGN_RIGHT
)
1289 xRealStart
+= width
- widthLine
;
1291 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1293 xRealStart
+= (width
- widthLine
) / 2;
1296 //else: left aligned, nothing to do
1298 DrawText(curLine
, xRealStart
, y
);
1303 // do we have underscore in this line? we can check yUnderscore
1304 // because it is set below to just y + heightLine if we do
1305 if ( y
== yUnderscore
)
1307 // adjust the horz positions to account for the shift
1308 startUnderscore
+= xRealStart
;
1309 endUnderscore
+= xRealStart
;
1312 if ( pc
== text
.end() )
1317 else // not end of line
1319 if ( pc
- text
.begin() == indexAccel
)
1321 // remember to draw underscore here
1322 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1324 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1326 yUnderscore
= y
+ heightLine
;
1335 // draw the underscore if found
1336 if ( startUnderscore
!= endUnderscore
)
1338 // it should be of the same colour as text
1339 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1341 // This adjustment is relatively arbitrary: we need to draw the
1342 // underline slightly higher to avoid overflowing the character cell
1343 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1345 // The currently used value seems to be compatible with native MSW
1346 // behaviour, i.e. it results in the same appearance of the owner-drawn
1347 // and normal labels.
1350 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1353 // return bounding rect if requested
1356 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1359 CalcBoundingBox(x0
, y0
);
1360 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1363 #if WXWIN_COMPATIBILITY_2_8
1364 // for compatibility with the old code when wxCoord was long everywhere
1365 void wxDC::GetTextExtent(const wxString
& string
,
1368 long *externalLeading
,
1369 const wxFont
*theFont
) const
1371 wxCoord x2
, y2
, descent2
, externalLeading2
;
1372 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1373 &descent2
, &externalLeading2
,
1380 *descent
= descent2
;
1381 if ( externalLeading
)
1382 *externalLeading
= externalLeading2
;
1385 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1388 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1395 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1398 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1405 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1407 wxCoord xx
,yy
,ww
,hh
;
1408 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1415 void wxDC::DrawObject(wxDrawObject
* drawobject
)
1417 drawobject
->Draw(*this);
1418 CalcBoundingBox(drawobject
->MinX(),drawobject
->MinY());
1419 CalcBoundingBox(drawobject
->MaxX(),drawobject
->MaxY());
1422 #endif // WXWIN_COMPATIBILITY_2_8
1425 Notes for wxWidgets DrawEllipticArcRot(...)
1427 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1428 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1431 All methods are generic, so they can be implemented in wxDCBase.
1432 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1433 methods like (WinCE) wxDC::DoDrawArc(...).
1435 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1436 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1437 parts) or every column (in steep parts) only one pixel is calculated.
1438 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1439 starting angle is not equal to the ending angle. The calculation of the
1440 pixels is done using simple arithmetic only and should perform not too
1441 bad even on devices without floating point processor. I didn't test this yet.
1443 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1444 For instance: an ellipse rotated 180 degrees is drawn
1445 slightly different from the original.
1447 The points are then moved to an array and used to draw a polyline and/or polygon
1448 (with center added, the pie).
1449 The result looks quite similar to the native ellipse, only e few pixels differ.
1451 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1452 slower as DrawEllipse(...), which calls the native API.
1453 An rotated ellipse outside the clipping region takes nearly the same time,
1454 while an native ellipse outside takes nearly no time to draw.
1456 If you draw an arc with this new method, you will see the starting and ending angles
1457 are calculated properly.
1458 If you use DrawEllipticArc(...), you will see they are only correct for circles
1459 and not properly calculated for ellipses.
1462 p.lenhard@t-online.de
1466 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1467 wxCoord w
, wxCoord h
,
1468 double sa
, double ea
, double angle
)
1472 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1473 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1475 // Add center (for polygon/pie)
1476 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1478 // copy list into array and delete list elements
1479 int n
= list
.GetCount();
1480 wxPoint
*points
= new wxPoint
[n
];
1482 wxPointList::compatibility_iterator node
;
1483 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1485 wxPoint
*point
= node
->GetData();
1486 points
[i
].x
= point
->x
;
1487 points
[i
].y
= point
->y
;
1491 // first draw the pie without pen, if necessary
1492 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1494 wxPen
tempPen( GetPen() );
1495 SetPen( *wxTRANSPARENT_PEN
);
1496 DoDrawPolygon( n
, points
, 0, 0 );
1500 // then draw the arc without brush, if necessary
1501 if( GetPen() != *wxTRANSPARENT_PEN
)
1504 DoDrawLines( n
-1, points
, 0, 0 );
1509 } // DrawEllipticArcRot
1511 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1516 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1517 double dCosA
= cos(angle
*2.0*pi
/360.0);
1518 wxPointList::compatibility_iterator node
;
1519 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1521 wxPoint
* point
= node
->GetData();
1523 // transform coordinates, if necessary
1524 if( center
.x
) point
->x
-= center
.x
;
1525 if( center
.y
) point
->y
-= center
.y
;
1527 // calculate rotation, rounding simply by implicit cast to integer
1528 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1529 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1532 // back transform coordinates, if necessary
1533 if( center
.x
) point
->x
+= center
.x
;
1534 if( center
.y
) point
->y
+= center
.y
;
1539 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1540 wxCoord xStart
, wxCoord yStart
,
1541 wxCoord w
, wxCoord h
,
1542 double sa
, double ea
)
1553 bool bUseAngles
= false;
1559 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1561 if( 2*a
== w
) decrX
= 1;
1563 if( 2*b
== h
) decrY
= 1;
1565 wxCoord xCenter
= xStart
+ a
;
1566 wxCoord yCenter
= yStart
+ b
;
1567 // calculate data for start and end, if necessary
1571 // normalisation of angles
1572 while( sa
<0 ) sa
+= 360;
1573 while( ea
<0 ) ea
+= 360;
1574 while( sa
>=360 ) sa
-= 360;
1575 while( ea
>=360 ) ea
-= 360;
1576 // calculate quadrant numbers
1577 if( sa
> 270 ) sq
= 3;
1578 else if( sa
> 180 ) sq
= 2;
1579 else if( sa
> 90 ) sq
= 1;
1580 if( ea
> 270 ) eq
= 3;
1581 else if( ea
> 180 ) eq
= 2;
1582 else if( ea
> 90 ) eq
= 1;
1583 sar
= sa
* pi
/ 180.0;
1584 ear
= ea
* pi
/ 180.0;
1585 // correct angle circle -> ellipse
1586 sar
= atan( -a
/(double)b
* tan( sar
) );
1587 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1588 ear
= atan( -a
/(double)b
* tan( ear
) );
1589 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1590 // coordinates of points
1591 xsa
= xCenter
+ a
* cos( sar
);
1592 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1593 ysa
= yCenter
+ b
* sin( sar
);
1594 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1595 xea
= xCenter
+ a
* cos( ear
);
1596 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1597 yea
= yCenter
+ b
* sin( ear
);
1598 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1600 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1602 double c2
= 2.0 / w
;
1611 // Lists for quadrant 1 to 4
1612 wxPointList pointsarray
[4];
1613 // Calculate points for first quadrant and set in all quadrants
1614 for( x
= 0; x
<= a
; ++x
)
1619 bool bNewPoint
= false;
1620 while( y2
> c1
- c2
* x2
&& y
> 0 )
1626 // old y now too big: set point with old y, old x
1627 if( bNewPoint
&& x
>1)
1630 // remove points on the same line
1631 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1632 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1633 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1634 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1636 } // calculate point
1638 // Starting and/or ending points for the quadrants, first quadrant gets both.
1639 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1640 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1641 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1642 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1643 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1645 // copy quadrants in original list
1648 // Copy the right part of the points in the lists
1649 // and delete the wxPoints, because they do not leave this method.
1650 points
->Append( new wxPoint( xsa
, ysa
) );
1652 bool bStarted
= false;
1653 bool bReady
= false;
1654 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1657 wxPointList::compatibility_iterator node
;
1658 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1660 // once: go to starting point in start quadrant
1663 node
->GetData()->x
< xsa
+1 && q
<= 1
1665 node
->GetData()->x
> xsa
-1 && q
>= 2
1672 // copy point, if not at ending point
1675 if( q
!= eq
|| bForceTurn
1677 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1679 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1683 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1684 points
->Append( pPoint
);
1686 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1696 } // while not bReady
1697 points
->Append( new wxPoint( xea
, yea
) );
1700 for( q
= 0; q
< 4; ++q
)
1702 wxPointList::compatibility_iterator node
;
1703 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1705 wxPoint
*p
= node
->GetData();
1712 wxPointList::compatibility_iterator node
;
1713 // copy whole ellipse, wxPoints will be deleted outside
1714 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1716 wxPoint
*p
= node
->GetData();
1717 points
->Append( p
);
1719 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1721 wxPoint
*p
= node
->GetData();
1722 points
->Append( p
);
1724 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1726 wxPoint
*p
= node
->GetData();
1727 points
->Append( p
);
1729 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1731 wxPoint
*p
= node
->GetData();
1732 points
->Append( p
);
1735 } // CalculateEllipticPoints
1737 #endif // __WXWINCE__
1739 float wxDCImpl::GetFontPointSizeAdjustment(float dpi
)
1741 // wxMSW has long-standing bug where wxFont point size is interpreted as
1742 // "pixel size corresponding to given point size *on screen*". In other
1743 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1744 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1745 // that *all* printing code has to account for it and consequently, other
1746 // ports need to emulate this bug too:
1747 const wxSize screenPPI
= wxGetDisplayPPI();
1748 return float(screenPPI
.y
) / dpi
;