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/dcclient.h"
49 #include "wx/gtk/dcmemory.h"
50 #include "wx/gtk/dcscreen.h"
51 #elif defined(__WXGTK__)
52 #include "wx/gtk1/dcclient.h"
53 #include "wx/gtk1/dcmemory.h"
54 #include "wx/gtk1/dcscreen.h"
58 #include "wx/osx/dcclient.h"
59 #include "wx/osx/dcmemory.h"
60 #include "wx/osx/dcscreen.h"
64 #include "wx/os2/dcclient.h"
65 #include "wx/os2/dcmemory.h"
66 #include "wx/os2/dcscreen.h"
70 #include "wx/cocoa/dcclient.h"
71 #include "wx/cocoa/dcmemory.h"
72 #include "wx/cocoa/dcscreen.h"
76 #include "wx/motif/dcclient.h"
77 #include "wx/motif/dcmemory.h"
78 #include "wx/motif/dcscreen.h"
82 #include "wx/x11/dcclient.h"
83 #include "wx/x11/dcmemory.h"
84 #include "wx/x11/dcscreen.h"
88 #include "wx/dfb/dcclient.h"
89 #include "wx/dfb/dcmemory.h"
90 #include "wx/dfb/dcscreen.h"
94 #include "wx/palmos/dcclient.h"
95 #include "wx/palmos/dcmemory.h"
96 #include "wx/palmos/dcscreen.h"
99 //----------------------------------------------------------------------------
101 //----------------------------------------------------------------------------
103 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
105 void wxDCFactory::Set(wxDCFactory
*factory
)
112 wxDCFactory
*wxDCFactory::Get()
115 m_factory
= new wxNativeDCFactory
;
120 class wxDCFactoryCleanupModule
: public wxModule
123 virtual bool OnInit() { return true; }
124 virtual void OnExit() { wxDCFactory::Set(NULL
); }
127 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
130 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
132 //-----------------------------------------------------------------------------
134 //-----------------------------------------------------------------------------
136 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
138 wxDCImpl
* const impl
= new wxWindowDCImpl( owner
, window
);
139 impl
->InheritAttributes(window
);
143 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
145 wxDCImpl
* const impl
= new wxClientDCImpl( owner
, window
);
146 impl
->InheritAttributes(window
);
150 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
152 wxDCImpl
* const impl
= new wxPaintDCImpl( owner
, window
);
153 impl
->InheritAttributes(window
);
157 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
159 return new wxMemoryDCImpl( owner
);
162 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC
*owner
, wxBitmap
& bitmap
)
164 // the bitmap may be modified when it's selected into a memory DC so make
165 // sure changing this bitmap doesn't affect any other shallow copies of it
166 // (see wxMemoryDC::SelectObject())
168 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
169 // method because this should be rarely needed and easy to work around by
170 // using the default ctor and calling SelectObjectAsSource itself
174 return new wxMemoryDCImpl(owner
, bitmap
);
177 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
179 return new wxMemoryDCImpl( owner
, dc
);
182 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
184 return new wxScreenDCImpl( owner
);
187 #if wxUSE_PRINTING_ARCHITECTURE
188 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
190 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
191 return factory
->CreatePrinterDCImpl( owner
, data
);
195 //-----------------------------------------------------------------------------
197 //-----------------------------------------------------------------------------
199 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
201 wxWindowDC::wxWindowDC(wxWindow
*win
)
202 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
206 //-----------------------------------------------------------------------------
208 //-----------------------------------------------------------------------------
210 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
212 wxClientDC::wxClientDC(wxWindow
*win
)
213 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
217 //-----------------------------------------------------------------------------
219 //-----------------------------------------------------------------------------
221 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
223 wxMemoryDC::wxMemoryDC()
224 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
228 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
229 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
233 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
234 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
238 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
240 if ( bmp
.IsSameAs(GetSelectedBitmap()) )
242 // Nothing to do, this bitmap is already selected.
246 // make sure that the given wxBitmap is not sharing its data with other
247 // wxBitmap instances as its contents will be modified by any drawing
248 // operation done on this DC
252 GetImpl()->DoSelect(bmp
);
255 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
257 GetImpl()->DoSelect(bmp
);
260 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
262 return GetImpl()->GetSelectedBitmap();
265 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
267 return GetImpl()->GetSelectedBitmap();
271 //-----------------------------------------------------------------------------
273 //-----------------------------------------------------------------------------
275 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
277 wxPaintDC::wxPaintDC(wxWindow
*win
)
278 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
282 //-----------------------------------------------------------------------------
284 //-----------------------------------------------------------------------------
286 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
288 wxScreenDC::wxScreenDC()
289 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
293 //-----------------------------------------------------------------------------
295 //-----------------------------------------------------------------------------
297 #if wxUSE_PRINTING_ARCHITECTURE
299 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
301 wxPrinterDC::wxPrinterDC()
302 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
306 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
307 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
311 wxRect
wxPrinterDC::GetPaperRect() const
313 return GetImpl()->GetPaperRect();
316 int wxPrinterDC::GetResolution() const
318 return GetImpl()->GetResolution();
321 #endif // wxUSE_PRINTING_ARCHITECTURE
323 //-----------------------------------------------------------------------------
325 //-----------------------------------------------------------------------------
327 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
329 wxDCImpl::wxDCImpl( wxDC
*owner
)
331 , m_colour(wxColourDisplay())
335 , m_isBBoxValid(false)
336 , m_logicalOriginX(0), m_logicalOriginY(0)
337 , m_deviceOriginX(0), m_deviceOriginY(0)
338 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
339 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
340 , m_userScaleX(1.0), m_userScaleY(1.0)
341 , m_scaleX(1.0), m_scaleY(1.0)
342 , m_signX(1), m_signY(1)
343 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
344 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
345 , m_logicalFunction(wxCOPY
)
346 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
347 , m_mappingMode(wxMM_TEXT
)
350 , m_backgroundBrush()
351 , m_textForegroundColour(*wxBLACK
)
352 , m_textBackgroundColour(*wxWHITE
)
356 , m_hasCustomPalette(false)
357 #endif // wxUSE_PALETTE
361 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
362 (double)wxGetDisplaySizeMM().GetWidth();
363 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
364 (double)wxGetDisplaySizeMM().GetHeight();
370 wxDCImpl::~wxDCImpl()
374 // ----------------------------------------------------------------------------
375 // coordinate conversions and transforms
376 // ----------------------------------------------------------------------------
378 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
380 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
383 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
385 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
388 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
390 return wxRound((double)(x
) / m_scaleX
);
393 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
395 return wxRound((double)(y
) / m_scaleY
);
398 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
400 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
403 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
405 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
408 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
410 return wxRound((double)(x
) * m_scaleX
);
413 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
415 return wxRound((double)(y
) * m_scaleY
);
418 void wxDCImpl::ComputeScaleAndOrigin()
420 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
421 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
424 void wxDCImpl::SetMapMode( wxMappingMode mode
)
429 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
432 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
435 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
438 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
442 SetLogicalScale( 1.0, 1.0 );
445 m_mappingMode
= mode
;
448 void wxDCImpl::SetUserScale( double x
, double y
)
450 // allow negative ? -> no
453 ComputeScaleAndOrigin();
456 void wxDCImpl::SetLogicalScale( double x
, double y
)
461 ComputeScaleAndOrigin();
464 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
466 m_logicalOriginX
= x
* m_signX
;
467 m_logicalOriginY
= y
* m_signY
;
468 ComputeScaleAndOrigin();
471 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
475 ComputeScaleAndOrigin();
478 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
480 m_deviceLocalOriginX
= x
;
481 m_deviceLocalOriginY
= y
;
482 ComputeScaleAndOrigin();
485 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
487 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
488 // wxWidgets 2.9: no longer override it
489 m_signX
= (xLeftRight
? 1 : -1);
490 m_signY
= (yBottomUp
? -1 : 1);
491 ComputeScaleAndOrigin();
495 // Each element of the widths array will be the width of the string up to and
496 // including the corresponding character in text. This is the generic
497 // implementation, the port-specific classes should do this with native APIs
498 // if available and if faster. Note: pango_layout_index_to_pos is much slower
499 // than calling GetTextExtent!!
506 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
507 ~FontWidthCache() { delete []m_widths
; }
512 m_widths
= new int[FWC_SIZE
];
514 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
522 static FontWidthCache s_fontWidthCache
;
524 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
528 const size_t len
= text
.length();
532 // reset the cache if font or horizontal scale have changed
533 if ( !s_fontWidthCache
.m_widths
||
534 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
535 (s_fontWidthCache
.m_font
!= GetFont()) )
537 s_fontWidthCache
.Reset();
538 s_fontWidthCache
.m_font
= GetFont();
539 s_fontWidthCache
.m_scaleX
= m_scaleX
;
542 // Calculate the position of each character based on the widths of
543 // the previous characters
545 for ( size_t i
= 0; i
< len
; i
++ )
547 const wxChar c
= text
[i
];
548 unsigned int c_int
= (unsigned int)c
;
550 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
552 w
= s_fontWidthCache
.m_widths
[c_int
];
556 DoGetTextExtent(c
, &w
, &h
);
557 if (c_int
< FWC_SIZE
)
558 s_fontWidthCache
.m_widths
[c_int
] = w
;
562 widths
[i
] = totalWidth
;
568 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
572 const wxFont
*font
) const
574 wxCoord widthTextMax
= 0, widthLine
,
575 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
578 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
580 if ( pc
== text
.end() || *pc
== wxT('\n') )
582 if ( curLine
.empty() )
584 // we can't use GetTextExtent - it will return 0 for both width
585 // and height and an empty line should count in height
588 // assume that this line has the same height as the previous
590 if ( !heightLineDefault
)
591 heightLineDefault
= heightLine
;
593 if ( !heightLineDefault
)
595 // but we don't know it yet - choose something reasonable
596 DoGetTextExtent(wxT("W"), NULL
, &heightLineDefault
,
600 heightTextTotal
+= heightLineDefault
;
604 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
606 if ( widthLine
> widthTextMax
)
607 widthTextMax
= widthLine
;
608 heightTextTotal
+= heightLine
;
611 if ( pc
== text
.end() )
629 *y
= heightTextTotal
;
634 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
635 wxCoord width
, wxCoord height
)
637 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
639 wxCoord x2
= x1
+ width
,
642 // the pen width is calibrated to give 3 for width == height == 10
643 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
645 // we're drawing a scaled version of wx/generic/tick.xpm here
646 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
647 y3
= y1
+ height
/ 2; // y of the left tick branch
648 DoDrawLine(x1
, y3
, x3
, y2
);
649 DoDrawLine(x3
, y2
, x2
, y1
);
651 CalcBoundingBox(x1
, y1
);
652 CalcBoundingBox(x2
, y2
);
656 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
657 wxCoord dstWidth
, wxCoord dstHeight
,
659 wxCoord xsrc
, wxCoord ysrc
,
660 wxCoord srcWidth
, wxCoord srcHeight
,
661 wxRasterOperationMode rop
,
666 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
667 wxT("invalid blit size") );
669 // emulate the stretching by modifying the DC scale
670 double xscale
= (double)srcWidth
/dstWidth
,
671 yscale
= (double)srcHeight
/dstHeight
;
673 double xscaleOld
, yscaleOld
;
674 GetUserScale(&xscaleOld
, &yscaleOld
);
675 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
677 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
678 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
680 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
682 SetUserScale(xscaleOld
, yscaleOld
);
687 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
689 int n
= list
->GetCount();
690 wxPoint
*points
= new wxPoint
[n
];
693 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
695 wxPoint
*point
= node
->GetData();
696 points
[i
].x
= point
->x
;
697 points
[i
].y
= point
->y
;
700 DoDrawLines(n
, points
, xoffset
, yoffset
);
705 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
706 wxCoord xoffset
, wxCoord yoffset
,
707 wxPolygonFillMode fillStyle
)
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 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
726 wxDCImpl::DoDrawPolyPolygon(int n
,
729 wxCoord xoffset
, wxCoord yoffset
,
730 wxPolygonFillMode fillStyle
)
734 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
741 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
746 pts
= new wxPoint
[j
+n
-1];
747 for (i
= 0; i
< j
; i
++)
749 for (i
= 2; i
<= n
; i
++)
751 lastOfs
-= count
[n
-i
];
752 pts
[j
++] = pts
[lastOfs
];
756 wxDCPenChanger
setTransp(*m_owner
, *wxTRANSPARENT_PEN
);
757 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
760 for (i
= j
= 0; i
< n
; i
++)
762 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
770 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
771 wxCoord x2
, wxCoord y2
,
772 wxCoord x3
, wxCoord y3
)
774 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
775 DrawSpline(WXSIZEOF(points
), points
);
778 void wxDCImpl::DrawSpline(int n
, wxPoint points
[])
781 for ( int i
= 0; i
< n
; i
++ )
782 list
.Append(&points
[i
]);
787 // ----------------------------------- spline code ----------------------------------------
789 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
790 double a3
, double b3
, double a4
, double b4
);
791 void wx_clear_stack();
792 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
793 double *y3
, double *x4
, double *y4
);
794 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
795 double x4
, double y4
);
796 static bool wx_spline_add_point(double x
, double y
);
797 static void wx_spline_draw_point_array(wxDC
*dc
);
799 static wxPointList wx_spline_point_list
;
801 #define half(z1, z2) ((z1+z2)/2.0)
804 /* iterative version */
806 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
809 register double xmid
, ymid
;
810 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
813 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
815 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
816 xmid
= (double)half(x2
, x3
);
817 ymid
= (double)half(y2
, y3
);
818 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
819 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
820 wx_spline_add_point( x1
, y1
);
821 wx_spline_add_point( xmid
, ymid
);
823 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
824 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
825 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
826 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
831 /* utilities used by spline drawing routines */
833 typedef struct wx_spline_stack_struct
{
834 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
837 #define SPLINE_STACK_DEPTH 20
838 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
839 static Stack
*wx_stack_top
;
840 static int wx_stack_count
;
842 void wx_clear_stack()
844 wx_stack_top
= wx_spline_stack
;
848 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
850 wx_stack_top
->x1
= x1
;
851 wx_stack_top
->y1
= y1
;
852 wx_stack_top
->x2
= x2
;
853 wx_stack_top
->y2
= y2
;
854 wx_stack_top
->x3
= x3
;
855 wx_stack_top
->y3
= y3
;
856 wx_stack_top
->x4
= x4
;
857 wx_stack_top
->y4
= y4
;
862 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
863 double *x3
, double *y3
, double *x4
, double *y4
)
865 if (wx_stack_count
== 0)
869 *x1
= wx_stack_top
->x1
;
870 *y1
= wx_stack_top
->y1
;
871 *x2
= wx_stack_top
->x2
;
872 *y2
= wx_stack_top
->y2
;
873 *x3
= wx_stack_top
->x3
;
874 *y3
= wx_stack_top
->y3
;
875 *x4
= wx_stack_top
->x4
;
876 *y4
= wx_stack_top
->y4
;
880 static bool wx_spline_add_point(double x
, double y
)
882 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
883 wx_spline_point_list
.Append(point
);
887 static void wx_spline_draw_point_array(wxDC
*dc
)
889 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
890 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
893 wxPoint
*point
= node
->GetData();
895 wx_spline_point_list
.Erase(node
);
896 node
= wx_spline_point_list
.GetFirst();
900 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
902 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
905 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
906 double x1
, y1
, x2
, y2
;
908 wxPointList::compatibility_iterator node
= points
->GetFirst();
913 p
= (wxPoint
*)node
->GetData();
918 node
= node
->GetNext();
923 cx1
= (double)((x1
+ x2
) / 2);
924 cy1
= (double)((y1
+ y2
) / 2);
925 cx2
= (double)((cx1
+ x2
) / 2);
926 cy2
= (double)((cy1
+ y2
) / 2);
928 wx_spline_add_point(x1
, y1
);
930 while ((node
= node
->GetNext())
931 #if !wxUSE_STD_CONTAINERS
933 #endif // !wxUSE_STD_CONTAINERS
941 cx4
= (double)(x1
+ x2
) / 2;
942 cy4
= (double)(y1
+ y2
) / 2;
943 cx3
= (double)(x1
+ cx4
) / 2;
944 cy3
= (double)(y1
+ cy4
) / 2;
946 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
950 cx2
= (double)(cx1
+ x2
) / 2;
951 cy2
= (double)(cy1
+ y2
) / 2;
954 wx_spline_add_point( cx1
, cy1
);
955 wx_spline_add_point( x2
, y2
);
957 wx_spline_draw_point_array( m_owner
);
960 #endif // wxUSE_SPLINES
964 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
965 const wxColour
& initialColour
,
966 const wxColour
& destColour
,
967 wxDirection nDirection
)
970 wxPen oldPen
= m_pen
;
971 wxBrush oldBrush
= m_brush
;
973 wxUint8 nR1
= initialColour
.Red();
974 wxUint8 nG1
= initialColour
.Green();
975 wxUint8 nB1
= initialColour
.Blue();
976 wxUint8 nR2
= destColour
.Red();
977 wxUint8 nG2
= destColour
.Green();
978 wxUint8 nB2
= destColour
.Blue();
981 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
983 wxInt32 x
= rect
.GetWidth();
984 wxInt32 w
= x
; // width of area to shade
985 wxInt32 xDelta
= w
/256; // height of one shade bend
993 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
995 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
998 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1000 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1003 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1005 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1007 wxColour
colour(nR
,nG
,nB
);
1008 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1009 SetBrush(wxBrush(colour
));
1010 if(nDirection
== wxEAST
)
1011 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1012 xDelta
, rect
.GetHeight());
1013 else //nDirection == wxWEST
1014 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1015 xDelta
, rect
.GetHeight());
1018 else // nDirection == wxNORTH || nDirection == wxSOUTH
1020 wxInt32 y
= rect
.GetHeight();
1021 wxInt32 w
= y
; // height of area to shade
1022 wxInt32 yDelta
= w
/255; // height of one shade bend
1030 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1032 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1035 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1037 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1040 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1042 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1044 wxColour
colour(nR
,nG
,nB
);
1045 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1046 SetBrush(wxBrush(colour
));
1047 if(nDirection
== wxNORTH
)
1048 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1049 rect
.GetWidth(), yDelta
);
1050 else //nDirection == wxSOUTH
1051 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1052 rect
.GetWidth(), yDelta
);
1060 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1061 const wxColour
& initialColour
,
1062 const wxColour
& destColour
,
1063 const wxPoint
& circleCenter
)
1065 // save the old pen and ensure it is restored on exit
1066 const wxPen penOrig
= m_pen
;
1067 wxON_BLOCK_EXIT_SET(m_pen
, penOrig
);
1069 wxUint8 nR1
= destColour
.Red();
1070 wxUint8 nG1
= destColour
.Green();
1071 wxUint8 nB1
= destColour
.Blue();
1072 wxUint8 nR2
= initialColour
.Red();
1073 wxUint8 nG2
= initialColour
.Green();
1074 wxUint8 nB2
= initialColour
.Blue();
1079 double cx
= rect
.GetWidth() / 2;
1080 double cy
= rect
.GetHeight() / 2;
1089 ptX
= circleCenter
.x
;
1090 ptY
= circleCenter
.y
;
1091 double nCircleOffX
= ptX
- cx
;
1092 double nCircleOffY
= ptY
- cy
;
1097 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1099 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1101 //get color difference
1105 dGradient
= ((dRadius
- sqrt( (dx
- cx
- nCircleOffX
) * (dx
- cx
- nCircleOffX
)
1106 +(dy
- cy
- nCircleOffY
) * (dy
- cy
- nCircleOffY
)
1111 //normalize Gradient
1116 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * dGradient
/ 100));
1117 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * dGradient
/ 100));
1118 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * dGradient
/ 100));
1121 SetPen(wxColour(nR
,nG
,nB
));
1122 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1127 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1129 wxCHECK_RET( win
, "window can't be NULL" );
1131 SetFont(win
->GetFont());
1132 SetTextForeground(win
->GetForegroundColour());
1133 SetTextBackground(win
->GetBackgroundColour());
1134 SetBackground(win
->GetBackgroundColour());
1135 SetLayoutDirection(win
->GetLayoutDirection());
1138 void wxDCImpl::DoGetFontMetrics(int *height
,
1141 int *internalLeading
,
1142 int *externalLeading
,
1143 int *averageWidth
) const
1145 // Average width is typically the same as width of 'x'.
1147 DoGetTextExtent("x", averageWidth
, &h
, &d
, externalLeading
);
1155 if ( internalLeading
)
1156 *internalLeading
= 0;
1159 //-----------------------------------------------------------------------------
1161 //-----------------------------------------------------------------------------
1163 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1165 void wxDC::CopyAttributes(const wxDC
& dc
)
1167 SetFont(dc
.GetFont());
1168 SetTextForeground(dc
.GetTextForeground());
1169 SetTextBackground(dc
.GetTextBackground());
1170 SetBackground(dc
.GetBackground());
1171 SetLayoutDirection(dc
.GetLayoutDirection());
1174 void wxDC::DrawLabel(const wxString
& text
,
1175 const wxBitmap
& bitmap
,
1179 wxRect
*rectBounding
)
1181 // find the text position
1182 wxCoord widthText
, heightText
, heightLine
;
1183 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1185 wxCoord width
, height
;
1186 if ( bitmap
.IsOk() )
1188 width
= widthText
+ bitmap
.GetWidth();
1189 height
= bitmap
.GetHeight();
1194 height
= heightText
;
1198 if ( alignment
& wxALIGN_RIGHT
)
1200 x
= rect
.GetRight() - width
;
1202 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1204 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1206 else // alignment & wxALIGN_LEFT
1211 if ( alignment
& wxALIGN_BOTTOM
)
1213 y
= rect
.GetBottom() - height
;
1215 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1217 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1219 else // alignment & wxALIGN_TOP
1224 // draw the bitmap first
1228 if ( bitmap
.IsOk() )
1230 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1232 wxCoord offset
= bitmap
.GetWidth() + 4;
1236 y
+= (height
- heightText
) / 2;
1239 // we will draw the underscore under the accel char later
1240 wxCoord startUnderscore
= 0,
1244 // split the string into lines and draw each of them separately
1246 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1247 // strings natively, this is not the case for all of them, notably not
1248 // wxMSW which uses this function for multi-line texts, so we may only
1249 // call DrawText() for single-line strings from here to avoid infinite
1252 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1254 if ( pc
== text
.end() || *pc
== '\n' )
1256 int xRealStart
= x
; // init it here to avoid compielr warnings
1258 if ( !curLine
.empty() )
1260 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1261 // wxALIGN_LEFT is 0
1262 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1265 GetTextExtent(curLine
, &widthLine
, NULL
);
1267 if ( alignment
& wxALIGN_RIGHT
)
1269 xRealStart
+= width
- widthLine
;
1271 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1273 xRealStart
+= (width
- widthLine
) / 2;
1276 //else: left aligned, nothing to do
1278 DrawText(curLine
, xRealStart
, y
);
1283 // do we have underscore in this line? we can check yUnderscore
1284 // because it is set below to just y + heightLine if we do
1285 if ( y
== yUnderscore
)
1287 // adjust the horz positions to account for the shift
1288 startUnderscore
+= xRealStart
;
1289 endUnderscore
+= xRealStart
;
1292 if ( pc
== text
.end() )
1297 else // not end of line
1299 if ( pc
- text
.begin() == indexAccel
)
1301 // remeber to draw underscore here
1302 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1304 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1306 yUnderscore
= y
+ heightLine
;
1315 // draw the underscore if found
1316 if ( startUnderscore
!= endUnderscore
)
1318 // it should be of the same colour as text
1319 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1321 // This adjustment is relatively arbitrary: we need to draw the
1322 // underline slightly higher to avoid overflowing the character cell
1323 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1325 // The currently used value seems to be compatible with native MSW
1326 // behaviour, i.e. it results in the same appearance of the owner-drawn
1327 // and normal labels.
1330 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1333 // return bounding rect if requested
1336 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1339 CalcBoundingBox(x0
, y0
);
1340 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1343 #if WXWIN_COMPATIBILITY_2_8
1344 // for compatibility with the old code when wxCoord was long everywhere
1345 void wxDC::GetTextExtent(const wxString
& string
,
1348 long *externalLeading
,
1349 const wxFont
*theFont
) const
1351 wxCoord x2
, y2
, descent2
, externalLeading2
;
1352 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1353 &descent2
, &externalLeading2
,
1360 *descent
= descent2
;
1361 if ( externalLeading
)
1362 *externalLeading
= externalLeading2
;
1365 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1368 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1375 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1378 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1385 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1387 wxCoord xx
,yy
,ww
,hh
;
1388 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1395 void wxDC::DrawObject(wxDrawObject
* drawobject
)
1397 drawobject
->Draw(*this);
1398 CalcBoundingBox(drawobject
->MinX(),drawobject
->MinY());
1399 CalcBoundingBox(drawobject
->MaxX(),drawobject
->MaxY());
1402 #endif // WXWIN_COMPATIBILITY_2_8
1405 Notes for wxWidgets DrawEllipticArcRot(...)
1407 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1408 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1411 All methods are generic, so they can be implemented in wxDCBase.
1412 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1413 methods like (WinCE) wxDC::DoDrawArc(...).
1415 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1416 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1417 parts) or every column (in steep parts) only one pixel is calculated.
1418 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1419 starting angle is not equal to the ending angle. The calculation of the
1420 pixels is done using simple arithmetic only and should perform not too
1421 bad even on devices without floating point processor. I didn't test this yet.
1423 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1424 For instance: an ellipse rotated 180 degrees is drawn
1425 slightly different from the original.
1427 The points are then moved to an array and used to draw a polyline and/or polygon
1428 (with center added, the pie).
1429 The result looks quite similar to the native ellipse, only e few pixels differ.
1431 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1432 slower as DrawEllipse(...), which calls the native API.
1433 An rotated ellipse outside the clipping region takes nearly the same time,
1434 while an native ellipse outside takes nearly no time to draw.
1436 If you draw an arc with this new method, you will see the starting and ending angles
1437 are calculated properly.
1438 If you use DrawEllipticArc(...), you will see they are only correct for circles
1439 and not properly calculated for ellipses.
1442 p.lenhard@t-online.de
1446 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1447 wxCoord w
, wxCoord h
,
1448 double sa
, double ea
, double angle
)
1452 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1453 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1455 // Add center (for polygon/pie)
1456 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1458 // copy list into array and delete list elements
1459 int n
= list
.GetCount();
1460 wxPoint
*points
= new wxPoint
[n
];
1462 wxPointList::compatibility_iterator node
;
1463 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1465 wxPoint
*point
= node
->GetData();
1466 points
[i
].x
= point
->x
;
1467 points
[i
].y
= point
->y
;
1471 // first draw the pie without pen, if necessary
1472 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1474 wxPen
tempPen( GetPen() );
1475 SetPen( *wxTRANSPARENT_PEN
);
1476 DoDrawPolygon( n
, points
, 0, 0 );
1480 // then draw the arc without brush, if necessary
1481 if( GetPen() != *wxTRANSPARENT_PEN
)
1484 DoDrawLines( n
-1, points
, 0, 0 );
1489 } // DrawEllipticArcRot
1491 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1496 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1497 double dCosA
= cos(angle
*2.0*pi
/360.0);
1498 wxPointList::compatibility_iterator node
;
1499 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1501 wxPoint
* point
= node
->GetData();
1503 // transform coordinates, if necessary
1504 if( center
.x
) point
->x
-= center
.x
;
1505 if( center
.y
) point
->y
-= center
.y
;
1507 // calculate rotation, rounding simply by implicit cast to integer
1508 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1509 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1512 // back transform coordinates, if necessary
1513 if( center
.x
) point
->x
+= center
.x
;
1514 if( center
.y
) point
->y
+= center
.y
;
1519 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1520 wxCoord xStart
, wxCoord yStart
,
1521 wxCoord w
, wxCoord h
,
1522 double sa
, double ea
)
1533 bool bUseAngles
= false;
1539 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1541 if( 2*a
== w
) decrX
= 1;
1543 if( 2*b
== h
) decrY
= 1;
1545 wxCoord xCenter
= xStart
+ a
;
1546 wxCoord yCenter
= yStart
+ b
;
1547 // calculate data for start and end, if necessary
1551 // normalisation of angles
1552 while( sa
<0 ) sa
+= 360;
1553 while( ea
<0 ) ea
+= 360;
1554 while( sa
>=360 ) sa
-= 360;
1555 while( ea
>=360 ) ea
-= 360;
1556 // calculate quadrant numbers
1557 if( sa
> 270 ) sq
= 3;
1558 else if( sa
> 180 ) sq
= 2;
1559 else if( sa
> 90 ) sq
= 1;
1560 if( ea
> 270 ) eq
= 3;
1561 else if( ea
> 180 ) eq
= 2;
1562 else if( ea
> 90 ) eq
= 1;
1563 sar
= sa
* pi
/ 180.0;
1564 ear
= ea
* pi
/ 180.0;
1565 // correct angle circle -> ellipse
1566 sar
= atan( -a
/(double)b
* tan( sar
) );
1567 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1568 ear
= atan( -a
/(double)b
* tan( ear
) );
1569 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1570 // coordinates of points
1571 xsa
= xCenter
+ a
* cos( sar
);
1572 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1573 ysa
= yCenter
+ b
* sin( sar
);
1574 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1575 xea
= xCenter
+ a
* cos( ear
);
1576 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1577 yea
= yCenter
+ b
* sin( ear
);
1578 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1580 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1582 double c2
= 2.0 / w
;
1591 // Lists for quadrant 1 to 4
1592 wxPointList pointsarray
[4];
1593 // Calculate points for first quadrant and set in all quadrants
1594 for( x
= 0; x
<= a
; ++x
)
1599 bool bNewPoint
= false;
1600 while( y2
> c1
- c2
* x2
&& y
> 0 )
1606 // old y now too big: set point with old y, old x
1607 if( bNewPoint
&& x
>1)
1610 // remove points on the same line
1611 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1612 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1613 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1614 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1616 } // calculate point
1618 // Starting and/or ending points for the quadrants, first quadrant gets both.
1619 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1620 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1621 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1622 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1623 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1625 // copy quadrants in original list
1628 // Copy the right part of the points in the lists
1629 // and delete the wxPoints, because they do not leave this method.
1630 points
->Append( new wxPoint( xsa
, ysa
) );
1632 bool bStarted
= false;
1633 bool bReady
= false;
1634 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1637 wxPointList::compatibility_iterator node
;
1638 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1640 // once: go to starting point in start quadrant
1643 node
->GetData()->x
< xsa
+1 && q
<= 1
1645 node
->GetData()->x
> xsa
-1 && q
>= 2
1652 // copy point, if not at ending point
1655 if( q
!= eq
|| bForceTurn
1657 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1659 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1663 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1664 points
->Append( pPoint
);
1666 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1676 } // while not bReady
1677 points
->Append( new wxPoint( xea
, yea
) );
1680 for( q
= 0; q
< 4; ++q
)
1682 wxPointList::compatibility_iterator node
;
1683 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1685 wxPoint
*p
= node
->GetData();
1692 wxPointList::compatibility_iterator node
;
1693 // copy whole ellipse, wxPoints will be deleted outside
1694 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1696 wxPoint
*p
= node
->GetData();
1697 points
->Append( p
);
1699 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1701 wxPoint
*p
= node
->GetData();
1702 points
->Append( p
);
1704 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1706 wxPoint
*p
= node
->GetData();
1707 points
->Append( p
);
1709 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1711 wxPoint
*p
= node
->GetData();
1712 points
->Append( p
);
1715 } // CalculateEllipticPoints
1717 #endif // __WXWINCE__
1719 float wxDCImpl::GetFontPointSizeAdjustment(float dpi
)
1721 // wxMSW has long-standing bug where wxFont point size is interpreted as
1722 // "pixel size corresponding to given point size *on screen*". In other
1723 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1724 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1725 // that *all* printing code has to account for it and consequently, other
1726 // ports need to emulate this bug too:
1727 const wxSize screenPPI
= wxGetDisplayPPI();
1728 return float(screenPPI
.y
) / dpi
;