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"
93 //----------------------------------------------------------------------------
95 //----------------------------------------------------------------------------
97 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
99 void wxDCFactory::Set(wxDCFactory
*factory
)
106 wxDCFactory
*wxDCFactory::Get()
109 m_factory
= new wxNativeDCFactory
;
114 class wxDCFactoryCleanupModule
: public wxModule
117 virtual bool OnInit() { return true; }
118 virtual void OnExit() { wxDCFactory::Set(NULL
); }
121 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
124 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
126 //-----------------------------------------------------------------------------
128 //-----------------------------------------------------------------------------
130 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
132 wxDCImpl
* const impl
= new wxWindowDCImpl( owner
, window
);
133 impl
->InheritAttributes(window
);
137 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
139 wxDCImpl
* const impl
= new wxClientDCImpl( owner
, window
);
140 impl
->InheritAttributes(window
);
144 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
146 wxDCImpl
* const impl
= new wxPaintDCImpl( owner
, window
);
147 impl
->InheritAttributes(window
);
151 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
153 return new wxMemoryDCImpl( owner
);
156 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC
*owner
, wxBitmap
& bitmap
)
158 // the bitmap may be modified when it's selected into a memory DC so make
159 // sure changing this bitmap doesn't affect any other shallow copies of it
160 // (see wxMemoryDC::SelectObject())
162 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
163 // method because this should be rarely needed and easy to work around by
164 // using the default ctor and calling SelectObjectAsSource itself
168 return new wxMemoryDCImpl(owner
, bitmap
);
171 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
173 return new wxMemoryDCImpl( owner
, dc
);
176 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
178 return new wxScreenDCImpl( owner
);
181 #if wxUSE_PRINTING_ARCHITECTURE
182 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
184 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
185 return factory
->CreatePrinterDCImpl( owner
, data
);
189 //-----------------------------------------------------------------------------
191 //-----------------------------------------------------------------------------
193 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
195 wxWindowDC::wxWindowDC(wxWindow
*win
)
196 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
200 //-----------------------------------------------------------------------------
202 //-----------------------------------------------------------------------------
204 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
206 wxClientDC::wxClientDC(wxWindow
*win
)
207 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
211 //-----------------------------------------------------------------------------
213 //-----------------------------------------------------------------------------
215 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
217 wxMemoryDC::wxMemoryDC()
218 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
222 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
223 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
227 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
228 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
232 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
234 if ( bmp
.IsSameAs(GetSelectedBitmap()) )
236 // Nothing to do, this bitmap is already selected.
240 // make sure that the given wxBitmap is not sharing its data with other
241 // wxBitmap instances as its contents will be modified by any drawing
242 // operation done on this DC
246 GetImpl()->DoSelect(bmp
);
249 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
251 GetImpl()->DoSelect(bmp
);
254 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
256 return GetImpl()->GetSelectedBitmap();
259 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
261 return GetImpl()->GetSelectedBitmap();
265 //-----------------------------------------------------------------------------
267 //-----------------------------------------------------------------------------
269 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
271 wxPaintDC::wxPaintDC(wxWindow
*win
)
272 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
276 //-----------------------------------------------------------------------------
278 //-----------------------------------------------------------------------------
280 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
282 wxScreenDC::wxScreenDC()
283 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
287 //-----------------------------------------------------------------------------
289 //-----------------------------------------------------------------------------
291 #if wxUSE_PRINTING_ARCHITECTURE
293 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
295 wxPrinterDC::wxPrinterDC()
296 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
300 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
301 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
305 wxRect
wxPrinterDC::GetPaperRect() const
307 return GetImpl()->GetPaperRect();
310 int wxPrinterDC::GetResolution() const
312 return GetImpl()->GetResolution();
315 #endif // wxUSE_PRINTING_ARCHITECTURE
317 //-----------------------------------------------------------------------------
319 //-----------------------------------------------------------------------------
321 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
323 wxDCImpl::wxDCImpl( wxDC
*owner
)
325 , m_colour(wxColourDisplay())
329 , m_isBBoxValid(false)
330 , m_logicalOriginX(0), m_logicalOriginY(0)
331 , m_deviceOriginX(0), m_deviceOriginY(0)
332 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
333 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
334 , m_userScaleX(1.0), m_userScaleY(1.0)
335 , m_scaleX(1.0), m_scaleY(1.0)
336 , m_signX(1), m_signY(1)
337 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
338 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
339 , m_logicalFunction(wxCOPY
)
340 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
341 , m_mappingMode(wxMM_TEXT
)
344 , m_backgroundBrush()
345 , m_textForegroundColour(*wxBLACK
)
346 , m_textBackgroundColour(*wxWHITE
)
350 , m_hasCustomPalette(false)
351 #endif // wxUSE_PALETTE
355 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
356 (double)wxGetDisplaySizeMM().GetWidth();
357 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
358 (double)wxGetDisplaySizeMM().GetHeight();
364 wxDCImpl::~wxDCImpl()
368 // ----------------------------------------------------------------------------
369 // coordinate conversions and transforms
370 // ----------------------------------------------------------------------------
372 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
374 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
377 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
379 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
382 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
384 return wxRound((double)(x
) / m_scaleX
);
387 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
389 return wxRound((double)(y
) / m_scaleY
);
392 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
394 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
397 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
399 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
402 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
404 return wxRound((double)(x
) * m_scaleX
);
407 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
409 return wxRound((double)(y
) * m_scaleY
);
412 void wxDCImpl::ComputeScaleAndOrigin()
414 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
415 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
418 void wxDCImpl::SetMapMode( wxMappingMode mode
)
423 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
426 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
429 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
432 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
436 SetLogicalScale( 1.0, 1.0 );
439 m_mappingMode
= mode
;
442 void wxDCImpl::SetUserScale( double x
, double y
)
444 // allow negative ? -> no
447 ComputeScaleAndOrigin();
450 void wxDCImpl::SetLogicalScale( double x
, double y
)
455 ComputeScaleAndOrigin();
458 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
460 m_logicalOriginX
= x
* m_signX
;
461 m_logicalOriginY
= y
* m_signY
;
462 ComputeScaleAndOrigin();
465 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
469 ComputeScaleAndOrigin();
472 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
474 m_deviceLocalOriginX
= x
;
475 m_deviceLocalOriginY
= y
;
476 ComputeScaleAndOrigin();
479 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
481 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
482 // wxWidgets 2.9: no longer override it
483 m_signX
= (xLeftRight
? 1 : -1);
484 m_signY
= (yBottomUp
? -1 : 1);
485 ComputeScaleAndOrigin();
489 // Each element of the widths array will be the width of the string up to and
490 // including the corresponding character in text. This is the generic
491 // implementation, the port-specific classes should do this with native APIs
492 // if available and if faster. Note: pango_layout_index_to_pos is much slower
493 // than calling GetTextExtent!!
500 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
501 ~FontWidthCache() { delete []m_widths
; }
506 m_widths
= new int[FWC_SIZE
];
508 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
516 static FontWidthCache s_fontWidthCache
;
518 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
522 const size_t len
= text
.length();
526 // reset the cache if font or horizontal scale have changed
527 if ( !s_fontWidthCache
.m_widths
||
528 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
529 (s_fontWidthCache
.m_font
!= GetFont()) )
531 s_fontWidthCache
.Reset();
532 s_fontWidthCache
.m_font
= GetFont();
533 s_fontWidthCache
.m_scaleX
= m_scaleX
;
536 // Calculate the position of each character based on the widths of
537 // the previous characters
539 for ( size_t i
= 0; i
< len
; i
++ )
541 const wxChar c
= text
[i
];
542 unsigned int c_int
= (unsigned int)c
;
544 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
546 w
= s_fontWidthCache
.m_widths
[c_int
];
550 DoGetTextExtent(c
, &w
, &h
);
551 if (c_int
< FWC_SIZE
)
552 s_fontWidthCache
.m_widths
[c_int
] = w
;
556 widths
[i
] = totalWidth
;
562 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
566 const wxFont
*font
) const
568 wxCoord widthTextMax
= 0, widthLine
,
569 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
572 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
574 if ( pc
== text
.end() || *pc
== wxT('\n') )
576 if ( curLine
.empty() )
578 // we can't use GetTextExtent - it will return 0 for both width
579 // and height and an empty line should count in height
582 // assume that this line has the same height as the previous
584 if ( !heightLineDefault
)
585 heightLineDefault
= heightLine
;
587 if ( !heightLineDefault
)
589 // but we don't know it yet - choose something reasonable
590 DoGetTextExtent(wxT("W"), NULL
, &heightLineDefault
,
594 heightTextTotal
+= heightLineDefault
;
598 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
600 if ( widthLine
> widthTextMax
)
601 widthTextMax
= widthLine
;
602 heightTextTotal
+= heightLine
;
605 if ( pc
== text
.end() )
623 *y
= heightTextTotal
;
628 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
629 wxCoord width
, wxCoord height
)
631 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
633 wxCoord x2
= x1
+ width
,
636 // the pen width is calibrated to give 3 for width == height == 10
637 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
639 // we're drawing a scaled version of wx/generic/tick.xpm here
640 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
641 y3
= y1
+ height
/ 2; // y of the left tick branch
642 DoDrawLine(x1
, y3
, x3
, y2
);
643 DoDrawLine(x3
, y2
, x2
, y1
);
645 CalcBoundingBox(x1
, y1
);
646 CalcBoundingBox(x2
, y2
);
650 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
651 wxCoord dstWidth
, wxCoord dstHeight
,
653 wxCoord xsrc
, wxCoord ysrc
,
654 wxCoord srcWidth
, wxCoord srcHeight
,
655 wxRasterOperationMode rop
,
660 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
661 wxT("invalid blit size") );
663 // emulate the stretching by modifying the DC scale
664 double xscale
= (double)srcWidth
/dstWidth
,
665 yscale
= (double)srcHeight
/dstHeight
;
667 double xscaleOld
, yscaleOld
;
668 GetUserScale(&xscaleOld
, &yscaleOld
);
669 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
671 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
672 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
674 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
676 SetUserScale(xscaleOld
, yscaleOld
);
681 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
683 int n
= list
->GetCount();
684 wxPoint
*points
= new wxPoint
[n
];
687 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
689 wxPoint
*point
= node
->GetData();
690 points
[i
].x
= point
->x
;
691 points
[i
].y
= point
->y
;
694 DoDrawLines(n
, points
, xoffset
, yoffset
);
699 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
700 wxCoord xoffset
, wxCoord yoffset
,
701 wxPolygonFillMode fillStyle
)
703 int n
= list
->GetCount();
704 wxPoint
*points
= new wxPoint
[n
];
707 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
709 wxPoint
*point
= node
->GetData();
710 points
[i
].x
= point
->x
;
711 points
[i
].y
= point
->y
;
714 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
720 wxDCImpl::DoDrawPolyPolygon(int n
,
723 wxCoord xoffset
, wxCoord yoffset
,
724 wxPolygonFillMode fillStyle
)
728 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
735 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
740 pts
= new wxPoint
[j
+n
-1];
741 for (i
= 0; i
< j
; i
++)
743 for (i
= 2; i
<= n
; i
++)
745 lastOfs
-= count
[n
-i
];
746 pts
[j
++] = pts
[lastOfs
];
750 wxDCPenChanger
setTransp(*m_owner
, *wxTRANSPARENT_PEN
);
751 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
754 for (i
= j
= 0; i
< n
; i
++)
756 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
764 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
765 wxCoord x2
, wxCoord y2
,
766 wxCoord x3
, wxCoord y3
)
768 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
769 DrawSpline(WXSIZEOF(points
), points
);
772 void wxDCImpl::DrawSpline(int n
, wxPoint points
[])
775 for ( int i
= 0; i
< n
; i
++ )
776 list
.Append(&points
[i
]);
781 // ----------------------------------- spline code ----------------------------------------
783 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
784 double a3
, double b3
, double a4
, double b4
);
785 void wx_clear_stack();
786 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
787 double *y3
, double *x4
, double *y4
);
788 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
789 double x4
, double y4
);
790 static bool wx_spline_add_point(double x
, double y
);
791 static void wx_spline_draw_point_array(wxDC
*dc
);
793 static wxPointList wx_spline_point_list
;
795 #define half(z1, z2) ((z1+z2)/2.0)
798 /* iterative version */
800 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
803 register double xmid
, ymid
;
804 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
807 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
809 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
810 xmid
= (double)half(x2
, x3
);
811 ymid
= (double)half(y2
, y3
);
812 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
813 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
814 wx_spline_add_point( x1
, y1
);
815 wx_spline_add_point( xmid
, ymid
);
817 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
818 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
819 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
820 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
825 /* utilities used by spline drawing routines */
827 typedef struct wx_spline_stack_struct
{
828 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
831 #define SPLINE_STACK_DEPTH 20
832 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
833 static Stack
*wx_stack_top
;
834 static int wx_stack_count
;
836 void wx_clear_stack()
838 wx_stack_top
= wx_spline_stack
;
842 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
844 wx_stack_top
->x1
= x1
;
845 wx_stack_top
->y1
= y1
;
846 wx_stack_top
->x2
= x2
;
847 wx_stack_top
->y2
= y2
;
848 wx_stack_top
->x3
= x3
;
849 wx_stack_top
->y3
= y3
;
850 wx_stack_top
->x4
= x4
;
851 wx_stack_top
->y4
= y4
;
856 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
857 double *x3
, double *y3
, double *x4
, double *y4
)
859 if (wx_stack_count
== 0)
863 *x1
= wx_stack_top
->x1
;
864 *y1
= wx_stack_top
->y1
;
865 *x2
= wx_stack_top
->x2
;
866 *y2
= wx_stack_top
->y2
;
867 *x3
= wx_stack_top
->x3
;
868 *y3
= wx_stack_top
->y3
;
869 *x4
= wx_stack_top
->x4
;
870 *y4
= wx_stack_top
->y4
;
874 static bool wx_spline_add_point(double x
, double y
)
876 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
877 wx_spline_point_list
.Append(point
);
881 static void wx_spline_draw_point_array(wxDC
*dc
)
883 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
884 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
887 wxPoint
*point
= node
->GetData();
889 wx_spline_point_list
.Erase(node
);
890 node
= wx_spline_point_list
.GetFirst();
894 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
896 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
899 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
900 double x1
, y1
, x2
, y2
;
902 wxPointList::compatibility_iterator node
= points
->GetFirst();
907 p
= (wxPoint
*)node
->GetData();
912 node
= node
->GetNext();
917 cx1
= (double)((x1
+ x2
) / 2);
918 cy1
= (double)((y1
+ y2
) / 2);
919 cx2
= (double)((cx1
+ x2
) / 2);
920 cy2
= (double)((cy1
+ y2
) / 2);
922 wx_spline_add_point(x1
, y1
);
924 while ((node
= node
->GetNext())
925 #if !wxUSE_STD_CONTAINERS
927 #endif // !wxUSE_STD_CONTAINERS
935 cx4
= (double)(x1
+ x2
) / 2;
936 cy4
= (double)(y1
+ y2
) / 2;
937 cx3
= (double)(x1
+ cx4
) / 2;
938 cy3
= (double)(y1
+ cy4
) / 2;
940 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
944 cx2
= (double)(cx1
+ x2
) / 2;
945 cy2
= (double)(cy1
+ y2
) / 2;
948 wx_spline_add_point( cx1
, cy1
);
949 wx_spline_add_point( x2
, y2
);
951 wx_spline_draw_point_array( m_owner
);
954 #endif // wxUSE_SPLINES
958 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
959 const wxColour
& initialColour
,
960 const wxColour
& destColour
,
961 wxDirection nDirection
)
964 wxPen oldPen
= m_pen
;
965 wxBrush oldBrush
= m_brush
;
967 wxUint8 nR1
= initialColour
.Red();
968 wxUint8 nG1
= initialColour
.Green();
969 wxUint8 nB1
= initialColour
.Blue();
970 wxUint8 nR2
= destColour
.Red();
971 wxUint8 nG2
= destColour
.Green();
972 wxUint8 nB2
= destColour
.Blue();
975 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
977 wxInt32 x
= rect
.GetWidth();
978 wxInt32 w
= x
; // width of area to shade
979 wxInt32 xDelta
= w
/256; // height of one shade bend
987 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
989 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
992 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
994 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
997 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
999 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1001 wxColour
colour(nR
,nG
,nB
);
1002 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1003 SetBrush(wxBrush(colour
));
1004 if(nDirection
== wxEAST
)
1005 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1006 xDelta
, rect
.GetHeight());
1007 else //nDirection == wxWEST
1008 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1009 xDelta
, rect
.GetHeight());
1012 else // nDirection == wxNORTH || nDirection == wxSOUTH
1014 wxInt32 y
= rect
.GetHeight();
1015 wxInt32 w
= y
; // height of area to shade
1016 wxInt32 yDelta
= w
/255; // height of one shade bend
1024 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1026 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1029 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1031 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1034 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1036 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1038 wxColour
colour(nR
,nG
,nB
);
1039 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1040 SetBrush(wxBrush(colour
));
1041 if(nDirection
== wxNORTH
)
1042 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1043 rect
.GetWidth(), yDelta
);
1044 else //nDirection == wxSOUTH
1045 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1046 rect
.GetWidth(), yDelta
);
1054 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1055 const wxColour
& initialColour
,
1056 const wxColour
& destColour
,
1057 const wxPoint
& circleCenter
)
1059 // save the old pen and ensure it is restored on exit
1060 const wxPen penOrig
= m_pen
;
1061 wxON_BLOCK_EXIT_SET(m_pen
, penOrig
);
1063 wxUint8 nR1
= destColour
.Red();
1064 wxUint8 nG1
= destColour
.Green();
1065 wxUint8 nB1
= destColour
.Blue();
1066 wxUint8 nR2
= initialColour
.Red();
1067 wxUint8 nG2
= initialColour
.Green();
1068 wxUint8 nB2
= initialColour
.Blue();
1073 double cx
= rect
.GetWidth() / 2;
1074 double cy
= rect
.GetHeight() / 2;
1083 ptX
= circleCenter
.x
;
1084 ptY
= circleCenter
.y
;
1085 double nCircleOffX
= ptX
- cx
;
1086 double nCircleOffY
= ptY
- cy
;
1091 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1093 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1095 //get color difference
1099 dGradient
= ((dRadius
- sqrt( (dx
- cx
- nCircleOffX
) * (dx
- cx
- nCircleOffX
)
1100 +(dy
- cy
- nCircleOffY
) * (dy
- cy
- nCircleOffY
)
1105 //normalize Gradient
1110 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * dGradient
/ 100));
1111 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * dGradient
/ 100));
1112 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * dGradient
/ 100));
1115 SetPen(wxColour(nR
,nG
,nB
));
1116 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1121 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1123 wxCHECK_RET( win
, "window can't be NULL" );
1125 SetFont(win
->GetFont());
1126 SetTextForeground(win
->GetForegroundColour());
1127 SetTextBackground(win
->GetBackgroundColour());
1128 SetBackground(win
->GetBackgroundColour());
1129 SetLayoutDirection(win
->GetLayoutDirection());
1132 void wxDCImpl::DoGetFontMetrics(int *height
,
1135 int *internalLeading
,
1136 int *externalLeading
,
1137 int *averageWidth
) const
1139 // Average width is typically the same as width of 'x'.
1141 DoGetTextExtent("x", averageWidth
, &h
, &d
, externalLeading
);
1149 if ( internalLeading
)
1150 *internalLeading
= 0;
1153 //-----------------------------------------------------------------------------
1155 //-----------------------------------------------------------------------------
1157 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1159 void wxDC::CopyAttributes(const wxDC
& dc
)
1161 SetFont(dc
.GetFont());
1162 SetTextForeground(dc
.GetTextForeground());
1163 SetTextBackground(dc
.GetTextBackground());
1164 SetBackground(dc
.GetBackground());
1165 SetLayoutDirection(dc
.GetLayoutDirection());
1168 void wxDC::DrawLabel(const wxString
& text
,
1169 const wxBitmap
& bitmap
,
1173 wxRect
*rectBounding
)
1175 // find the text position
1176 wxCoord widthText
, heightText
, heightLine
;
1177 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1179 wxCoord width
, height
;
1180 if ( bitmap
.IsOk() )
1182 width
= widthText
+ bitmap
.GetWidth();
1183 height
= bitmap
.GetHeight();
1188 height
= heightText
;
1192 if ( alignment
& wxALIGN_RIGHT
)
1194 x
= rect
.GetRight() - width
;
1196 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1198 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1200 else // alignment & wxALIGN_LEFT
1205 if ( alignment
& wxALIGN_BOTTOM
)
1207 y
= rect
.GetBottom() - height
;
1209 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1211 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1213 else // alignment & wxALIGN_TOP
1218 // draw the bitmap first
1222 if ( bitmap
.IsOk() )
1224 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1226 wxCoord offset
= bitmap
.GetWidth() + 4;
1230 y
+= (height
- heightText
) / 2;
1233 // we will draw the underscore under the accel char later
1234 wxCoord startUnderscore
= 0,
1238 // split the string into lines and draw each of them separately
1240 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1241 // strings natively, this is not the case for all of them, notably not
1242 // wxMSW which uses this function for multi-line texts, so we may only
1243 // call DrawText() for single-line strings from here to avoid infinite
1246 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1248 if ( pc
== text
.end() || *pc
== '\n' )
1250 int xRealStart
= x
; // init it here to avoid compielr warnings
1252 if ( !curLine
.empty() )
1254 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1255 // wxALIGN_LEFT is 0
1256 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1259 GetTextExtent(curLine
, &widthLine
, NULL
);
1261 if ( alignment
& wxALIGN_RIGHT
)
1263 xRealStart
+= width
- widthLine
;
1265 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1267 xRealStart
+= (width
- widthLine
) / 2;
1270 //else: left aligned, nothing to do
1272 DrawText(curLine
, xRealStart
, y
);
1277 // do we have underscore in this line? we can check yUnderscore
1278 // because it is set below to just y + heightLine if we do
1279 if ( y
== yUnderscore
)
1281 // adjust the horz positions to account for the shift
1282 startUnderscore
+= xRealStart
;
1283 endUnderscore
+= xRealStart
;
1286 if ( pc
== text
.end() )
1291 else // not end of line
1293 if ( pc
- text
.begin() == indexAccel
)
1295 // remember to draw underscore here
1296 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1298 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1300 yUnderscore
= y
+ heightLine
;
1309 // draw the underscore if found
1310 if ( startUnderscore
!= endUnderscore
)
1312 // it should be of the same colour as text
1313 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1315 // This adjustment is relatively arbitrary: we need to draw the
1316 // underline slightly higher to avoid overflowing the character cell
1317 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1319 // The currently used value seems to be compatible with native MSW
1320 // behaviour, i.e. it results in the same appearance of the owner-drawn
1321 // and normal labels.
1324 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1327 // return bounding rect if requested
1330 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1333 CalcBoundingBox(x0
, y0
);
1334 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1337 #if WXWIN_COMPATIBILITY_2_8
1338 // for compatibility with the old code when wxCoord was long everywhere
1339 void wxDC::GetTextExtent(const wxString
& string
,
1342 long *externalLeading
,
1343 const wxFont
*theFont
) const
1345 wxCoord x2
, y2
, descent2
, externalLeading2
;
1346 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1347 &descent2
, &externalLeading2
,
1354 *descent
= descent2
;
1355 if ( externalLeading
)
1356 *externalLeading
= externalLeading2
;
1359 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1362 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1369 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1372 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1379 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1381 wxCoord xx
,yy
,ww
,hh
;
1382 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1389 void wxDC::DrawObject(wxDrawObject
* drawobject
)
1391 drawobject
->Draw(*this);
1392 CalcBoundingBox(drawobject
->MinX(),drawobject
->MinY());
1393 CalcBoundingBox(drawobject
->MaxX(),drawobject
->MaxY());
1396 #endif // WXWIN_COMPATIBILITY_2_8
1399 Notes for wxWidgets DrawEllipticArcRot(...)
1401 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1402 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1405 All methods are generic, so they can be implemented in wxDCBase.
1406 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1407 methods like (WinCE) wxDC::DoDrawArc(...).
1409 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1410 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1411 parts) or every column (in steep parts) only one pixel is calculated.
1412 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1413 starting angle is not equal to the ending angle. The calculation of the
1414 pixels is done using simple arithmetic only and should perform not too
1415 bad even on devices without floating point processor. I didn't test this yet.
1417 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1418 For instance: an ellipse rotated 180 degrees is drawn
1419 slightly different from the original.
1421 The points are then moved to an array and used to draw a polyline and/or polygon
1422 (with center added, the pie).
1423 The result looks quite similar to the native ellipse, only e few pixels differ.
1425 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1426 slower as DrawEllipse(...), which calls the native API.
1427 An rotated ellipse outside the clipping region takes nearly the same time,
1428 while an native ellipse outside takes nearly no time to draw.
1430 If you draw an arc with this new method, you will see the starting and ending angles
1431 are calculated properly.
1432 If you use DrawEllipticArc(...), you will see they are only correct for circles
1433 and not properly calculated for ellipses.
1436 p.lenhard@t-online.de
1440 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1441 wxCoord w
, wxCoord h
,
1442 double sa
, double ea
, double angle
)
1446 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1447 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1449 // Add center (for polygon/pie)
1450 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1452 // copy list into array and delete list elements
1453 int n
= list
.GetCount();
1454 wxPoint
*points
= new wxPoint
[n
];
1456 wxPointList::compatibility_iterator node
;
1457 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1459 wxPoint
*point
= node
->GetData();
1460 points
[i
].x
= point
->x
;
1461 points
[i
].y
= point
->y
;
1465 // first draw the pie without pen, if necessary
1466 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1468 wxPen
tempPen( GetPen() );
1469 SetPen( *wxTRANSPARENT_PEN
);
1470 DoDrawPolygon( n
, points
, 0, 0 );
1474 // then draw the arc without brush, if necessary
1475 if( GetPen() != *wxTRANSPARENT_PEN
)
1478 DoDrawLines( n
-1, points
, 0, 0 );
1483 } // DrawEllipticArcRot
1485 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1490 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1491 double dCosA
= cos(angle
*2.0*pi
/360.0);
1492 wxPointList::compatibility_iterator node
;
1493 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1495 wxPoint
* point
= node
->GetData();
1497 // transform coordinates, if necessary
1498 if( center
.x
) point
->x
-= center
.x
;
1499 if( center
.y
) point
->y
-= center
.y
;
1501 // calculate rotation, rounding simply by implicit cast to integer
1502 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1503 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1506 // back transform coordinates, if necessary
1507 if( center
.x
) point
->x
+= center
.x
;
1508 if( center
.y
) point
->y
+= center
.y
;
1513 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1514 wxCoord xStart
, wxCoord yStart
,
1515 wxCoord w
, wxCoord h
,
1516 double sa
, double ea
)
1527 bool bUseAngles
= false;
1533 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1535 if( 2*a
== w
) decrX
= 1;
1537 if( 2*b
== h
) decrY
= 1;
1539 wxCoord xCenter
= xStart
+ a
;
1540 wxCoord yCenter
= yStart
+ b
;
1541 // calculate data for start and end, if necessary
1545 // normalisation of angles
1546 while( sa
<0 ) sa
+= 360;
1547 while( ea
<0 ) ea
+= 360;
1548 while( sa
>=360 ) sa
-= 360;
1549 while( ea
>=360 ) ea
-= 360;
1550 // calculate quadrant numbers
1551 if( sa
> 270 ) sq
= 3;
1552 else if( sa
> 180 ) sq
= 2;
1553 else if( sa
> 90 ) sq
= 1;
1554 if( ea
> 270 ) eq
= 3;
1555 else if( ea
> 180 ) eq
= 2;
1556 else if( ea
> 90 ) eq
= 1;
1557 sar
= sa
* pi
/ 180.0;
1558 ear
= ea
* pi
/ 180.0;
1559 // correct angle circle -> ellipse
1560 sar
= atan( -a
/(double)b
* tan( sar
) );
1561 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1562 ear
= atan( -a
/(double)b
* tan( ear
) );
1563 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1564 // coordinates of points
1565 xsa
= xCenter
+ a
* cos( sar
);
1566 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1567 ysa
= yCenter
+ b
* sin( sar
);
1568 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1569 xea
= xCenter
+ a
* cos( ear
);
1570 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1571 yea
= yCenter
+ b
* sin( ear
);
1572 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1574 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1576 double c2
= 2.0 / w
;
1585 // Lists for quadrant 1 to 4
1586 wxPointList pointsarray
[4];
1587 // Calculate points for first quadrant and set in all quadrants
1588 for( x
= 0; x
<= a
; ++x
)
1593 bool bNewPoint
= false;
1594 while( y2
> c1
- c2
* x2
&& y
> 0 )
1600 // old y now too big: set point with old y, old x
1601 if( bNewPoint
&& x
>1)
1604 // remove points on the same line
1605 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1606 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1607 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1608 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1610 } // calculate point
1612 // Starting and/or ending points for the quadrants, first quadrant gets both.
1613 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1614 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1615 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1616 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1617 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1619 // copy quadrants in original list
1622 // Copy the right part of the points in the lists
1623 // and delete the wxPoints, because they do not leave this method.
1624 points
->Append( new wxPoint( xsa
, ysa
) );
1626 bool bStarted
= false;
1627 bool bReady
= false;
1628 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1631 wxPointList::compatibility_iterator node
;
1632 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1634 // once: go to starting point in start quadrant
1637 node
->GetData()->x
< xsa
+1 && q
<= 1
1639 node
->GetData()->x
> xsa
-1 && q
>= 2
1646 // copy point, if not at ending point
1649 if( q
!= eq
|| bForceTurn
1651 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1653 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1657 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1658 points
->Append( pPoint
);
1660 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1670 } // while not bReady
1671 points
->Append( new wxPoint( xea
, yea
) );
1674 for( q
= 0; q
< 4; ++q
)
1676 wxPointList::compatibility_iterator node
;
1677 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1679 wxPoint
*p
= node
->GetData();
1686 wxPointList::compatibility_iterator node
;
1687 // copy whole ellipse, wxPoints will be deleted outside
1688 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1690 wxPoint
*p
= node
->GetData();
1691 points
->Append( p
);
1693 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1695 wxPoint
*p
= node
->GetData();
1696 points
->Append( p
);
1698 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1700 wxPoint
*p
= node
->GetData();
1701 points
->Append( p
);
1703 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1705 wxPoint
*p
= node
->GetData();
1706 points
->Append( p
);
1709 } // CalculateEllipticPoints
1711 #endif // __WXWINCE__
1713 float wxDCImpl::GetFontPointSizeAdjustment(float dpi
)
1715 // wxMSW has long-standing bug where wxFont point size is interpreted as
1716 // "pixel size corresponding to given point size *on screen*". In other
1717 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1718 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1719 // that *all* printing code has to account for it and consequently, other
1720 // ports need to emulate this bug too:
1721 const wxSize screenPPI
= wxGetDisplayPPI();
1722 return float(screenPPI
.y
) / dpi
;