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"
41 #include "wx/msw/dcclient.h"
42 #include "wx/msw/dcmemory.h"
43 #include "wx/msw/dcscreen.h"
47 #include "wx/gtk/dcclient.h"
48 #include "wx/gtk/dcmemory.h"
49 #include "wx/gtk/dcscreen.h"
50 #elif defined(__WXGTK__)
51 #include "wx/gtk1/dcclient.h"
52 #include "wx/gtk1/dcmemory.h"
53 #include "wx/gtk1/dcscreen.h"
57 #include "wx/osx/dcclient.h"
58 #include "wx/osx/dcmemory.h"
59 #include "wx/osx/dcscreen.h"
63 #include "wx/os2/dcclient.h"
64 #include "wx/os2/dcmemory.h"
65 #include "wx/os2/dcscreen.h"
69 #include "wx/cocoa/dcclient.h"
70 #include "wx/cocoa/dcmemory.h"
71 #include "wx/cocoa/dcscreen.h"
75 #include "wx/motif/dcclient.h"
76 #include "wx/motif/dcmemory.h"
77 #include "wx/motif/dcscreen.h"
81 #include "wx/x11/dcclient.h"
82 #include "wx/x11/dcmemory.h"
83 #include "wx/x11/dcscreen.h"
87 #include "wx/dfb/dcclient.h"
88 #include "wx/dfb/dcmemory.h"
89 #include "wx/dfb/dcscreen.h"
93 #include "wx/palmos/dcclient.h"
94 #include "wx/palmos/dcmemory.h"
95 #include "wx/palmos/dcscreen.h"
98 //----------------------------------------------------------------------------
100 //----------------------------------------------------------------------------
102 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
104 void wxDCFactory::Set(wxDCFactory
*factory
)
111 wxDCFactory
*wxDCFactory::Get()
114 m_factory
= new wxNativeDCFactory
;
119 class wxDCFactoryCleanupModule
: public wxModule
122 virtual bool OnInit() { return true; }
123 virtual void OnExit() { wxDCFactory::Set(NULL
); }
126 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
129 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
131 //-----------------------------------------------------------------------------
133 //-----------------------------------------------------------------------------
135 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
137 wxDCImpl
* const impl
= new wxWindowDCImpl( owner
, window
);
138 impl
->InheritAttributes(window
);
142 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
144 wxDCImpl
* const impl
= new wxClientDCImpl( owner
, window
);
145 impl
->InheritAttributes(window
);
149 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
151 wxDCImpl
* const impl
= new wxPaintDCImpl( owner
, window
);
152 impl
->InheritAttributes(window
);
156 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
158 return new wxMemoryDCImpl( owner
);
161 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC
*owner
, wxBitmap
& bitmap
)
163 // the bitmap may be modified when it's selected into a memory DC so make
164 // sure changing this bitmap doesn't affect any other shallow copies of it
165 // (see wxMemoryDC::SelectObject())
167 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
168 // method because this should be rarely needed and easy to work around by
169 // using the default ctor and calling SelectObjectAsSource itself
173 return new wxMemoryDCImpl(owner
, bitmap
);
176 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
178 return new wxMemoryDCImpl( owner
, dc
);
181 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
183 return new wxScreenDCImpl( owner
);
186 #if wxUSE_PRINTING_ARCHITECTURE
187 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
189 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
190 return factory
->CreatePrinterDCImpl( owner
, data
);
194 //-----------------------------------------------------------------------------
196 //-----------------------------------------------------------------------------
198 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
200 wxWindowDC::wxWindowDC(wxWindow
*win
)
201 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
205 //-----------------------------------------------------------------------------
207 //-----------------------------------------------------------------------------
209 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
211 wxClientDC::wxClientDC(wxWindow
*win
)
212 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
216 //-----------------------------------------------------------------------------
218 //-----------------------------------------------------------------------------
220 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
222 wxMemoryDC::wxMemoryDC()
223 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
227 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
228 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
232 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
233 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
237 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
239 if ( bmp
.IsSameAs(GetSelectedBitmap()) )
241 // Nothing to do, this bitmap is already selected.
245 // make sure that the given wxBitmap is not sharing its data with other
246 // wxBitmap instances as its contents will be modified by any drawing
247 // operation done on this DC
251 GetImpl()->DoSelect(bmp
);
254 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
256 GetImpl()->DoSelect(bmp
);
259 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
261 return GetImpl()->GetSelectedBitmap();
264 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
266 return GetImpl()->GetSelectedBitmap();
270 //-----------------------------------------------------------------------------
272 //-----------------------------------------------------------------------------
274 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
276 wxPaintDC::wxPaintDC(wxWindow
*win
)
277 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
281 //-----------------------------------------------------------------------------
283 //-----------------------------------------------------------------------------
285 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
287 wxScreenDC::wxScreenDC()
288 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
292 //-----------------------------------------------------------------------------
294 //-----------------------------------------------------------------------------
296 #if wxUSE_PRINTING_ARCHITECTURE
298 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
300 wxPrinterDC::wxPrinterDC()
301 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
305 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
306 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
310 wxRect
wxPrinterDC::GetPaperRect() const
312 return GetImpl()->GetPaperRect();
315 int wxPrinterDC::GetResolution() const
317 return GetImpl()->GetResolution();
320 #endif // wxUSE_PRINTING_ARCHITECTURE
322 //-----------------------------------------------------------------------------
324 //-----------------------------------------------------------------------------
326 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
328 wxDCImpl::wxDCImpl( wxDC
*owner
)
330 , m_colour(wxColourDisplay())
334 , m_isBBoxValid(false)
335 , m_logicalOriginX(0), m_logicalOriginY(0)
336 , m_deviceOriginX(0), m_deviceOriginY(0)
337 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
338 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
339 , m_userScaleX(1.0), m_userScaleY(1.0)
340 , m_scaleX(1.0), m_scaleY(1.0)
341 , m_signX(1), m_signY(1)
342 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
343 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
344 , m_logicalFunction(wxCOPY
)
345 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
346 , m_mappingMode(wxMM_TEXT
)
349 , m_backgroundBrush()
350 , m_textForegroundColour(*wxBLACK
)
351 , m_textBackgroundColour(*wxWHITE
)
355 , m_hasCustomPalette(false)
356 #endif // wxUSE_PALETTE
360 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
361 (double)wxGetDisplaySizeMM().GetWidth();
362 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
363 (double)wxGetDisplaySizeMM().GetHeight();
369 wxDCImpl::~wxDCImpl()
373 // ----------------------------------------------------------------------------
374 // coordinate conversions and transforms
375 // ----------------------------------------------------------------------------
377 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
379 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
382 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
384 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
387 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
389 return wxRound((double)(x
) / m_scaleX
);
392 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
394 return wxRound((double)(y
) / m_scaleY
);
397 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
399 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
402 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
404 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
407 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
409 return wxRound((double)(x
) * m_scaleX
);
412 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
414 return wxRound((double)(y
) * m_scaleY
);
417 void wxDCImpl::ComputeScaleAndOrigin()
419 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
420 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
423 void wxDCImpl::SetMapMode( wxMappingMode mode
)
428 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
431 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
434 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
437 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
441 SetLogicalScale( 1.0, 1.0 );
444 m_mappingMode
= mode
;
447 void wxDCImpl::SetUserScale( double x
, double y
)
449 // allow negative ? -> no
452 ComputeScaleAndOrigin();
455 void wxDCImpl::SetLogicalScale( double x
, double y
)
460 ComputeScaleAndOrigin();
463 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
465 m_logicalOriginX
= x
* m_signX
;
466 m_logicalOriginY
= y
* m_signY
;
467 ComputeScaleAndOrigin();
470 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
474 ComputeScaleAndOrigin();
477 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
479 m_deviceLocalOriginX
= x
;
480 m_deviceLocalOriginY
= y
;
481 ComputeScaleAndOrigin();
484 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
486 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
487 // wxWidgets 2.9: no longer override it
488 m_signX
= (xLeftRight
? 1 : -1);
489 m_signY
= (yBottomUp
? -1 : 1);
490 ComputeScaleAndOrigin();
494 // Each element of the widths array will be the width of the string up to and
495 // including the corresponding character in text. This is the generic
496 // implementation, the port-specific classes should do this with native APIs
497 // if available and if faster. Note: pango_layout_index_to_pos is much slower
498 // than calling GetTextExtent!!
505 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
506 ~FontWidthCache() { delete []m_widths
; }
511 m_widths
= new int[FWC_SIZE
];
513 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
521 static FontWidthCache s_fontWidthCache
;
523 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
527 const size_t len
= text
.length();
531 // reset the cache if font or horizontal scale have changed
532 if ( !s_fontWidthCache
.m_widths
||
533 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
534 (s_fontWidthCache
.m_font
!= GetFont()) )
536 s_fontWidthCache
.Reset();
537 s_fontWidthCache
.m_font
= GetFont();
538 s_fontWidthCache
.m_scaleX
= m_scaleX
;
541 // Calculate the position of each character based on the widths of
542 // the previous characters
544 for ( size_t i
= 0; i
< len
; i
++ )
546 const wxChar c
= text
[i
];
547 unsigned int c_int
= (unsigned int)c
;
549 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
551 w
= s_fontWidthCache
.m_widths
[c_int
];
555 DoGetTextExtent(c
, &w
, &h
);
556 if (c_int
< FWC_SIZE
)
557 s_fontWidthCache
.m_widths
[c_int
] = w
;
561 widths
[i
] = totalWidth
;
567 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
571 const wxFont
*font
) const
573 wxCoord widthTextMax
= 0, widthLine
,
574 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
577 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
579 if ( pc
== text
.end() || *pc
== wxT('\n') )
581 if ( curLine
.empty() )
583 // we can't use GetTextExtent - it will return 0 for both width
584 // and height and an empty line should count in height
587 // assume that this line has the same height as the previous
589 if ( !heightLineDefault
)
590 heightLineDefault
= heightLine
;
592 if ( !heightLineDefault
)
594 // but we don't know it yet - choose something reasonable
595 DoGetTextExtent(wxT("W"), NULL
, &heightLineDefault
,
599 heightTextTotal
+= heightLineDefault
;
603 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
605 if ( widthLine
> widthTextMax
)
606 widthTextMax
= widthLine
;
607 heightTextTotal
+= heightLine
;
610 if ( pc
== text
.end() )
628 *y
= heightTextTotal
;
633 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
634 wxCoord width
, wxCoord height
)
636 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
638 wxCoord x2
= x1
+ width
,
641 // the pen width is calibrated to give 3 for width == height == 10
642 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
644 // we're drawing a scaled version of wx/generic/tick.xpm here
645 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
646 y3
= y1
+ height
/ 2; // y of the left tick branch
647 DoDrawLine(x1
, y3
, x3
, y2
);
648 DoDrawLine(x3
, y2
, x2
, y1
);
650 CalcBoundingBox(x1
, y1
);
651 CalcBoundingBox(x2
, y2
);
655 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
656 wxCoord dstWidth
, wxCoord dstHeight
,
658 wxCoord xsrc
, wxCoord ysrc
,
659 wxCoord srcWidth
, wxCoord srcHeight
,
660 wxRasterOperationMode rop
,
665 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
666 wxT("invalid blit size") );
668 // emulate the stretching by modifying the DC scale
669 double xscale
= (double)srcWidth
/dstWidth
,
670 yscale
= (double)srcHeight
/dstHeight
;
672 double xscaleOld
, yscaleOld
;
673 GetUserScale(&xscaleOld
, &yscaleOld
);
674 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
676 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
677 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
679 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
681 SetUserScale(xscaleOld
, yscaleOld
);
686 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
688 int n
= list
->GetCount();
689 wxPoint
*points
= new wxPoint
[n
];
692 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
694 wxPoint
*point
= node
->GetData();
695 points
[i
].x
= point
->x
;
696 points
[i
].y
= point
->y
;
699 DoDrawLines(n
, points
, xoffset
, yoffset
);
704 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
705 wxCoord xoffset
, wxCoord yoffset
,
706 wxPolygonFillMode fillStyle
)
708 int n
= list
->GetCount();
709 wxPoint
*points
= new wxPoint
[n
];
712 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
714 wxPoint
*point
= node
->GetData();
715 points
[i
].x
= point
->x
;
716 points
[i
].y
= point
->y
;
719 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
725 wxDCImpl::DoDrawPolyPolygon(int n
,
728 wxCoord xoffset
, wxCoord yoffset
,
729 wxPolygonFillMode fillStyle
)
733 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
740 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
745 pts
= new wxPoint
[j
+n
-1];
746 for (i
= 0; i
< j
; i
++)
748 for (i
= 2; i
<= n
; i
++)
750 lastOfs
-= count
[n
-i
];
751 pts
[j
++] = pts
[lastOfs
];
755 wxDCPenChanger
setTransp(*m_owner
, *wxTRANSPARENT_PEN
);
756 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
759 for (i
= j
= 0; i
< n
; i
++)
761 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
769 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
770 wxCoord x2
, wxCoord y2
,
771 wxCoord x3
, wxCoord y3
)
773 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
774 DrawSpline(WXSIZEOF(points
), points
);
777 void wxDCImpl::DrawSpline(int n
, wxPoint points
[])
780 for ( int i
= 0; i
< n
; i
++ )
781 list
.Append(&points
[i
]);
786 // ----------------------------------- spline code ----------------------------------------
788 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
789 double a3
, double b3
, double a4
, double b4
);
790 void wx_clear_stack();
791 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
792 double *y3
, double *x4
, double *y4
);
793 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
794 double x4
, double y4
);
795 static bool wx_spline_add_point(double x
, double y
);
796 static void wx_spline_draw_point_array(wxDC
*dc
);
798 static wxPointList wx_spline_point_list
;
800 #define half(z1, z2) ((z1+z2)/2.0)
803 /* iterative version */
805 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
808 register double xmid
, ymid
;
809 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
812 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
814 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
815 xmid
= (double)half(x2
, x3
);
816 ymid
= (double)half(y2
, y3
);
817 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
818 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
819 wx_spline_add_point( x1
, y1
);
820 wx_spline_add_point( xmid
, ymid
);
822 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
823 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
824 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
825 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
830 /* utilities used by spline drawing routines */
832 typedef struct wx_spline_stack_struct
{
833 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
836 #define SPLINE_STACK_DEPTH 20
837 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
838 static Stack
*wx_stack_top
;
839 static int wx_stack_count
;
841 void wx_clear_stack()
843 wx_stack_top
= wx_spline_stack
;
847 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
849 wx_stack_top
->x1
= x1
;
850 wx_stack_top
->y1
= y1
;
851 wx_stack_top
->x2
= x2
;
852 wx_stack_top
->y2
= y2
;
853 wx_stack_top
->x3
= x3
;
854 wx_stack_top
->y3
= y3
;
855 wx_stack_top
->x4
= x4
;
856 wx_stack_top
->y4
= y4
;
861 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
862 double *x3
, double *y3
, double *x4
, double *y4
)
864 if (wx_stack_count
== 0)
868 *x1
= wx_stack_top
->x1
;
869 *y1
= wx_stack_top
->y1
;
870 *x2
= wx_stack_top
->x2
;
871 *y2
= wx_stack_top
->y2
;
872 *x3
= wx_stack_top
->x3
;
873 *y3
= wx_stack_top
->y3
;
874 *x4
= wx_stack_top
->x4
;
875 *y4
= wx_stack_top
->y4
;
879 static bool wx_spline_add_point(double x
, double y
)
881 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
882 wx_spline_point_list
.Append(point
);
886 static void wx_spline_draw_point_array(wxDC
*dc
)
888 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
889 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
892 wxPoint
*point
= node
->GetData();
894 wx_spline_point_list
.Erase(node
);
895 node
= wx_spline_point_list
.GetFirst();
899 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
901 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
904 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
905 double x1
, y1
, x2
, y2
;
907 wxPointList::compatibility_iterator node
= points
->GetFirst();
912 p
= (wxPoint
*)node
->GetData();
917 node
= node
->GetNext();
922 cx1
= (double)((x1
+ x2
) / 2);
923 cy1
= (double)((y1
+ y2
) / 2);
924 cx2
= (double)((cx1
+ x2
) / 2);
925 cy2
= (double)((cy1
+ y2
) / 2);
927 wx_spline_add_point(x1
, y1
);
929 while ((node
= node
->GetNext())
930 #if !wxUSE_STD_CONTAINERS
932 #endif // !wxUSE_STD_CONTAINERS
940 cx4
= (double)(x1
+ x2
) / 2;
941 cy4
= (double)(y1
+ y2
) / 2;
942 cx3
= (double)(x1
+ cx4
) / 2;
943 cy3
= (double)(y1
+ cy4
) / 2;
945 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
949 cx2
= (double)(cx1
+ x2
) / 2;
950 cy2
= (double)(cy1
+ y2
) / 2;
953 wx_spline_add_point( cx1
, cy1
);
954 wx_spline_add_point( x2
, y2
);
956 wx_spline_draw_point_array( m_owner
);
959 #endif // wxUSE_SPLINES
963 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
964 const wxColour
& initialColour
,
965 const wxColour
& destColour
,
966 wxDirection nDirection
)
969 wxPen oldPen
= m_pen
;
970 wxBrush oldBrush
= m_brush
;
972 wxUint8 nR1
= initialColour
.Red();
973 wxUint8 nG1
= initialColour
.Green();
974 wxUint8 nB1
= initialColour
.Blue();
975 wxUint8 nR2
= destColour
.Red();
976 wxUint8 nG2
= destColour
.Green();
977 wxUint8 nB2
= destColour
.Blue();
980 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
982 wxInt32 x
= rect
.GetWidth();
983 wxInt32 w
= x
; // width of area to shade
984 wxInt32 xDelta
= w
/256; // height of one shade bend
992 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
994 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
997 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
999 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1002 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1004 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1006 wxColour
colour(nR
,nG
,nB
);
1007 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1008 SetBrush(wxBrush(colour
));
1009 if(nDirection
== wxEAST
)
1010 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1011 xDelta
, rect
.GetHeight());
1012 else //nDirection == wxWEST
1013 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1014 xDelta
, rect
.GetHeight());
1017 else // nDirection == wxNORTH || nDirection == wxSOUTH
1019 wxInt32 y
= rect
.GetHeight();
1020 wxInt32 w
= y
; // height of area to shade
1021 wxInt32 yDelta
= w
/255; // height of one shade bend
1029 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1031 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1034 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1036 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1039 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1041 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1043 wxColour
colour(nR
,nG
,nB
);
1044 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1045 SetBrush(wxBrush(colour
));
1046 if(nDirection
== wxNORTH
)
1047 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1048 rect
.GetWidth(), yDelta
);
1049 else //nDirection == wxSOUTH
1050 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1051 rect
.GetWidth(), yDelta
);
1059 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1060 const wxColour
& initialColour
,
1061 const wxColour
& destColour
,
1062 const wxPoint
& circleCenter
)
1064 // save the old pen and ensure it is restored on exit
1065 const wxPen penOrig
= m_pen
;
1066 wxON_BLOCK_EXIT_SET(m_pen
, penOrig
);
1068 wxUint8 nR1
= destColour
.Red();
1069 wxUint8 nG1
= destColour
.Green();
1070 wxUint8 nB1
= destColour
.Blue();
1071 wxUint8 nR2
= initialColour
.Red();
1072 wxUint8 nG2
= initialColour
.Green();
1073 wxUint8 nB2
= initialColour
.Blue();
1078 double cx
= rect
.GetWidth() / 2;
1079 double cy
= rect
.GetHeight() / 2;
1088 ptX
= circleCenter
.x
;
1089 ptY
= circleCenter
.y
;
1090 double nCircleOffX
= ptX
- cx
;
1091 double nCircleOffY
= ptY
- cy
;
1096 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1098 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1100 //get color difference
1104 dGradient
= ((dRadius
- sqrt( (dx
- cx
- nCircleOffX
) * (dx
- cx
- nCircleOffX
)
1105 +(dy
- cy
- nCircleOffY
) * (dy
- cy
- nCircleOffY
)
1110 //normalize Gradient
1115 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * dGradient
/ 100));
1116 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * dGradient
/ 100));
1117 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * dGradient
/ 100));
1120 SetPen(wxColour(nR
,nG
,nB
));
1121 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1126 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1128 wxCHECK_RET( win
, "window can't be NULL" );
1130 SetFont(win
->GetFont());
1131 SetTextForeground(win
->GetForegroundColour());
1132 SetTextBackground(win
->GetBackgroundColour());
1133 SetBackground(win
->GetBackgroundColour());
1134 SetLayoutDirection(win
->GetLayoutDirection());
1137 void wxDCImpl::DoGetFontMetrics(int *height
,
1140 int *internalLeading
,
1141 int *externalLeading
,
1142 int *averageWidth
) const
1144 // Average width is typically the same as width of 'x'.
1146 DoGetTextExtent("x", averageWidth
, &h
, &d
, externalLeading
);
1154 if ( internalLeading
)
1155 *internalLeading
= 0;
1158 //-----------------------------------------------------------------------------
1160 //-----------------------------------------------------------------------------
1162 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1164 void wxDC::CopyAttributes(const wxDC
& dc
)
1166 SetFont(dc
.GetFont());
1167 SetTextForeground(dc
.GetTextForeground());
1168 SetTextBackground(dc
.GetTextBackground());
1169 SetBackground(dc
.GetBackground());
1170 SetLayoutDirection(dc
.GetLayoutDirection());
1173 void wxDC::DrawLabel(const wxString
& text
,
1174 const wxBitmap
& bitmap
,
1178 wxRect
*rectBounding
)
1180 // find the text position
1181 wxCoord widthText
, heightText
, heightLine
;
1182 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1184 wxCoord width
, height
;
1187 width
= widthText
+ bitmap
.GetWidth();
1188 height
= bitmap
.GetHeight();
1193 height
= heightText
;
1197 if ( alignment
& wxALIGN_RIGHT
)
1199 x
= rect
.GetRight() - width
;
1201 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1203 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1205 else // alignment & wxALIGN_LEFT
1210 if ( alignment
& wxALIGN_BOTTOM
)
1212 y
= rect
.GetBottom() - height
;
1214 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1216 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1218 else // alignment & wxALIGN_TOP
1223 // draw the bitmap first
1229 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1231 wxCoord offset
= bitmap
.GetWidth() + 4;
1235 y
+= (height
- heightText
) / 2;
1238 // we will draw the underscore under the accel char later
1239 wxCoord startUnderscore
= 0,
1243 // split the string into lines and draw each of them separately
1245 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1246 // strings natively, this is not the case for all of them, notably not
1247 // wxMSW which uses this function for multi-line texts, so we may only
1248 // call DrawText() for single-line strings from here to avoid infinite
1251 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1253 if ( pc
== text
.end() || *pc
== '\n' )
1255 int xRealStart
= x
; // init it here to avoid compielr warnings
1257 if ( !curLine
.empty() )
1259 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1260 // wxALIGN_LEFT is 0
1261 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1264 GetTextExtent(curLine
, &widthLine
, NULL
);
1266 if ( alignment
& wxALIGN_RIGHT
)
1268 xRealStart
+= width
- widthLine
;
1270 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1272 xRealStart
+= (width
- widthLine
) / 2;
1275 //else: left aligned, nothing to do
1277 DrawText(curLine
, xRealStart
, y
);
1282 // do we have underscore in this line? we can check yUnderscore
1283 // because it is set below to just y + heightLine if we do
1284 if ( y
== yUnderscore
)
1286 // adjust the horz positions to account for the shift
1287 startUnderscore
+= xRealStart
;
1288 endUnderscore
+= xRealStart
;
1291 if ( pc
== text
.end() )
1296 else // not end of line
1298 if ( pc
- text
.begin() == indexAccel
)
1300 // remeber to draw underscore here
1301 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1303 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1305 yUnderscore
= y
+ heightLine
;
1314 // draw the underscore if found
1315 if ( startUnderscore
!= endUnderscore
)
1317 // it should be of the same colour as text
1318 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1320 // This adjustment is relatively arbitrary: we need to draw the
1321 // underline slightly higher to avoid overflowing the character cell
1322 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1324 // The currently used value seems to be compatible with native MSW
1325 // behaviour, i.e. it results in the same appearance of the owner-drawn
1326 // and normal labels.
1329 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1332 // return bounding rect if requested
1335 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1338 CalcBoundingBox(x0
, y0
);
1339 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1342 #if WXWIN_COMPATIBILITY_2_8
1343 // for compatibility with the old code when wxCoord was long everywhere
1344 void wxDC::GetTextExtent(const wxString
& string
,
1347 long *externalLeading
,
1348 const wxFont
*theFont
) const
1350 wxCoord x2
, y2
, descent2
, externalLeading2
;
1351 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1352 &descent2
, &externalLeading2
,
1359 *descent
= descent2
;
1360 if ( externalLeading
)
1361 *externalLeading
= externalLeading2
;
1364 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1367 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1374 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1377 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1384 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1386 wxCoord xx
,yy
,ww
,hh
;
1387 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1394 void wxDC::DrawObject(wxDrawObject
* drawobject
)
1396 drawobject
->Draw(*this);
1397 CalcBoundingBox(drawobject
->MinX(),drawobject
->MinY());
1398 CalcBoundingBox(drawobject
->MaxX(),drawobject
->MaxY());
1401 #endif // WXWIN_COMPATIBILITY_2_8
1404 Notes for wxWidgets DrawEllipticArcRot(...)
1406 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1407 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1410 All methods are generic, so they can be implemented in wxDCBase.
1411 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1412 methods like (WinCE) wxDC::DoDrawArc(...).
1414 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1415 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1416 parts) or every column (in steep parts) only one pixel is calculated.
1417 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1418 starting angle is not equal to the ending angle. The calculation of the
1419 pixels is done using simple arithmetic only and should perform not too
1420 bad even on devices without floating point processor. I didn't test this yet.
1422 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1423 For instance: an ellipse rotated 180 degrees is drawn
1424 slightly different from the original.
1426 The points are then moved to an array and used to draw a polyline and/or polygon
1427 (with center added, the pie).
1428 The result looks quite similar to the native ellipse, only e few pixels differ.
1430 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1431 slower as DrawEllipse(...), which calls the native API.
1432 An rotated ellipse outside the clipping region takes nearly the same time,
1433 while an native ellipse outside takes nearly no time to draw.
1435 If you draw an arc with this new method, you will see the starting and ending angles
1436 are calculated properly.
1437 If you use DrawEllipticArc(...), you will see they are only correct for circles
1438 and not properly calculated for ellipses.
1441 p.lenhard@t-online.de
1445 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1446 wxCoord w
, wxCoord h
,
1447 double sa
, double ea
, double angle
)
1451 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1452 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1454 // Add center (for polygon/pie)
1455 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1457 // copy list into array and delete list elements
1458 int n
= list
.GetCount();
1459 wxPoint
*points
= new wxPoint
[n
];
1461 wxPointList::compatibility_iterator node
;
1462 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1464 wxPoint
*point
= node
->GetData();
1465 points
[i
].x
= point
->x
;
1466 points
[i
].y
= point
->y
;
1470 // first draw the pie without pen, if necessary
1471 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1473 wxPen
tempPen( GetPen() );
1474 SetPen( *wxTRANSPARENT_PEN
);
1475 DoDrawPolygon( n
, points
, 0, 0 );
1479 // then draw the arc without brush, if necessary
1480 if( GetPen() != *wxTRANSPARENT_PEN
)
1483 DoDrawLines( n
-1, points
, 0, 0 );
1488 } // DrawEllipticArcRot
1490 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1495 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1496 double dCosA
= cos(angle
*2.0*pi
/360.0);
1497 wxPointList::compatibility_iterator node
;
1498 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1500 wxPoint
* point
= node
->GetData();
1502 // transform coordinates, if necessary
1503 if( center
.x
) point
->x
-= center
.x
;
1504 if( center
.y
) point
->y
-= center
.y
;
1506 // calculate rotation, rounding simply by implicit cast to integer
1507 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1508 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1511 // back transform coordinates, if necessary
1512 if( center
.x
) point
->x
+= center
.x
;
1513 if( center
.y
) point
->y
+= center
.y
;
1518 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1519 wxCoord xStart
, wxCoord yStart
,
1520 wxCoord w
, wxCoord h
,
1521 double sa
, double ea
)
1532 bool bUseAngles
= false;
1538 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1540 if( 2*a
== w
) decrX
= 1;
1542 if( 2*b
== h
) decrY
= 1;
1544 wxCoord xCenter
= xStart
+ a
;
1545 wxCoord yCenter
= yStart
+ b
;
1546 // calculate data for start and end, if necessary
1550 // normalisation of angles
1551 while( sa
<0 ) sa
+= 360;
1552 while( ea
<0 ) ea
+= 360;
1553 while( sa
>=360 ) sa
-= 360;
1554 while( ea
>=360 ) ea
-= 360;
1555 // calculate quadrant numbers
1556 if( sa
> 270 ) sq
= 3;
1557 else if( sa
> 180 ) sq
= 2;
1558 else if( sa
> 90 ) sq
= 1;
1559 if( ea
> 270 ) eq
= 3;
1560 else if( ea
> 180 ) eq
= 2;
1561 else if( ea
> 90 ) eq
= 1;
1562 sar
= sa
* pi
/ 180.0;
1563 ear
= ea
* pi
/ 180.0;
1564 // correct angle circle -> ellipse
1565 sar
= atan( -a
/(double)b
* tan( sar
) );
1566 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1567 ear
= atan( -a
/(double)b
* tan( ear
) );
1568 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1569 // coordinates of points
1570 xsa
= xCenter
+ a
* cos( sar
);
1571 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1572 ysa
= yCenter
+ b
* sin( sar
);
1573 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1574 xea
= xCenter
+ a
* cos( ear
);
1575 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1576 yea
= yCenter
+ b
* sin( ear
);
1577 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1579 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1581 double c2
= 2.0 / w
;
1590 // Lists for quadrant 1 to 4
1591 wxPointList pointsarray
[4];
1592 // Calculate points for first quadrant and set in all quadrants
1593 for( x
= 0; x
<= a
; ++x
)
1598 bool bNewPoint
= false;
1599 while( y2
> c1
- c2
* x2
&& y
> 0 )
1605 // old y now too big: set point with old y, old x
1606 if( bNewPoint
&& x
>1)
1609 // remove points on the same line
1610 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1611 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1612 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1613 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1615 } // calculate point
1617 // Starting and/or ending points for the quadrants, first quadrant gets both.
1618 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1619 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1620 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1621 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1622 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1624 // copy quadrants in original list
1627 // Copy the right part of the points in the lists
1628 // and delete the wxPoints, because they do not leave this method.
1629 points
->Append( new wxPoint( xsa
, ysa
) );
1631 bool bStarted
= false;
1632 bool bReady
= false;
1633 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1636 wxPointList::compatibility_iterator node
;
1637 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1639 // once: go to starting point in start quadrant
1642 node
->GetData()->x
< xsa
+1 && q
<= 1
1644 node
->GetData()->x
> xsa
-1 && q
>= 2
1651 // copy point, if not at ending point
1654 if( q
!= eq
|| bForceTurn
1656 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1658 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1662 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1663 points
->Append( pPoint
);
1665 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1675 } // while not bReady
1676 points
->Append( new wxPoint( xea
, yea
) );
1679 for( q
= 0; q
< 4; ++q
)
1681 wxPointList::compatibility_iterator node
;
1682 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1684 wxPoint
*p
= node
->GetData();
1691 wxPointList::compatibility_iterator node
;
1692 // copy whole ellipse, wxPoints will be deleted outside
1693 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1695 wxPoint
*p
= node
->GetData();
1696 points
->Append( p
);
1698 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1700 wxPoint
*p
= node
->GetData();
1701 points
->Append( p
);
1703 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1705 wxPoint
*p
= node
->GetData();
1706 points
->Append( p
);
1708 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1710 wxPoint
*p
= node
->GetData();
1711 points
->Append( p
);
1714 } // CalculateEllipticPoints
1716 #endif // __WXWINCE__
1718 float wxDCImpl::GetFontPointSizeAdjustment(float dpi
)
1720 // wxMSW has long-standing bug where wxFont point size is interpreted as
1721 // "pixel size corresponding to given point size *on screen*". In other
1722 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1723 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1724 // that *all* printing code has to account for it and consequently, other
1725 // ports need to emulate this bug too:
1726 const wxSize screenPPI
= wxGetDisplayPPI();
1727 return float(screenPPI
.y
) / dpi
;