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 // ----------------------------------------------------------------------------
371 // coordinate conversions and transforms
372 // ----------------------------------------------------------------------------
374 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
376 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
379 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
381 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
384 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
386 return wxRound((double)(x
) / m_scaleX
);
389 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
391 return wxRound((double)(y
) / m_scaleY
);
394 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
396 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
399 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
401 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
404 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
406 return wxRound((double)(x
) * m_scaleX
);
409 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
411 return wxRound((double)(y
) * m_scaleY
);
414 void wxDCImpl::ComputeScaleAndOrigin()
416 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
417 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
420 void wxDCImpl::SetMapMode( wxMappingMode mode
)
425 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
428 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
431 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
434 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
438 SetLogicalScale( 1.0, 1.0 );
441 m_mappingMode
= mode
;
444 void wxDCImpl::SetUserScale( double x
, double y
)
446 // allow negative ? -> no
449 ComputeScaleAndOrigin();
452 void wxDCImpl::SetLogicalScale( double x
, double y
)
457 ComputeScaleAndOrigin();
460 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
462 m_logicalOriginX
= x
* m_signX
;
463 m_logicalOriginY
= y
* m_signY
;
464 ComputeScaleAndOrigin();
467 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
471 ComputeScaleAndOrigin();
474 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
476 m_deviceLocalOriginX
= x
;
477 m_deviceLocalOriginY
= y
;
478 ComputeScaleAndOrigin();
481 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
483 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
484 // wxWidgets 2.9: no longer override it
485 m_signX
= (xLeftRight
? 1 : -1);
486 m_signY
= (yBottomUp
? -1 : 1);
487 ComputeScaleAndOrigin();
491 // Each element of the widths array will be the width of the string up to and
492 // including the corresponding character in text. This is the generic
493 // implementation, the port-specific classes should do this with native APIs
494 // if available and if faster. Note: pango_layout_index_to_pos is much slower
495 // than calling GetTextExtent!!
502 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
503 ~FontWidthCache() { delete []m_widths
; }
508 m_widths
= new int[FWC_SIZE
];
510 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
518 static FontWidthCache s_fontWidthCache
;
520 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
524 const size_t len
= text
.length();
528 // reset the cache if font or horizontal scale have changed
529 if ( !s_fontWidthCache
.m_widths
||
530 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
531 (s_fontWidthCache
.m_font
!= GetFont()) )
533 s_fontWidthCache
.Reset();
534 s_fontWidthCache
.m_font
= GetFont();
535 s_fontWidthCache
.m_scaleX
= m_scaleX
;
538 // Calculate the position of each character based on the widths of
539 // the previous characters
541 for ( size_t i
= 0; i
< len
; i
++ )
543 const wxChar c
= text
[i
];
544 unsigned int c_int
= (unsigned int)c
;
546 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
548 w
= s_fontWidthCache
.m_widths
[c_int
];
552 DoGetTextExtent(c
, &w
, &h
);
553 if (c_int
< FWC_SIZE
)
554 s_fontWidthCache
.m_widths
[c_int
] = w
;
558 widths
[i
] = totalWidth
;
564 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
568 const wxFont
*font
) const
570 wxCoord widthTextMax
= 0, widthLine
,
571 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
574 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
576 if ( pc
== text
.end() || *pc
== wxT('\n') )
578 if ( curLine
.empty() )
580 // we can't use GetTextExtent - it will return 0 for both width
581 // and height and an empty line should count in height
584 // assume that this line has the same height as the previous
586 if ( !heightLineDefault
)
587 heightLineDefault
= heightLine
;
589 if ( !heightLineDefault
)
591 // but we don't know it yet - choose something reasonable
592 DoGetTextExtent(wxT("W"), NULL
, &heightLineDefault
,
596 heightTextTotal
+= heightLineDefault
;
600 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
602 if ( widthLine
> widthTextMax
)
603 widthTextMax
= widthLine
;
604 heightTextTotal
+= heightLine
;
607 if ( pc
== text
.end() )
625 *y
= heightTextTotal
;
630 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
631 wxCoord width
, wxCoord height
)
633 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
635 wxCoord x2
= x1
+ width
,
638 // the pen width is calibrated to give 3 for width == height == 10
639 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
641 // we're drawing a scaled version of wx/generic/tick.xpm here
642 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
643 y3
= y1
+ height
/ 2; // y of the left tick branch
644 DoDrawLine(x1
, y3
, x3
, y2
);
645 DoDrawLine(x3
, y2
, x2
, y1
);
647 CalcBoundingBox(x1
, y1
);
648 CalcBoundingBox(x2
, y2
);
652 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
653 wxCoord dstWidth
, wxCoord dstHeight
,
655 wxCoord xsrc
, wxCoord ysrc
,
656 wxCoord srcWidth
, wxCoord srcHeight
,
657 wxRasterOperationMode rop
,
662 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
663 wxT("invalid blit size") );
665 // emulate the stretching by modifying the DC scale
666 double xscale
= (double)srcWidth
/dstWidth
,
667 yscale
= (double)srcHeight
/dstHeight
;
669 double xscaleOld
, yscaleOld
;
670 GetUserScale(&xscaleOld
, &yscaleOld
);
671 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
673 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
674 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
676 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
678 SetUserScale(xscaleOld
, yscaleOld
);
683 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
685 int n
= list
->GetCount();
686 wxPoint
*points
= new wxPoint
[n
];
689 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
691 wxPoint
*point
= node
->GetData();
692 points
[i
].x
= point
->x
;
693 points
[i
].y
= point
->y
;
696 DoDrawLines(n
, points
, xoffset
, yoffset
);
701 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
702 wxCoord xoffset
, wxCoord yoffset
,
703 wxPolygonFillMode fillStyle
)
705 int n
= list
->GetCount();
706 wxPoint
*points
= new wxPoint
[n
];
709 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
711 wxPoint
*point
= node
->GetData();
712 points
[i
].x
= point
->x
;
713 points
[i
].y
= point
->y
;
716 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
722 wxDCImpl::DoDrawPolyPolygon(int n
,
725 wxCoord xoffset
, wxCoord yoffset
,
726 wxPolygonFillMode fillStyle
)
730 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
737 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
742 pts
= new wxPoint
[j
+n
-1];
743 for (i
= 0; i
< j
; i
++)
745 for (i
= 2; i
<= n
; i
++)
747 lastOfs
-= count
[n
-i
];
748 pts
[j
++] = pts
[lastOfs
];
752 wxDCPenChanger
setTransp(*m_owner
, *wxTRANSPARENT_PEN
);
753 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
756 for (i
= j
= 0; i
< n
; i
++)
758 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
766 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
767 wxCoord x2
, wxCoord y2
,
768 wxCoord x3
, wxCoord y3
)
770 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
771 DrawSpline(WXSIZEOF(points
), points
);
774 void wxDCImpl::DrawSpline(int n
, wxPoint points
[])
777 for ( int i
= 0; i
< n
; i
++ )
778 list
.Append(&points
[i
]);
783 // ----------------------------------- spline code ----------------------------------------
785 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
786 double a3
, double b3
, double a4
, double b4
);
787 void wx_clear_stack();
788 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
789 double *y3
, double *x4
, double *y4
);
790 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
791 double x4
, double y4
);
792 static bool wx_spline_add_point(double x
, double y
);
793 static void wx_spline_draw_point_array(wxDC
*dc
);
795 static wxPointList wx_spline_point_list
;
797 #define half(z1, z2) ((z1+z2)/2.0)
800 /* iterative version */
802 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
805 register double xmid
, ymid
;
806 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
809 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
811 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
812 xmid
= (double)half(x2
, x3
);
813 ymid
= (double)half(y2
, y3
);
814 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
815 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
816 wx_spline_add_point( x1
, y1
);
817 wx_spline_add_point( xmid
, ymid
);
819 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
820 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
821 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
822 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
827 /* utilities used by spline drawing routines */
829 typedef struct wx_spline_stack_struct
{
830 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
833 #define SPLINE_STACK_DEPTH 20
834 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
835 static Stack
*wx_stack_top
;
836 static int wx_stack_count
;
838 void wx_clear_stack()
840 wx_stack_top
= wx_spline_stack
;
844 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
846 wx_stack_top
->x1
= x1
;
847 wx_stack_top
->y1
= y1
;
848 wx_stack_top
->x2
= x2
;
849 wx_stack_top
->y2
= y2
;
850 wx_stack_top
->x3
= x3
;
851 wx_stack_top
->y3
= y3
;
852 wx_stack_top
->x4
= x4
;
853 wx_stack_top
->y4
= y4
;
858 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
859 double *x3
, double *y3
, double *x4
, double *y4
)
861 if (wx_stack_count
== 0)
865 *x1
= wx_stack_top
->x1
;
866 *y1
= wx_stack_top
->y1
;
867 *x2
= wx_stack_top
->x2
;
868 *y2
= wx_stack_top
->y2
;
869 *x3
= wx_stack_top
->x3
;
870 *y3
= wx_stack_top
->y3
;
871 *x4
= wx_stack_top
->x4
;
872 *y4
= wx_stack_top
->y4
;
876 static bool wx_spline_add_point(double x
, double y
)
878 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
879 wx_spline_point_list
.Append(point
);
883 static void wx_spline_draw_point_array(wxDC
*dc
)
885 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
886 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
889 wxPoint
*point
= node
->GetData();
891 wx_spline_point_list
.Erase(node
);
892 node
= wx_spline_point_list
.GetFirst();
896 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
898 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
901 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
902 double x1
, y1
, x2
, y2
;
904 wxPointList::compatibility_iterator node
= points
->GetFirst();
909 p
= (wxPoint
*)node
->GetData();
914 node
= node
->GetNext();
919 cx1
= (double)((x1
+ x2
) / 2);
920 cy1
= (double)((y1
+ y2
) / 2);
921 cx2
= (double)((cx1
+ x2
) / 2);
922 cy2
= (double)((cy1
+ y2
) / 2);
924 wx_spline_add_point(x1
, y1
);
926 while ((node
= node
->GetNext())
927 #if !wxUSE_STD_CONTAINERS
929 #endif // !wxUSE_STD_CONTAINERS
937 cx4
= (double)(x1
+ x2
) / 2;
938 cy4
= (double)(y1
+ y2
) / 2;
939 cx3
= (double)(x1
+ cx4
) / 2;
940 cy3
= (double)(y1
+ cy4
) / 2;
942 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
946 cx2
= (double)(cx1
+ x2
) / 2;
947 cy2
= (double)(cy1
+ y2
) / 2;
950 wx_spline_add_point( cx1
, cy1
);
951 wx_spline_add_point( x2
, y2
);
953 wx_spline_draw_point_array( m_owner
);
956 #endif // wxUSE_SPLINES
960 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
961 const wxColour
& initialColour
,
962 const wxColour
& destColour
,
963 wxDirection nDirection
)
966 wxPen oldPen
= m_pen
;
967 wxBrush oldBrush
= m_brush
;
969 wxUint8 nR1
= initialColour
.Red();
970 wxUint8 nG1
= initialColour
.Green();
971 wxUint8 nB1
= initialColour
.Blue();
972 wxUint8 nR2
= destColour
.Red();
973 wxUint8 nG2
= destColour
.Green();
974 wxUint8 nB2
= destColour
.Blue();
977 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
979 wxInt32 x
= rect
.GetWidth();
980 wxInt32 w
= x
; // width of area to shade
981 wxInt32 xDelta
= w
/256; // height of one shade bend
989 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
991 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
994 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
996 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
999 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1001 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1003 wxColour
colour(nR
,nG
,nB
);
1004 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1005 SetBrush(wxBrush(colour
));
1006 if(nDirection
== wxEAST
)
1007 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1008 xDelta
, rect
.GetHeight());
1009 else //nDirection == wxWEST
1010 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1011 xDelta
, rect
.GetHeight());
1014 else // nDirection == wxNORTH || nDirection == wxSOUTH
1016 wxInt32 y
= rect
.GetHeight();
1017 wxInt32 w
= y
; // height of area to shade
1018 wxInt32 yDelta
= w
/255; // height of one shade bend
1026 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1028 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1031 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1033 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1036 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1038 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1040 wxColour
colour(nR
,nG
,nB
);
1041 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1042 SetBrush(wxBrush(colour
));
1043 if(nDirection
== wxNORTH
)
1044 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1045 rect
.GetWidth(), yDelta
);
1046 else //nDirection == wxSOUTH
1047 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1048 rect
.GetWidth(), yDelta
);
1056 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1057 const wxColour
& initialColour
,
1058 const wxColour
& destColour
,
1059 const wxPoint
& circleCenter
)
1061 // save the old pen and ensure it is restored on exit
1062 const wxPen penOrig
= m_pen
;
1063 wxON_BLOCK_EXIT_SET(m_pen
, penOrig
);
1065 wxUint8 nR1
= destColour
.Red();
1066 wxUint8 nG1
= destColour
.Green();
1067 wxUint8 nB1
= destColour
.Blue();
1068 wxUint8 nR2
= initialColour
.Red();
1069 wxUint8 nG2
= initialColour
.Green();
1070 wxUint8 nB2
= initialColour
.Blue();
1075 double cx
= rect
.GetWidth() / 2;
1076 double cy
= rect
.GetHeight() / 2;
1085 ptX
= circleCenter
.x
;
1086 ptY
= circleCenter
.y
;
1087 double nCircleOffX
= ptX
- cx
;
1088 double nCircleOffY
= ptY
- cy
;
1093 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1095 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1097 //get color difference
1101 dGradient
= ((dRadius
- sqrt( (dx
- cx
- nCircleOffX
) * (dx
- cx
- nCircleOffX
)
1102 +(dy
- cy
- nCircleOffY
) * (dy
- cy
- nCircleOffY
)
1107 //normalize Gradient
1112 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * dGradient
/ 100));
1113 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * dGradient
/ 100));
1114 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * dGradient
/ 100));
1117 SetPen(wxColour(nR
,nG
,nB
));
1118 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1123 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1125 wxCHECK_RET( win
, "window can't be NULL" );
1127 SetFont(win
->GetFont());
1128 SetTextForeground(win
->GetForegroundColour());
1129 SetTextBackground(win
->GetBackgroundColour());
1130 SetBackground(win
->GetBackgroundColour());
1131 SetLayoutDirection(win
->GetLayoutDirection());
1134 void wxDCImpl::DoGetFontMetrics(int *height
,
1137 int *internalLeading
,
1138 int *externalLeading
,
1139 int *averageWidth
) const
1141 // Average width is typically the same as width of 'x'.
1143 DoGetTextExtent("x", averageWidth
, &h
, &d
, externalLeading
);
1151 if ( internalLeading
)
1152 *internalLeading
= 0;
1155 //-----------------------------------------------------------------------------
1157 //-----------------------------------------------------------------------------
1159 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1161 void wxDC::CopyAttributes(const wxDC
& dc
)
1163 SetFont(dc
.GetFont());
1164 SetTextForeground(dc
.GetTextForeground());
1165 SetTextBackground(dc
.GetTextBackground());
1166 SetBackground(dc
.GetBackground());
1167 SetLayoutDirection(dc
.GetLayoutDirection());
1170 void wxDC::DrawLabel(const wxString
& text
,
1171 const wxBitmap
& bitmap
,
1175 wxRect
*rectBounding
)
1177 // find the text position
1178 wxCoord widthText
, heightText
, heightLine
;
1179 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1181 wxCoord width
, height
;
1182 if ( bitmap
.IsOk() )
1184 width
= widthText
+ bitmap
.GetWidth();
1185 height
= bitmap
.GetHeight();
1190 height
= heightText
;
1194 if ( alignment
& wxALIGN_RIGHT
)
1196 x
= rect
.GetRight() - width
;
1198 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1200 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1202 else // alignment & wxALIGN_LEFT
1207 if ( alignment
& wxALIGN_BOTTOM
)
1209 y
= rect
.GetBottom() - height
;
1211 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1213 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1215 else // alignment & wxALIGN_TOP
1220 // draw the bitmap first
1224 if ( bitmap
.IsOk() )
1226 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1228 wxCoord offset
= bitmap
.GetWidth() + 4;
1232 y
+= (height
- heightText
) / 2;
1235 // we will draw the underscore under the accel char later
1236 wxCoord startUnderscore
= 0,
1240 // split the string into lines and draw each of them separately
1242 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1243 // strings natively, this is not the case for all of them, notably not
1244 // wxMSW which uses this function for multi-line texts, so we may only
1245 // call DrawText() for single-line strings from here to avoid infinite
1248 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1250 if ( pc
== text
.end() || *pc
== '\n' )
1252 int xRealStart
= x
; // init it here to avoid compielr warnings
1254 if ( !curLine
.empty() )
1256 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1257 // wxALIGN_LEFT is 0
1258 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1261 GetTextExtent(curLine
, &widthLine
, NULL
);
1263 if ( alignment
& wxALIGN_RIGHT
)
1265 xRealStart
+= width
- widthLine
;
1267 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1269 xRealStart
+= (width
- widthLine
) / 2;
1272 //else: left aligned, nothing to do
1274 DrawText(curLine
, xRealStart
, y
);
1279 // do we have underscore in this line? we can check yUnderscore
1280 // because it is set below to just y + heightLine if we do
1281 if ( y
== yUnderscore
)
1283 // adjust the horz positions to account for the shift
1284 startUnderscore
+= xRealStart
;
1285 endUnderscore
+= xRealStart
;
1288 if ( pc
== text
.end() )
1293 else // not end of line
1295 if ( pc
- text
.begin() == indexAccel
)
1297 // remember to draw underscore here
1298 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1300 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1302 yUnderscore
= y
+ heightLine
;
1311 // draw the underscore if found
1312 if ( startUnderscore
!= endUnderscore
)
1314 // it should be of the same colour as text
1315 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1317 // This adjustment is relatively arbitrary: we need to draw the
1318 // underline slightly higher to avoid overflowing the character cell
1319 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1321 // The currently used value seems to be compatible with native MSW
1322 // behaviour, i.e. it results in the same appearance of the owner-drawn
1323 // and normal labels.
1326 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1329 // return bounding rect if requested
1332 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1335 CalcBoundingBox(x0
, y0
);
1336 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1339 #if WXWIN_COMPATIBILITY_2_8
1340 // for compatibility with the old code when wxCoord was long everywhere
1341 void wxDC::GetTextExtent(const wxString
& string
,
1344 long *externalLeading
,
1345 const wxFont
*theFont
) const
1347 wxCoord x2
, y2
, descent2
, externalLeading2
;
1348 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1349 &descent2
, &externalLeading2
,
1356 *descent
= descent2
;
1357 if ( externalLeading
)
1358 *externalLeading
= externalLeading2
;
1361 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1364 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1371 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1374 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1381 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1383 wxCoord xx
,yy
,ww
,hh
;
1384 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1391 void wxDC::DrawObject(wxDrawObject
* drawobject
)
1393 drawobject
->Draw(*this);
1394 CalcBoundingBox(drawobject
->MinX(),drawobject
->MinY());
1395 CalcBoundingBox(drawobject
->MaxX(),drawobject
->MaxY());
1398 #endif // WXWIN_COMPATIBILITY_2_8
1401 Notes for wxWidgets DrawEllipticArcRot(...)
1403 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1404 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1407 All methods are generic, so they can be implemented in wxDCBase.
1408 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1409 methods like (WinCE) wxDC::DoDrawArc(...).
1411 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1412 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1413 parts) or every column (in steep parts) only one pixel is calculated.
1414 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1415 starting angle is not equal to the ending angle. The calculation of the
1416 pixels is done using simple arithmetic only and should perform not too
1417 bad even on devices without floating point processor. I didn't test this yet.
1419 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1420 For instance: an ellipse rotated 180 degrees is drawn
1421 slightly different from the original.
1423 The points are then moved to an array and used to draw a polyline and/or polygon
1424 (with center added, the pie).
1425 The result looks quite similar to the native ellipse, only e few pixels differ.
1427 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1428 slower as DrawEllipse(...), which calls the native API.
1429 An rotated ellipse outside the clipping region takes nearly the same time,
1430 while an native ellipse outside takes nearly no time to draw.
1432 If you draw an arc with this new method, you will see the starting and ending angles
1433 are calculated properly.
1434 If you use DrawEllipticArc(...), you will see they are only correct for circles
1435 and not properly calculated for ellipses.
1438 p.lenhard@t-online.de
1442 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1443 wxCoord w
, wxCoord h
,
1444 double sa
, double ea
, double angle
)
1448 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1449 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1451 // Add center (for polygon/pie)
1452 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1454 // copy list into array and delete list elements
1455 int n
= list
.GetCount();
1456 wxPoint
*points
= new wxPoint
[n
];
1458 wxPointList::compatibility_iterator node
;
1459 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1461 wxPoint
*point
= node
->GetData();
1462 points
[i
].x
= point
->x
;
1463 points
[i
].y
= point
->y
;
1467 // first draw the pie without pen, if necessary
1468 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1470 wxPen
tempPen( GetPen() );
1471 SetPen( *wxTRANSPARENT_PEN
);
1472 DoDrawPolygon( n
, points
, 0, 0 );
1476 // then draw the arc without brush, if necessary
1477 if( GetPen() != *wxTRANSPARENT_PEN
)
1480 DoDrawLines( n
-1, points
, 0, 0 );
1485 } // DrawEllipticArcRot
1487 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1492 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1493 double dCosA
= cos(angle
*2.0*pi
/360.0);
1494 wxPointList::compatibility_iterator node
;
1495 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1497 wxPoint
* point
= node
->GetData();
1499 // transform coordinates, if necessary
1500 if( center
.x
) point
->x
-= center
.x
;
1501 if( center
.y
) point
->y
-= center
.y
;
1503 // calculate rotation, rounding simply by implicit cast to integer
1504 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1505 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1508 // back transform coordinates, if necessary
1509 if( center
.x
) point
->x
+= center
.x
;
1510 if( center
.y
) point
->y
+= center
.y
;
1515 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1516 wxCoord xStart
, wxCoord yStart
,
1517 wxCoord w
, wxCoord h
,
1518 double sa
, double ea
)
1529 bool bUseAngles
= false;
1535 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1537 if( 2*a
== w
) decrX
= 1;
1539 if( 2*b
== h
) decrY
= 1;
1541 wxCoord xCenter
= xStart
+ a
;
1542 wxCoord yCenter
= yStart
+ b
;
1543 // calculate data for start and end, if necessary
1547 // normalisation of angles
1548 while( sa
<0 ) sa
+= 360;
1549 while( ea
<0 ) ea
+= 360;
1550 while( sa
>=360 ) sa
-= 360;
1551 while( ea
>=360 ) ea
-= 360;
1552 // calculate quadrant numbers
1553 if( sa
> 270 ) sq
= 3;
1554 else if( sa
> 180 ) sq
= 2;
1555 else if( sa
> 90 ) sq
= 1;
1556 if( ea
> 270 ) eq
= 3;
1557 else if( ea
> 180 ) eq
= 2;
1558 else if( ea
> 90 ) eq
= 1;
1559 sar
= sa
* pi
/ 180.0;
1560 ear
= ea
* pi
/ 180.0;
1561 // correct angle circle -> ellipse
1562 sar
= atan( -a
/(double)b
* tan( sar
) );
1563 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1564 ear
= atan( -a
/(double)b
* tan( ear
) );
1565 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1566 // coordinates of points
1567 xsa
= xCenter
+ a
* cos( sar
);
1568 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1569 ysa
= yCenter
+ b
* sin( sar
);
1570 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1571 xea
= xCenter
+ a
* cos( ear
);
1572 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1573 yea
= yCenter
+ b
* sin( ear
);
1574 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1576 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1578 double c2
= 2.0 / w
;
1587 // Lists for quadrant 1 to 4
1588 wxPointList pointsarray
[4];
1589 // Calculate points for first quadrant and set in all quadrants
1590 for( x
= 0; x
<= a
; ++x
)
1595 bool bNewPoint
= false;
1596 while( y2
> c1
- c2
* x2
&& y
> 0 )
1602 // old y now too big: set point with old y, old x
1603 if( bNewPoint
&& x
>1)
1606 // remove points on the same line
1607 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1608 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1609 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1610 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1612 } // calculate point
1614 // Starting and/or ending points for the quadrants, first quadrant gets both.
1615 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1616 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1617 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1618 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1619 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1621 // copy quadrants in original list
1624 // Copy the right part of the points in the lists
1625 // and delete the wxPoints, because they do not leave this method.
1626 points
->Append( new wxPoint( xsa
, ysa
) );
1628 bool bStarted
= false;
1629 bool bReady
= false;
1630 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1633 wxPointList::compatibility_iterator node
;
1634 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1636 // once: go to starting point in start quadrant
1639 node
->GetData()->x
< xsa
+1 && q
<= 1
1641 node
->GetData()->x
> xsa
-1 && q
>= 2
1648 // copy point, if not at ending point
1651 if( q
!= eq
|| bForceTurn
1653 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1655 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1659 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1660 points
->Append( pPoint
);
1662 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1672 } // while not bReady
1673 points
->Append( new wxPoint( xea
, yea
) );
1676 for( q
= 0; q
< 4; ++q
)
1678 wxPointList::compatibility_iterator node
;
1679 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1681 wxPoint
*p
= node
->GetData();
1688 wxPointList::compatibility_iterator node
;
1689 // copy whole ellipse, wxPoints will be deleted outside
1690 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1692 wxPoint
*p
= node
->GetData();
1693 points
->Append( p
);
1695 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1697 wxPoint
*p
= node
->GetData();
1698 points
->Append( p
);
1700 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1702 wxPoint
*p
= node
->GetData();
1703 points
->Append( p
);
1705 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1707 wxPoint
*p
= node
->GetData();
1708 points
->Append( p
);
1711 } // CalculateEllipticPoints
1713 #endif // __WXWINCE__
1715 float wxDCImpl::GetFontPointSizeAdjustment(float dpi
)
1717 // wxMSW has long-standing bug where wxFont point size is interpreted as
1718 // "pixel size corresponding to given point size *on screen*". In other
1719 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1720 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1721 // that *all* printing code has to account for it and consequently, other
1722 // ports need to emulate this bug too:
1723 const wxSize screenPPI
= wxGetDisplayPPI();
1724 return float(screenPPI
.y
) / dpi
;