1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
7 // Copyright: (c) wxWidgets team
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
27 #include "wx/dcclient.h"
28 #include "wx/dcmemory.h"
29 #include "wx/dcscreen.h"
30 #include "wx/dcprint.h"
31 #include "wx/prntbase.h"
32 #include "wx/scopeguard.h"
36 #include "wx/module.h"
37 #include "wx/window.h"
40 #include "wx/private/textmeasure.h"
43 #include "wx/msw/dcclient.h"
44 #include "wx/msw/dcmemory.h"
45 #include "wx/msw/dcscreen.h"
49 #include "wx/gtk/dc.h"
50 #elif defined __WXGTK20__
51 #include "wx/gtk/dcclient.h"
52 #include "wx/gtk/dcmemory.h"
53 #include "wx/gtk/dcscreen.h"
54 #elif defined(__WXGTK__)
55 #include "wx/gtk1/dcclient.h"
56 #include "wx/gtk1/dcmemory.h"
57 #include "wx/gtk1/dcscreen.h"
61 #include "wx/osx/dcclient.h"
62 #include "wx/osx/dcmemory.h"
63 #include "wx/osx/dcscreen.h"
67 #include "wx/os2/dcclient.h"
68 #include "wx/os2/dcmemory.h"
69 #include "wx/os2/dcscreen.h"
73 #include "wx/cocoa/dcclient.h"
74 #include "wx/cocoa/dcmemory.h"
75 #include "wx/cocoa/dcscreen.h"
79 #include "wx/motif/dcclient.h"
80 #include "wx/motif/dcmemory.h"
81 #include "wx/motif/dcscreen.h"
85 #include "wx/x11/dcclient.h"
86 #include "wx/x11/dcmemory.h"
87 #include "wx/x11/dcscreen.h"
91 #include "wx/dfb/dcclient.h"
92 #include "wx/dfb/dcmemory.h"
93 #include "wx/dfb/dcscreen.h"
96 //----------------------------------------------------------------------------
98 //----------------------------------------------------------------------------
100 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
102 void wxDCFactory::Set(wxDCFactory
*factory
)
109 wxDCFactory
*wxDCFactory::Get()
112 m_factory
= new wxNativeDCFactory
;
117 class wxDCFactoryCleanupModule
: public wxModule
120 virtual bool OnInit() { return true; }
121 virtual void OnExit() { wxDCFactory::Set(NULL
); }
124 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
127 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
129 //-----------------------------------------------------------------------------
131 //-----------------------------------------------------------------------------
133 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
135 wxDCImpl
* const impl
= new wxWindowDCImpl( owner
, window
);
136 impl
->InheritAttributes(window
);
140 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
142 wxDCImpl
* const impl
= new wxClientDCImpl( owner
, window
);
143 impl
->InheritAttributes(window
);
147 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
149 wxDCImpl
* const impl
= new wxPaintDCImpl( owner
, window
);
150 impl
->InheritAttributes(window
);
154 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
156 return new wxMemoryDCImpl( owner
);
159 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC
*owner
, wxBitmap
& bitmap
)
161 // the bitmap may be modified when it's selected into a memory DC so make
162 // sure changing this bitmap doesn't affect any other shallow copies of it
163 // (see wxMemoryDC::SelectObject())
165 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
166 // method because this should be rarely needed and easy to work around by
167 // using the default ctor and calling SelectObjectAsSource itself
171 return new wxMemoryDCImpl(owner
, bitmap
);
174 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
176 return new wxMemoryDCImpl( owner
, dc
);
179 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
181 return new wxScreenDCImpl( owner
);
184 #if wxUSE_PRINTING_ARCHITECTURE
185 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
187 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
188 return factory
->CreatePrinterDCImpl( owner
, data
);
192 //-----------------------------------------------------------------------------
194 //-----------------------------------------------------------------------------
196 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
198 wxWindowDC::wxWindowDC(wxWindow
*win
)
199 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
203 //-----------------------------------------------------------------------------
205 //-----------------------------------------------------------------------------
207 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
209 wxClientDC::wxClientDC(wxWindow
*win
)
210 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
220 wxMemoryDC::wxMemoryDC()
221 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
225 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
226 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
230 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
231 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
235 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
237 if ( bmp
.IsSameAs(GetSelectedBitmap()) )
239 // Nothing to do, this bitmap is already selected.
243 // make sure that the given wxBitmap is not sharing its data with other
244 // wxBitmap instances as its contents will be modified by any drawing
245 // operation done on this DC
249 GetImpl()->DoSelect(bmp
);
252 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
254 GetImpl()->DoSelect(bmp
);
257 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
259 return GetImpl()->GetSelectedBitmap();
262 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
264 return GetImpl()->GetSelectedBitmap();
268 //-----------------------------------------------------------------------------
270 //-----------------------------------------------------------------------------
272 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
274 wxPaintDC::wxPaintDC(wxWindow
*win
)
275 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
279 //-----------------------------------------------------------------------------
281 //-----------------------------------------------------------------------------
283 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
285 wxScreenDC::wxScreenDC()
286 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
290 //-----------------------------------------------------------------------------
292 //-----------------------------------------------------------------------------
294 #if wxUSE_PRINTING_ARCHITECTURE
296 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
298 wxPrinterDC::wxPrinterDC()
299 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
303 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
304 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
308 wxRect
wxPrinterDC::GetPaperRect() const
310 return GetImpl()->GetPaperRect();
313 int wxPrinterDC::GetResolution() const
315 return GetImpl()->GetResolution();
318 #endif // wxUSE_PRINTING_ARCHITECTURE
320 //-----------------------------------------------------------------------------
322 //-----------------------------------------------------------------------------
324 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
326 wxDCImpl::wxDCImpl( wxDC
*owner
)
328 , m_colour(wxColourDisplay())
332 , m_isBBoxValid(false)
333 , m_logicalOriginX(0), m_logicalOriginY(0)
334 , m_deviceOriginX(0), m_deviceOriginY(0)
335 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
336 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
337 , m_userScaleX(1.0), m_userScaleY(1.0)
338 , m_scaleX(1.0), m_scaleY(1.0)
339 , m_signX(1), m_signY(1)
340 , m_contentScaleFactor(1)
341 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
342 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
343 , m_logicalFunction(wxCOPY
)
344 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
345 , m_mappingMode(wxMM_TEXT
)
348 , m_backgroundBrush()
349 , m_textForegroundColour(*wxBLACK
)
350 , m_textBackgroundColour(*wxWHITE
)
354 , m_hasCustomPalette(false)
355 #endif // wxUSE_PALETTE
359 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
360 (double)wxGetDisplaySizeMM().GetWidth();
361 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
362 (double)wxGetDisplaySizeMM().GetHeight();
368 wxDCImpl::~wxDCImpl()
372 // ----------------------------------------------------------------------------
374 // ----------------------------------------------------------------------------
376 void wxDCImpl::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
380 m_clipX1
= wxMax( m_clipX1
, x
);
381 m_clipY1
= wxMax( m_clipY1
, y
);
382 m_clipX2
= wxMin( m_clipX2
, (x
+ w
) );
383 m_clipY2
= wxMin( m_clipY2
, (y
+ h
) );
396 // ----------------------------------------------------------------------------
397 // coordinate conversions and transforms
398 // ----------------------------------------------------------------------------
400 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
402 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
405 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
407 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
410 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
412 return wxRound((double)(x
) / m_scaleX
);
415 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
417 return wxRound((double)(y
) / m_scaleY
);
420 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
422 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
425 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
427 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
430 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
432 return wxRound((double)(x
) * m_scaleX
);
435 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
437 return wxRound((double)(y
) * m_scaleY
);
440 void wxDCImpl::ComputeScaleAndOrigin()
442 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
443 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
446 void wxDCImpl::SetMapMode( wxMappingMode mode
)
451 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
454 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
457 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
460 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
464 SetLogicalScale( 1.0, 1.0 );
467 m_mappingMode
= mode
;
470 void wxDCImpl::SetUserScale( double x
, double y
)
472 // allow negative ? -> no
475 ComputeScaleAndOrigin();
478 void wxDCImpl::SetLogicalScale( double x
, double y
)
483 ComputeScaleAndOrigin();
486 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
488 m_logicalOriginX
= x
* m_signX
;
489 m_logicalOriginY
= y
* m_signY
;
490 ComputeScaleAndOrigin();
493 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
497 ComputeScaleAndOrigin();
500 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
502 m_deviceLocalOriginX
= x
;
503 m_deviceLocalOriginY
= y
;
504 ComputeScaleAndOrigin();
507 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
509 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
510 // wxWidgets 2.9: no longer override it
511 m_signX
= (xLeftRight
? 1 : -1);
512 m_signY
= (yBottomUp
? -1 : 1);
513 ComputeScaleAndOrigin();
516 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
518 wxTextMeasure
tm(GetOwner(), &m_font
);
519 return tm
.GetPartialTextExtents(text
, widths
, m_scaleX
);
522 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
526 const wxFont
*font
) const
528 wxTextMeasure
tm(GetOwner(), font
&& font
->IsOk() ? font
: &m_font
);
529 tm
.GetMultiLineTextExtent(text
, x
, y
, h
);
532 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
533 wxCoord width
, wxCoord height
)
535 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
537 wxCoord x2
= x1
+ width
,
540 // the pen width is calibrated to give 3 for width == height == 10
541 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
543 // we're drawing a scaled version of wx/generic/tick.xpm here
544 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
545 y3
= y1
+ height
/ 2; // y of the left tick branch
546 DoDrawLine(x1
, y3
, x3
, y2
);
547 DoDrawLine(x3
, y2
, x2
, y1
);
549 CalcBoundingBox(x1
, y1
);
550 CalcBoundingBox(x2
, y2
);
554 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
555 wxCoord dstWidth
, wxCoord dstHeight
,
557 wxCoord xsrc
, wxCoord ysrc
,
558 wxCoord srcWidth
, wxCoord srcHeight
,
559 wxRasterOperationMode rop
,
564 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
565 wxT("invalid blit size") );
567 // emulate the stretching by modifying the DC scale
568 double xscale
= (double)srcWidth
/dstWidth
,
569 yscale
= (double)srcHeight
/dstHeight
;
571 double xscaleOld
, yscaleOld
;
572 GetUserScale(&xscaleOld
, &yscaleOld
);
573 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
575 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
576 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
578 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
580 SetUserScale(xscaleOld
, yscaleOld
);
585 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
587 int n
= list
->GetCount();
588 wxPoint
*points
= new wxPoint
[n
];
591 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
593 wxPoint
*point
= node
->GetData();
594 points
[i
].x
= point
->x
;
595 points
[i
].y
= point
->y
;
598 DoDrawLines(n
, points
, xoffset
, yoffset
);
603 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
604 wxCoord xoffset
, wxCoord yoffset
,
605 wxPolygonFillMode fillStyle
)
607 int n
= list
->GetCount();
608 wxPoint
*points
= new wxPoint
[n
];
611 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
613 wxPoint
*point
= node
->GetData();
614 points
[i
].x
= point
->x
;
615 points
[i
].y
= point
->y
;
618 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
624 wxDCImpl::DoDrawPolyPolygon(int n
,
626 const wxPoint points
[],
627 wxCoord xoffset
, wxCoord yoffset
,
628 wxPolygonFillMode fillStyle
)
632 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
639 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
644 pts
= new wxPoint
[j
+n
-1];
645 for (i
= 0; i
< j
; i
++)
647 for (i
= 2; i
<= n
; i
++)
649 lastOfs
-= count
[n
-i
];
650 pts
[j
++] = pts
[lastOfs
];
654 wxDCPenChanger
setTransp(*m_owner
, *wxTRANSPARENT_PEN
);
655 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
658 for (i
= j
= 0; i
< n
; i
++)
660 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
668 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
669 wxCoord x2
, wxCoord y2
,
670 wxCoord x3
, wxCoord y3
)
672 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
673 DrawSpline(WXSIZEOF(points
), points
);
676 void wxDCImpl::DrawSpline(int n
, const wxPoint points
[])
679 for ( int i
= 0; i
< n
; i
++ )
680 list
.Append(const_cast<wxPoint
*>(&points
[i
]));
685 // ----------------------------------- spline code ----------------------------------------
687 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
688 double a3
, double b3
, double a4
, double b4
);
689 void wx_clear_stack();
690 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
691 double *y3
, double *x4
, double *y4
);
692 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
693 double x4
, double y4
);
694 static bool wx_spline_add_point(double x
, double y
);
695 static void wx_spline_draw_point_array(wxDC
*dc
);
697 static wxPointList wx_spline_point_list
;
699 #define half(z1, z2) ((z1+z2)/2.0)
702 /* iterative version */
704 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
707 register double xmid
, ymid
;
708 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
711 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
713 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
714 xmid
= (double)half(x2
, x3
);
715 ymid
= (double)half(y2
, y3
);
716 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
717 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
718 wx_spline_add_point( x1
, y1
);
719 wx_spline_add_point( xmid
, ymid
);
721 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
722 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
723 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
724 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
729 /* utilities used by spline drawing routines */
731 typedef struct wx_spline_stack_struct
{
732 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
735 #define SPLINE_STACK_DEPTH 20
736 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
737 static Stack
*wx_stack_top
;
738 static int wx_stack_count
;
740 void wx_clear_stack()
742 wx_stack_top
= wx_spline_stack
;
746 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
748 wx_stack_top
->x1
= x1
;
749 wx_stack_top
->y1
= y1
;
750 wx_stack_top
->x2
= x2
;
751 wx_stack_top
->y2
= y2
;
752 wx_stack_top
->x3
= x3
;
753 wx_stack_top
->y3
= y3
;
754 wx_stack_top
->x4
= x4
;
755 wx_stack_top
->y4
= y4
;
760 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
761 double *x3
, double *y3
, double *x4
, double *y4
)
763 if (wx_stack_count
== 0)
767 *x1
= wx_stack_top
->x1
;
768 *y1
= wx_stack_top
->y1
;
769 *x2
= wx_stack_top
->x2
;
770 *y2
= wx_stack_top
->y2
;
771 *x3
= wx_stack_top
->x3
;
772 *y3
= wx_stack_top
->y3
;
773 *x4
= wx_stack_top
->x4
;
774 *y4
= wx_stack_top
->y4
;
778 static bool wx_spline_add_point(double x
, double y
)
780 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
781 wx_spline_point_list
.Append(point
);
785 static void wx_spline_draw_point_array(wxDC
*dc
)
787 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
788 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
791 wxPoint
*point
= node
->GetData();
793 wx_spline_point_list
.Erase(node
);
794 node
= wx_spline_point_list
.GetFirst();
798 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
800 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
803 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
804 double x1
, y1
, x2
, y2
;
806 wxPointList::compatibility_iterator node
= points
->GetFirst();
816 node
= node
->GetNext();
821 cx1
= (double)((x1
+ x2
) / 2);
822 cy1
= (double)((y1
+ y2
) / 2);
823 cx2
= (double)((cx1
+ x2
) / 2);
824 cy2
= (double)((cy1
+ y2
) / 2);
826 wx_spline_add_point(x1
, y1
);
828 while ((node
= node
->GetNext())
829 #if !wxUSE_STD_CONTAINERS
831 #endif // !wxUSE_STD_CONTAINERS
839 cx4
= (double)(x1
+ x2
) / 2;
840 cy4
= (double)(y1
+ y2
) / 2;
841 cx3
= (double)(x1
+ cx4
) / 2;
842 cy3
= (double)(y1
+ cy4
) / 2;
844 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
848 cx2
= (double)(cx1
+ x2
) / 2;
849 cy2
= (double)(cy1
+ y2
) / 2;
852 wx_spline_add_point( cx1
, cy1
);
853 wx_spline_add_point( x2
, y2
);
855 wx_spline_draw_point_array( m_owner
);
858 #endif // wxUSE_SPLINES
862 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
863 const wxColour
& initialColour
,
864 const wxColour
& destColour
,
865 wxDirection nDirection
)
868 wxPen oldPen
= m_pen
;
869 wxBrush oldBrush
= m_brush
;
871 wxUint8 nR1
= initialColour
.Red();
872 wxUint8 nG1
= initialColour
.Green();
873 wxUint8 nB1
= initialColour
.Blue();
874 wxUint8 nR2
= destColour
.Red();
875 wxUint8 nG2
= destColour
.Green();
876 wxUint8 nB2
= destColour
.Blue();
879 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
881 wxInt32 x
= rect
.GetWidth();
882 wxInt32 w
= x
; // width of area to shade
883 wxInt32 xDelta
= w
/256; // height of one shade bend
891 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
893 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
896 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
898 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
901 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
903 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
905 wxColour
colour(nR
,nG
,nB
);
906 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
907 SetBrush(wxBrush(colour
));
908 if(nDirection
== wxEAST
)
909 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
910 xDelta
, rect
.GetHeight());
911 else //nDirection == wxWEST
912 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
913 xDelta
, rect
.GetHeight());
916 else // nDirection == wxNORTH || nDirection == wxSOUTH
918 wxInt32 y
= rect
.GetHeight();
919 wxInt32 w
= y
; // height of area to shade
920 wxInt32 yDelta
= w
/255; // height of one shade bend
928 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
930 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
933 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
935 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
938 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
940 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
942 wxColour
colour(nR
,nG
,nB
);
943 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
944 SetBrush(wxBrush(colour
));
945 if(nDirection
== wxNORTH
)
946 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
947 rect
.GetWidth(), yDelta
);
948 else //nDirection == wxSOUTH
949 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
950 rect
.GetWidth(), yDelta
);
958 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
959 const wxColour
& initialColour
,
960 const wxColour
& destColour
,
961 const wxPoint
& circleCenter
)
963 // save the old pen and ensure it is restored on exit
964 const wxPen penOrig
= m_pen
;
965 wxON_BLOCK_EXIT_SET(m_pen
, penOrig
);
967 wxUint8 nR1
= destColour
.Red();
968 wxUint8 nG1
= destColour
.Green();
969 wxUint8 nB1
= destColour
.Blue();
970 wxUint8 nR2
= initialColour
.Red();
971 wxUint8 nG2
= initialColour
.Green();
972 wxUint8 nB2
= initialColour
.Blue();
977 double cx
= rect
.GetWidth() / 2;
978 double cy
= rect
.GetHeight() / 2;
987 ptX
= circleCenter
.x
;
988 ptY
= circleCenter
.y
;
989 double nCircleOffX
= ptX
- cx
;
990 double nCircleOffY
= ptY
- cy
;
995 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
997 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
999 //get color difference
1003 dGradient
= ((dRadius
- sqrt( (dx
- cx
- nCircleOffX
) * (dx
- cx
- nCircleOffX
)
1004 +(dy
- cy
- nCircleOffY
) * (dy
- cy
- nCircleOffY
)
1009 //normalize Gradient
1014 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * dGradient
/ 100));
1015 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * dGradient
/ 100));
1016 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * dGradient
/ 100));
1019 SetPen(wxColour(nR
,nG
,nB
));
1020 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1025 void wxDCImpl::InheritAttributes(wxWindow
*win
)
1027 wxCHECK_RET( win
, "window can't be NULL" );
1029 SetFont(win
->GetFont());
1030 SetTextForeground(win
->GetForegroundColour());
1031 SetTextBackground(win
->GetBackgroundColour());
1032 SetBackground(win
->GetBackgroundColour());
1033 SetLayoutDirection(win
->GetLayoutDirection());
1036 void wxDCImpl::DoGetFontMetrics(int *height
,
1039 int *internalLeading
,
1040 int *externalLeading
,
1041 int *averageWidth
) const
1043 // Average width is typically the same as width of 'x'.
1045 DoGetTextExtent("x", averageWidth
, &h
, &d
, externalLeading
);
1053 if ( internalLeading
)
1054 *internalLeading
= 0;
1057 //-----------------------------------------------------------------------------
1059 //-----------------------------------------------------------------------------
1061 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1063 void wxDC::CopyAttributes(const wxDC
& dc
)
1065 SetFont(dc
.GetFont());
1066 SetTextForeground(dc
.GetTextForeground());
1067 SetTextBackground(dc
.GetTextBackground());
1068 SetBackground(dc
.GetBackground());
1069 SetLayoutDirection(dc
.GetLayoutDirection());
1072 void wxDC::DrawLabel(const wxString
& text
,
1073 const wxBitmap
& bitmap
,
1077 wxRect
*rectBounding
)
1079 // find the text position
1080 wxCoord widthText
, heightText
, heightLine
;
1081 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1083 wxCoord width
, height
;
1084 if ( bitmap
.IsOk() )
1086 width
= widthText
+ bitmap
.GetWidth();
1087 height
= bitmap
.GetHeight();
1092 height
= heightText
;
1096 if ( alignment
& wxALIGN_RIGHT
)
1098 x
= rect
.GetRight() - width
;
1100 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1102 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1104 else // alignment & wxALIGN_LEFT
1109 if ( alignment
& wxALIGN_BOTTOM
)
1111 y
= rect
.GetBottom() - height
;
1113 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1115 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1117 else // alignment & wxALIGN_TOP
1122 // draw the bitmap first
1126 if ( bitmap
.IsOk() )
1128 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1130 wxCoord offset
= bitmap
.GetWidth() + 4;
1134 y
+= (height
- heightText
) / 2;
1137 // we will draw the underscore under the accel char later
1138 wxCoord startUnderscore
= 0,
1142 // split the string into lines and draw each of them separately
1144 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1145 // strings natively, this is not the case for all of them, notably not
1146 // wxMSW which uses this function for multi-line texts, so we may only
1147 // call DrawText() for single-line strings from here to avoid infinite
1150 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1152 if ( pc
== text
.end() || *pc
== '\n' )
1154 int xRealStart
= x
; // init it here to avoid compielr warnings
1156 if ( !curLine
.empty() )
1158 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1159 // wxALIGN_LEFT is 0
1160 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1163 GetTextExtent(curLine
, &widthLine
, NULL
);
1165 if ( alignment
& wxALIGN_RIGHT
)
1167 xRealStart
+= width
- widthLine
;
1169 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1171 xRealStart
+= (width
- widthLine
) / 2;
1174 //else: left aligned, nothing to do
1176 DrawText(curLine
, xRealStart
, y
);
1181 // do we have underscore in this line? we can check yUnderscore
1182 // because it is set below to just y + heightLine if we do
1183 if ( y
== yUnderscore
)
1185 // adjust the horz positions to account for the shift
1186 startUnderscore
+= xRealStart
;
1187 endUnderscore
+= xRealStart
;
1190 if ( pc
== text
.end() )
1195 else // not end of line
1197 if ( pc
- text
.begin() == indexAccel
)
1199 // remember to draw underscore here
1200 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1202 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1204 yUnderscore
= y
+ heightLine
;
1213 // draw the underscore if found
1214 if ( startUnderscore
!= endUnderscore
)
1216 // it should be of the same colour as text
1217 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1219 // This adjustment is relatively arbitrary: we need to draw the
1220 // underline slightly higher to avoid overflowing the character cell
1221 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1223 // The currently used value seems to be compatible with native MSW
1224 // behaviour, i.e. it results in the same appearance of the owner-drawn
1225 // and normal labels.
1228 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1231 // return bounding rect if requested
1234 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1237 CalcBoundingBox(x0
, y0
);
1238 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1241 #if WXWIN_COMPATIBILITY_2_8
1242 // for compatibility with the old code when wxCoord was long everywhere
1243 void wxDC::GetTextExtent(const wxString
& string
,
1246 long *externalLeading
,
1247 const wxFont
*theFont
) const
1249 wxCoord x2
, y2
, descent2
, externalLeading2
;
1250 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1251 &descent2
, &externalLeading2
,
1258 *descent
= descent2
;
1259 if ( externalLeading
)
1260 *externalLeading
= externalLeading2
;
1263 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1266 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1273 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1276 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1283 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1285 wxCoord xx
,yy
,ww
,hh
;
1286 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1293 void wxDC::DrawObject(wxDrawObject
* drawobject
)
1295 drawobject
->Draw(*this);
1296 CalcBoundingBox(drawobject
->MinX(),drawobject
->MinY());
1297 CalcBoundingBox(drawobject
->MaxX(),drawobject
->MaxY());
1300 #endif // WXWIN_COMPATIBILITY_2_8
1303 Notes for wxWidgets DrawEllipticArcRot(...)
1305 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1306 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1309 All methods are generic, so they can be implemented in wxDCBase.
1310 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1311 methods like (WinCE) wxDC::DoDrawArc(...).
1313 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1314 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1315 parts) or every column (in steep parts) only one pixel is calculated.
1316 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1317 starting angle is not equal to the ending angle. The calculation of the
1318 pixels is done using simple arithmetic only and should perform not too
1319 bad even on devices without floating point processor. I didn't test this yet.
1321 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1322 For instance: an ellipse rotated 180 degrees is drawn
1323 slightly different from the original.
1325 The points are then moved to an array and used to draw a polyline and/or polygon
1326 (with center added, the pie).
1327 The result looks quite similar to the native ellipse, only e few pixels differ.
1329 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1330 slower as DrawEllipse(...), which calls the native API.
1331 An rotated ellipse outside the clipping region takes nearly the same time,
1332 while an native ellipse outside takes nearly no time to draw.
1334 If you draw an arc with this new method, you will see the starting and ending angles
1335 are calculated properly.
1336 If you use DrawEllipticArc(...), you will see they are only correct for circles
1337 and not properly calculated for ellipses.
1340 p.lenhard@t-online.de
1344 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1345 wxCoord w
, wxCoord h
,
1346 double sa
, double ea
, double angle
)
1350 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1351 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1353 // Add center (for polygon/pie)
1354 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1356 // copy list into array and delete list elements
1357 int n
= list
.GetCount();
1358 wxPoint
*points
= new wxPoint
[n
];
1360 wxPointList::compatibility_iterator node
;
1361 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1363 wxPoint
*point
= node
->GetData();
1364 points
[i
].x
= point
->x
;
1365 points
[i
].y
= point
->y
;
1369 // first draw the pie without pen, if necessary
1370 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1372 wxPen
tempPen( GetPen() );
1373 SetPen( *wxTRANSPARENT_PEN
);
1374 DoDrawPolygon( n
, points
, 0, 0 );
1378 // then draw the arc without brush, if necessary
1379 if( GetPen() != *wxTRANSPARENT_PEN
)
1382 DoDrawLines( n
-1, points
, 0, 0 );
1387 } // DrawEllipticArcRot
1389 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1394 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1395 double dCosA
= cos(angle
*2.0*pi
/360.0);
1396 wxPointList::compatibility_iterator node
;
1397 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1399 wxPoint
* point
= node
->GetData();
1401 // transform coordinates, if necessary
1402 if( center
.x
) point
->x
-= center
.x
;
1403 if( center
.y
) point
->y
-= center
.y
;
1405 // calculate rotation, rounding simply by implicit cast to integer
1406 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1407 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1410 // back transform coordinates, if necessary
1411 if( center
.x
) point
->x
+= center
.x
;
1412 if( center
.y
) point
->y
+= center
.y
;
1417 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1418 wxCoord xStart
, wxCoord yStart
,
1419 wxCoord w
, wxCoord h
,
1420 double sa
, double ea
)
1431 bool bUseAngles
= false;
1437 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1439 if( 2*a
== w
) decrX
= 1;
1441 if( 2*b
== h
) decrY
= 1;
1443 wxCoord xCenter
= xStart
+ a
;
1444 wxCoord yCenter
= yStart
+ b
;
1445 // calculate data for start and end, if necessary
1449 // normalisation of angles
1450 while( sa
<0 ) sa
+= 360;
1451 while( ea
<0 ) ea
+= 360;
1452 while( sa
>=360 ) sa
-= 360;
1453 while( ea
>=360 ) ea
-= 360;
1454 // calculate quadrant numbers
1455 if( sa
> 270 ) sq
= 3;
1456 else if( sa
> 180 ) sq
= 2;
1457 else if( sa
> 90 ) sq
= 1;
1458 if( ea
> 270 ) eq
= 3;
1459 else if( ea
> 180 ) eq
= 2;
1460 else if( ea
> 90 ) eq
= 1;
1461 sar
= sa
* pi
/ 180.0;
1462 ear
= ea
* pi
/ 180.0;
1463 // correct angle circle -> ellipse
1464 sar
= atan( -a
/(double)b
* tan( sar
) );
1465 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1466 ear
= atan( -a
/(double)b
* tan( ear
) );
1467 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1468 // coordinates of points
1469 xsa
= xCenter
+ a
* cos( sar
);
1470 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1471 ysa
= yCenter
+ b
* sin( sar
);
1472 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1473 xea
= xCenter
+ a
* cos( ear
);
1474 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1475 yea
= yCenter
+ b
* sin( ear
);
1476 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1478 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1480 double c2
= 2.0 / w
;
1489 // Lists for quadrant 1 to 4
1490 wxPointList pointsarray
[4];
1491 // Calculate points for first quadrant and set in all quadrants
1492 for( x
= 0; x
<= a
; ++x
)
1497 bool bNewPoint
= false;
1498 while( y2
> c1
- c2
* x2
&& y
> 0 )
1504 // old y now too big: set point with old y, old x
1505 if( bNewPoint
&& x
>1)
1508 // remove points on the same line
1509 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1510 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1511 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1512 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1514 } // calculate point
1516 // Starting and/or ending points for the quadrants, first quadrant gets both.
1517 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1518 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1519 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1520 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1521 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1523 // copy quadrants in original list
1526 // Copy the right part of the points in the lists
1527 // and delete the wxPoints, because they do not leave this method.
1528 points
->Append( new wxPoint( xsa
, ysa
) );
1530 bool bStarted
= false;
1531 bool bReady
= false;
1532 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1535 wxPointList::compatibility_iterator node
;
1536 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1538 // once: go to starting point in start quadrant
1541 node
->GetData()->x
< xsa
+1 && q
<= 1
1543 node
->GetData()->x
> xsa
-1 && q
>= 2
1550 // copy point, if not at ending point
1553 if( q
!= eq
|| bForceTurn
1555 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1557 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1561 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1562 points
->Append( pPoint
);
1564 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1574 } // while not bReady
1575 points
->Append( new wxPoint( xea
, yea
) );
1578 for( q
= 0; q
< 4; ++q
)
1580 wxPointList::compatibility_iterator node
;
1581 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1583 wxPoint
*p
= node
->GetData();
1590 wxPointList::compatibility_iterator node
;
1591 // copy whole ellipse, wxPoints will be deleted outside
1592 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1594 wxPoint
*p
= node
->GetData();
1595 points
->Append( p
);
1597 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1599 wxPoint
*p
= node
->GetData();
1600 points
->Append( p
);
1602 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1604 wxPoint
*p
= node
->GetData();
1605 points
->Append( p
);
1607 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1609 wxPoint
*p
= node
->GetData();
1610 points
->Append( p
);
1613 } // CalculateEllipticPoints
1615 #endif // __WXWINCE__
1617 float wxDCImpl::GetFontPointSizeAdjustment(float dpi
)
1619 // wxMSW has long-standing bug where wxFont point size is interpreted as
1620 // "pixel size corresponding to given point size *on screen*". In other
1621 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1622 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1623 // that *all* printing code has to account for it and consequently, other
1624 // ports need to emulate this bug too:
1625 const wxSize screenPPI
= wxGetDisplayPPI();
1626 return float(screenPPI
.y
) / dpi
;