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/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
38 //----------------------------------------------------------------------------
40 //----------------------------------------------------------------------------
42 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
44 void wxDCFactory::SetDCFactory( wxDCFactory
*factory
)
46 if (wxDCFactory::m_factory
)
47 delete wxDCFactory::m_factory
;
49 wxDCFactory::m_factory
= factory
;
52 wxDCFactory
*wxDCFactory::GetFactory()
54 if (!wxDCFactory::m_factory
)
55 wxDCFactory::m_factory
= new wxNativeDCFactory
;
57 return wxDCFactory::m_factory
;
60 //-----------------------------------------------------------------------------
62 //-----------------------------------------------------------------------------
64 wxImplDC
* wxNativeDCFactory::CreateWindowDC()
66 #if defined(__WXMSW__)
67 return new wxWindowsWindowImplDC();
68 #elif defined(__WXGTK20__)
69 return new wxGTKWindowImplDC();
70 #elif defined(__WXGTK__)
71 return new wxGTKWindowImplDC();
72 #elif defined(__WXMAC__)
73 return new wxMacWindowImplDC();
74 #elif defined(__WXCOCOA__)
75 return new wxCocoaWindowImplDC();
76 #elif defined(__WXMOTIF__)
77 return new wxMotifWindowImplDC();
78 #elif defined(__WXX11__)
79 return new wxX11WindowImplDC();
80 #elif defined(__WXMGL__)
81 return new wxMGLWindowImplDC();
82 #elif defined(__WXDFB__)
83 return new wxDFBWindowImplDC();
84 #elif defined(__WXPM__)
85 return new wxPMWindowImplDC();
86 #elif defined(__PALMOS__)
87 return new wxPalmWindowImplDC();
91 wxImplDC
* wxNativeDCFactory::CreateWindowDC( wxWindow
*window
)
93 #if defined(__WXMSW__)
94 return new wxWindowsWindowImplDC( window
);
95 #elif defined(__WXGTK20__)
96 return new wxGTKWindowImplDC( window
);
97 #elif defined(__WXGTK__)
98 return new wxGTKWindowImplDC( window
);
99 #elif defined(__WXMAC__)
100 return new wxMacWindowImplDC( window
);
101 #elif defined(__WXCOCOA__)
102 return new wxCocoaWindowImplDC( window
);
103 #elif defined(__WXMOTIF__)
104 return new wxMotifWindowImplDC( window
);
105 #elif defined(__WXX11__)
106 return new wxX11WindowImplDC( window
);
107 #elif defined(__WXMGL__)
108 return new wxMGLWindowImplDC( window
);
109 #elif defined(__WXDFB__)
110 return new wxDFBWindowImplDC( window
);
111 #elif defined(__WXPM__)
112 return new wxPMWindowImplDC( window
);
113 #elif defined(__PALMOS__)
114 return new wxPalmWindowImplDC( window
);
118 wxImplDC
* wxNativeDCFactory::CreateClientDC()
120 #if defined(__WXMSW__)
121 return new wxWindowsClientImplDC();
122 #elif defined(__WXGTK20__)
123 return new wxGTKClientImplDC();
124 #elif defined(__WXGTK__)
125 return new wxGTKClientImplDC();
126 #elif defined(__WXMAC__)
127 return new wxMacClientImplDC();
128 #elif defined(__WXCOCOA__)
129 return new wxCocoaClientImplDC();
130 #elif defined(__WXMOTIF__)
131 return new wxMotifClientImplDC();
132 #elif defined(__WXX11__)
133 return new wxX11ClientImplDC();
134 #elif defined(__WXMGL__)
135 return new wxMGLClientImplDC();
136 #elif defined(__WXDFB__)
137 return new wxDFBClientImplDC();
138 #elif defined(__WXPM__)
139 return new wxPMClientImplDC();
140 #elif defined(__PALMOS__)
141 return new wxPalmClientImplDC();
145 wxImplDC
* wxNativeDCFactory::CreateClientDC( wxWindow
*window
)
147 #if defined(__WXMSW__)
148 return new wxWindowsClientImplDC( window
);
149 #elif defined(__WXGTK20__)
150 return new wxGTKClientImplDC( window
);
151 #elif defined(__WXGTK__)
152 return new wxGTKClientImplDC( window
);
153 #elif defined(__WXMAC__)
154 return new wxMacClientImplDC( window
);
155 #elif defined(__WXCOCOA__)
156 return new wxCocoaClientImplDC( window
);
157 #elif defined(__WXMOTIF__)
158 return new wxMotifClientImplDC( window
);
159 #elif defined(__WXX11__)
160 return new wxX11ClientImplDC( window
);
161 #elif defined(__WXMGL__)
162 return new wxMGLClientImplDC( window
);
163 #elif defined(__WXDFB__)
164 return new wxDFBClientImplDC( window
);
165 #elif defined(__WXPM__)
166 return new wxPMClientImplDC( window
);
167 #elif defined(__PALMOS__)
168 return new wxPalmClientImplDC( window
);
172 wxImplDC
* wxNativeDCFactory::CreatePaintDC()
174 #if defined(__WXMSW__)
175 return new wxWindowsPaintImplDC();
176 #elif defined(__WXGTK20__)
177 return new wxGTKPaintImplDC();
178 #elif defined(__WXGTK__)
179 return new wxGTKPaintImplDC();
180 #elif defined(__WXMAC__)
181 return new wxMacPaintImplDC();
182 #elif defined(__WXCOCOA__)
183 return new wxCocoaPaintImplDC();
184 #elif defined(__WXMOTIF__)
185 return new wxMotifPaintImplDC();
186 #elif defined(__WXX11__)
187 return new wxX11PaintImplDC();
188 #elif defined(__WXMGL__)
189 return new wxMGLPaintImplDC();
190 #elif defined(__WXDFB__)
191 return new wxDFBPaintImplDC();
192 #elif defined(__WXPM__)
193 return new wxPMPaintImplDC();
194 #elif defined(__PALMOS__)
195 return new wxPalmPaintImplDC();
199 wxImplDC
* wxNativeDCFactory::CreatePaintDC( wxWindow
*window
)
201 #if defined(__WXMSW__)
202 return new wxWindowsPaintImplDC( window
);
203 #elif defined(__WXGTK20__)
204 return new wxGTKPaintImplDC( window
);
205 #elif defined(__WXGTK__)
206 return new wxGTKPaintImplDC( window
);
207 #elif defined(__WXMAC__)
208 return new wxMacPaintImplDC( window
);
209 #elif defined(__WXCOCOA__)
210 return new wxCocoaPaintImplDC( window
);
211 #elif defined(__WXMOTIF__)
212 return new wxMotifPaintImplDC( window
);
213 #elif defined(__WXX11__)
214 return new wxX11PaintImplDC( window
);
215 #elif defined(__WXMGL__)
216 return new wxMGLPaintImplDC( window
);
217 #elif defined(__WXDFB__)
218 return new wxDFBPaintImplDC( window
);
219 #elif defined(__WXPM__)
220 return new wxPMPaintImplDC( window
);
221 #elif defined(__PALMOS__)
222 return new wxPalmPaintImplDC( window
);
226 wxImplDC
* wxNativeDCFactory::CreateMemoryDC()
228 #if defined(__WXMSW__)
229 return new wxWindowsMemoryImplDC();
230 #elif defined(__WXGTK20__)
231 return new wxGTKMemoryImplDC();
232 #elif defined(__WXGTK__)
233 return new wxGTKMemoryImplDC();
234 #elif defined(__WXMAC__)
235 return new wxMacMemoryImplDC();
236 #elif defined(__WXCOCOA__)
237 return new wxCocoaMemoryImplDC();
238 #elif defined(__WXMOTIF__)
239 return new wxMotifMemoryImplDC();
240 #elif defined(__WXX11__)
241 return new wxX11MemoryImplDC();
242 #elif defined(__WXMGL__)
243 return new wxMGLMemoryImplDC();
244 #elif defined(__WXDFB__)
245 return new wxDFBMemoryImplDC();
246 #elif defined(__WXPM__)
247 return new wxPMMemoryImplDC();
248 #elif defined(__PALMOS__)
249 return new wxPalmMemoryImplDC();
253 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxBitmap
&bitmap
)
255 #if defined(__WXMSW__)
256 return new wxWindowsMemoryImplDC( bitmap
);
257 #elif defined(__WXGTK20__)
258 return new wxGTKMemoryImplDC( bitmap
);
259 #elif defined(__WXGTK__)
260 return new wxGTKMemoryImplDC( bitmap
);
261 #elif defined(__WXMAC__)
262 return new wxMacMemoryImplDC( bitmap
);
263 #elif defined(__WXCOCOA__)
264 return new wxCocoaMemoryImplDC( bitmap
);
265 #elif defined(__WXMOTIF__)
266 return new wxMotifMemoryImplDC( bitmap
);
267 #elif defined(__WXX11__)
268 return new wxX11MemoryImplDC( bitmap
);
269 #elif defined(__WXMGL__)
270 return new wxMGLMemoryImplDC( bitmap
);
271 #elif defined(__WXDFB__)
272 return new wxDFBMemoryImplDC( bitmap
);
273 #elif defined(__WXPM__)
274 return new wxPMMemoryImplDC( bitmap
);
275 #elif defined(__PALMOS__)
276 return new wxPalmMemoryImplDC( bitmap
);
280 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxDC
*dc
)
282 #if defined(__WXMSW__)
283 return new wxWindowsMemoryImplDC( dc
);
284 #elif defined(__WXGTK20__)
285 return new wxGTKMemoryImplDC( dc
);
286 #elif defined(__WXGTK__)
287 return new wxGTKMemoryImplDC( dc
);
288 #elif defined(__WXMAC__)
289 return new wxMacMemoryImplDC( dc
);
290 #elif defined(__WXCOCOA__)
291 return new wxCocoaMemoryImplDC( dc
);
292 #elif defined(__WXMOTIF__)
293 return new wxMotifMemoryImplDC( dc
);
294 #elif defined(__WXX11__)
295 return new wxX11MemoryImplDC( dc
);
296 #elif defined(__WXMGL__)
297 return new wxMGLMemoryImplDC( dc
);
298 #elif defined(__WXDFB__)
299 return new wxDFBMemoryImplDC( dc
);
300 #elif defined(__WXPM__)
301 return new wxPMMemoryImplDC( dc
);
302 #elif defined(__PALMOS__)
303 return new wxPalmMemoryImplDC( dc
);
307 //-----------------------------------------------------------------------------
309 //-----------------------------------------------------------------------------
311 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
313 wxWindow::wxWindowDC()
315 wxDCFactory
*factory
= wxDCFactory::GetFactory();
316 m_pimpl
= factory
->CreateWindowDC();
319 wxWindow::wxWindowDC( wxWindow
*win
)
321 wxDCFactory
*factory
= wxDCFactory::GetFactory();
322 m_pimpl
= factory
->CreateWindowDC( win
);
325 //-----------------------------------------------------------------------------
327 //-----------------------------------------------------------------------------
329 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxDC
)
331 wxClientDC::wxClientDC()
333 wxDCFactory
*factory
= wxDCFactory::GetFactory();
334 m_pimpl
= factory
->CreateClientDC();
337 wxClientDC::wxClientDC( wxWindow
*win
)
339 wxDCFactory
*factory
= wxDCFactory::GetFactory();
340 m_pimpl
= factory
->CreateClientDC( win
);
343 //-----------------------------------------------------------------------------
345 //-----------------------------------------------------------------------------
347 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
349 wxMemoryDC::wxMemoryDC()
351 wxDCFactory
*factory
= wxDCFactory::GetFactory();
352 m_pimpl
= factory
->CreateMemoryDC();
355 wxMemoryDC::wxMemoryDC( wxBitmap
& bitmap
)
357 wxDCFactory
*factory
= wxDCFactory::GetFactory();
358 m_pimpl
= factory
->CreateMemoryDC( bitmap
);
361 wxMemoryDC::wxMemoryDC( wxDC
*dc
)
363 wxDCFactory
*factory
= wxDCFactory::GetFactory();
364 m_pimpl
= factory
->CreateMemoryDC( dc
);
367 //-----------------------------------------------------------------------------
369 //-----------------------------------------------------------------------------
371 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxDC
)
373 wxPaintDC::wxPaintDC()
375 wxDCFactory
*factory
= wxDCFactory::GetFactory();
376 m_pimpl
= factory
->CreatePaintDC();
379 wxPaintDC::wxPaintDC( wxWindow
*win
)
381 wxDCFactory
*factory
= wxDCFactory::GetFactory();
382 m_pimpl
= factory
->CreatePaintDC( win
);
385 //-----------------------------------------------------------------------------
387 //-----------------------------------------------------------------------------
389 IMPLEMENT_ABSTRACT_CLASS(wxImplDC
, wxObject
)
391 wxImplDC::wxImplDC( wxDC
*owner
)
392 : m_colour(wxColourDisplay())
396 , m_isBBoxValid(false)
397 , m_logicalOriginX(0), m_logicalOriginY(0)
398 , m_deviceOriginX(0), m_deviceOriginY(0)
399 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
400 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
401 , m_userScaleX(1.0), m_userScaleY(1.0)
402 , m_scaleX(1.0), m_scaleY(1.0)
403 , m_signX(1), m_signY(1)
404 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
405 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
406 , m_logicalFunction(wxCOPY
)
407 , m_backgroundMode(wxTRANSPARENT
)
408 , m_mappingMode(wxMM_TEXT
)
411 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
412 , m_textForegroundColour(*wxBLACK
)
413 , m_textBackgroundColour(*wxWHITE
)
417 , m_hasCustomPalette(false)
418 #endif // wxUSE_PALETTE
422 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
423 (double)wxGetDisplaySizeMM().GetWidth();
424 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
425 (double)wxGetDisplaySizeMM().GetHeight();
431 wxImplDC::~wxImplDC()
435 #if WXWIN_COMPATIBILITY_2_8
436 // for compatibility with the old code when wxCoord was long everywhere
437 void wxImplDC::GetTextExtent(const wxString
& string
,
440 long *externalLeading
,
441 const wxFont
*theFont
) const
443 wxCoord x2
, y2
, descent2
, externalLeading2
;
444 DoGetTextExtent(string
, &x2
, &y2
,
445 &descent2
, &externalLeading2
,
453 if ( externalLeading
)
454 *externalLeading
= externalLeading2
;
457 void wxImplDC::GetLogicalOrigin(long *x
, long *y
) const
460 DoGetLogicalOrigin(&x2
, &y2
);
467 void wxImplDC::GetDeviceOrigin(long *x
, long *y
) const
470 DoGetDeviceOrigin(&x2
, &y2
);
477 void wxImplDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
480 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
486 #endif // WXWIN_COMPATIBILITY_2_8
490 // ----------------------------------------------------------------------------
491 // coordinate conversions and transforms
492 // ----------------------------------------------------------------------------
494 wxCoord
wxImplDC::DeviceToLogicalX(wxCoord x
) const
496 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
499 wxCoord
wxImplDC::DeviceToLogicalY(wxCoord y
) const
501 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
504 wxCoord
wxImplDC::DeviceToLogicalXRel(wxCoord x
) const
506 return wxRound((double)(x
) / m_scaleX
);
509 wxCoord
wxImplDC::DeviceToLogicalYRel(wxCoord y
) const
511 return wxRound((double)(y
) / m_scaleY
);
514 wxCoord
wxImplDC::LogicalToDeviceX(wxCoord x
) const
516 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
519 wxCoord
wxImplDC::LogicalToDeviceY(wxCoord y
) const
521 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ m_deviceLocalOriginY
;
524 wxCoord
wxImplDC::LogicalToDeviceXRel(wxCoord x
) const
526 return wxRound((double)(x
) * m_scaleX
);
529 wxCoord
wxImplDC::LogicalToDeviceYRel(wxCoord y
) const
531 return wxRound((double)(y
) * m_scaleY
);
534 void wxImplDC::ComputeScaleAndOrigin()
536 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
537 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
540 void wxImplDC::SetMapMode( int mode
)
545 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
548 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
551 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
554 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
558 SetLogicalScale( 1.0, 1.0 );
561 m_mappingMode
= mode
;
564 void wxImplDC::SetUserScale( double x
, double y
)
566 // allow negative ? -> no
569 ComputeScaleAndOrigin();
572 void wxImplDC::SetLogicalScale( double x
, double y
)
577 ComputeScaleAndOrigin();
580 void wxImplDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
582 m_logicalOriginX
= x
* m_signX
;
583 m_logicalOriginY
= y
* m_signY
;
584 ComputeScaleAndOrigin();
587 void wxImplDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
591 ComputeScaleAndOrigin();
594 void wxImplDC::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
596 m_deviceLocalOriginX
= x
;
597 m_deviceLocalOriginY
= y
;
598 ComputeScaleAndOrigin();
601 void wxImplDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
603 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
604 // wxWidgets 2.9: no longer override it
605 m_signX
= (xLeftRight
? 1 : -1);
606 m_signY
= (yBottomUp
? -1 : 1);
607 ComputeScaleAndOrigin();
611 // Each element of the widths array will be the width of the string up to and
612 // including the corresponding character in text. This is the generic
613 // implementation, the port-specific classes should do this with native APIs
614 // if available and if faster. Note: pango_layout_index_to_pos is much slower
615 // than calling GetTextExtent!!
622 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
623 ~FontWidthCache() { delete []m_widths
; }
628 m_widths
= new int[FWC_SIZE
];
630 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
638 static FontWidthCache s_fontWidthCache
;
640 bool wxImplDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
644 const size_t len
= text
.length();
648 // reset the cache if font or horizontal scale have changed
649 if ( !s_fontWidthCache
.m_widths
||
650 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
651 (s_fontWidthCache
.m_font
!= GetFont()) )
653 s_fontWidthCache
.Reset();
654 s_fontWidthCache
.m_font
= GetFont();
655 s_fontWidthCache
.m_scaleX
= m_scaleX
;
658 // Calculate the position of each character based on the widths of
659 // the previous characters
661 for ( size_t i
= 0; i
< len
; i
++ )
663 const wxChar c
= text
[i
];
664 unsigned int c_int
= (unsigned int)c
;
666 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
668 w
= s_fontWidthCache
.m_widths
[c_int
];
672 GetTextExtent(c
, &w
, &h
);
673 if (c_int
< FWC_SIZE
)
674 s_fontWidthCache
.m_widths
[c_int
] = w
;
678 widths
[i
] = totalWidth
;
684 void wxImplDC::GetMultiLineTextExtent(const wxString
& text
,
688 const wxFont
*font
) const
690 wxCoord widthTextMax
= 0, widthLine
,
691 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
694 for ( const wxChar
*pc
= text
; ; pc
++ )
696 if ( *pc
== _T('\n') || *pc
== _T('\0') )
698 if ( curLine
.empty() )
700 // we can't use GetTextExtent - it will return 0 for both width
701 // and height and an empty line should count in height
704 // assume that this line has the same height as the previous
706 if ( !heightLineDefault
)
707 heightLineDefault
= heightLine
;
709 if ( !heightLineDefault
)
711 // but we don't know it yet - choose something reasonable
712 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
716 heightTextTotal
+= heightLineDefault
;
720 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
722 if ( widthLine
> widthTextMax
)
723 widthTextMax
= widthLine
;
724 heightTextTotal
+= heightLine
;
727 if ( *pc
== _T('\n') )
746 *y
= heightTextTotal
;
751 void wxImplDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
752 wxCoord width
, wxCoord height
)
754 wxCHECK_RET( Ok(), wxT("invalid window dc") );
756 wxCoord x2
= x1
+ width
,
759 // the pen width is calibrated to give 3 for width == height == 10
760 wxDCPenChanger
pen(m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
762 // we're drawing a scaled version of wx/generic/tick.xpm here
763 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
764 y3
= y1
+ height
/ 2; // y of the left tick branch
765 DoDrawLine(x1
, y3
, x3
, y2
);
766 DoDrawLine(x3
, y2
, x2
, y1
);
768 CalcBoundingBox(x1
, y1
);
769 CalcBoundingBox(x2
, y2
);
773 wxImplDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
774 wxCoord dstWidth
, wxCoord dstHeight
,
776 wxCoord xsrc
, wxCoord ysrc
,
777 wxCoord srcWidth
, wxCoord srcHeight
,
783 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
784 _T("invalid blit size") );
786 // emulate the stretching by modifying the DC scale
787 double xscale
= (double)srcWidth
/dstWidth
,
788 yscale
= (double)srcHeight
/dstHeight
;
790 double xscaleOld
, yscaleOld
;
791 GetUserScale(&xscaleOld
, &yscaleOld
);
792 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
794 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
795 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
797 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
799 SetUserScale(xscaleOld
, yscaleOld
);
804 void wxImplDC::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
806 int n
= list
->GetCount();
807 wxPoint
*points
= new wxPoint
[n
];
810 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
812 wxPoint
*point
= (wxPoint
*)node
->GetData();
813 points
[i
].x
= point
->x
;
814 points
[i
].y
= point
->y
;
817 DoDrawLines(n
, points
, xoffset
, yoffset
);
822 void wxImplDC::DrawPolygon(const wxList
*list
,
823 wxCoord xoffset
, wxCoord yoffset
,
826 int n
= list
->GetCount();
827 wxPoint
*points
= new wxPoint
[n
];
830 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
832 wxPoint
*point
= (wxPoint
*)node
->GetData();
833 points
[i
].x
= point
->x
;
834 points
[i
].y
= point
->y
;
837 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
843 wxImplDC::DoDrawPolyPolygon(int n
,
846 wxCoord xoffset
, wxCoord yoffset
,
851 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
859 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
864 pts
= new wxPoint
[j
+n
-1];
865 for (i
= 0; i
< j
; i
++)
867 for (i
= 2; i
<= n
; i
++)
869 lastOfs
-= count
[n
-i
];
870 pts
[j
++] = pts
[lastOfs
];
874 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
875 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
877 for (i
= j
= 0; i
< n
; i
++)
879 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
887 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
888 void wxImplDC::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
892 wxPoint
*point1
= new wxPoint
;
893 point1
->x
= x1
; point1
->y
= y1
;
894 point_list
.Append((wxObject
*)point1
);
896 wxPoint
*point2
= new wxPoint
;
897 point2
->x
= x2
; point2
->y
= y2
;
898 point_list
.Append((wxObject
*)point2
);
900 wxPoint
*point3
= new wxPoint
;
901 point3
->x
= x3
; point3
->y
= y3
;
902 point_list
.Append((wxObject
*)point3
);
904 DrawSpline(&point_list
);
906 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
908 wxPoint
*p
= (wxPoint
*)node
->GetData();
913 void wxImplDC::DrawSpline(int n
, wxPoint points
[])
916 for (int i
=0; i
< n
; i
++)
918 list
.Append((wxObject
*)&points
[i
]);
924 // ----------------------------------- spline code ----------------------------------------
926 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
927 double a3
, double b3
, double a4
, double b4
);
928 void wx_clear_stack();
929 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
930 double *y3
, double *x4
, double *y4
);
931 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
932 double x4
, double y4
);
933 static bool wx_spline_add_point(double x
, double y
);
934 static void wx_spline_draw_point_array(wxDCBase
*dc
);
936 wxList wx_spline_point_list
;
938 #define half(z1, z2) ((z1+z2)/2.0)
941 /* iterative version */
943 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
946 register double xmid
, ymid
;
947 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
950 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
952 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
953 xmid
= (double)half(x2
, x3
);
954 ymid
= (double)half(y2
, y3
);
955 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
956 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
957 wx_spline_add_point( x1
, y1
);
958 wx_spline_add_point( xmid
, ymid
);
960 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
961 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
962 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
963 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
968 /* utilities used by spline drawing routines */
970 typedef struct wx_spline_stack_struct
{
971 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
974 #define SPLINE_STACK_DEPTH 20
975 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
976 static Stack
*wx_stack_top
;
977 static int wx_stack_count
;
979 void wx_clear_stack()
981 wx_stack_top
= wx_spline_stack
;
985 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
987 wx_stack_top
->x1
= x1
;
988 wx_stack_top
->y1
= y1
;
989 wx_stack_top
->x2
= x2
;
990 wx_stack_top
->y2
= y2
;
991 wx_stack_top
->x3
= x3
;
992 wx_stack_top
->y3
= y3
;
993 wx_stack_top
->x4
= x4
;
994 wx_stack_top
->y4
= y4
;
999 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1000 double *x3
, double *y3
, double *x4
, double *y4
)
1002 if (wx_stack_count
== 0)
1006 *x1
= wx_stack_top
->x1
;
1007 *y1
= wx_stack_top
->y1
;
1008 *x2
= wx_stack_top
->x2
;
1009 *y2
= wx_stack_top
->y2
;
1010 *x3
= wx_stack_top
->x3
;
1011 *y3
= wx_stack_top
->y3
;
1012 *x4
= wx_stack_top
->x4
;
1013 *y4
= wx_stack_top
->y4
;
1017 static bool wx_spline_add_point(double x
, double y
)
1019 wxPoint
*point
= new wxPoint
;
1022 wx_spline_point_list
.Append((wxObject
*)point
);
1026 static void wx_spline_draw_point_array(wxDC
*dc
)
1028 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1029 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1032 wxPoint
*point
= (wxPoint
*)node
->GetData();
1034 wx_spline_point_list
.Erase(node
);
1035 node
= wx_spline_point_list
.GetFirst();
1039 void wxImplDC::DoDrawSpline( wxList
*points
)
1041 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1044 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1045 double x1
, y1
, x2
, y2
;
1047 wxList::compatibility_iterator node
= points
->GetFirst();
1052 p
= (wxPoint
*)node
->GetData();
1057 node
= node
->GetNext();
1058 p
= (wxPoint
*)node
->GetData();
1062 cx1
= (double)((x1
+ x2
) / 2);
1063 cy1
= (double)((y1
+ y2
) / 2);
1064 cx2
= (double)((cx1
+ x2
) / 2);
1065 cy2
= (double)((cy1
+ y2
) / 2);
1067 wx_spline_add_point(x1
, y1
);
1069 while ((node
= node
->GetNext())
1072 #endif // !wxUSE_STL
1075 p
= (wxPoint
*)node
->GetData();
1080 cx4
= (double)(x1
+ x2
) / 2;
1081 cy4
= (double)(y1
+ y2
) / 2;
1082 cx3
= (double)(x1
+ cx4
) / 2;
1083 cy3
= (double)(y1
+ cy4
) / 2;
1085 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1089 cx2
= (double)(cx1
+ x2
) / 2;
1090 cy2
= (double)(cy1
+ y2
) / 2;
1093 wx_spline_add_point( cx1
, cy1
);
1094 wx_spline_add_point( x2
, y2
);
1096 wx_spline_draw_point_array( m_owner
);
1099 #endif // wxUSE_SPLINES
1102 void wxImplDC::DrawLabel(const wxString
& text
,
1103 const wxBitmap
& bitmap
,
1107 wxRect
*rectBounding
)
1109 // find the text position
1110 wxCoord widthText
, heightText
, heightLine
;
1111 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1113 wxCoord width
, height
;
1116 width
= widthText
+ bitmap
.GetWidth();
1117 height
= bitmap
.GetHeight();
1122 height
= heightText
;
1126 if ( alignment
& wxALIGN_RIGHT
)
1128 x
= rect
.GetRight() - width
;
1130 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1132 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1134 else // alignment & wxALIGN_LEFT
1139 if ( alignment
& wxALIGN_BOTTOM
)
1141 y
= rect
.GetBottom() - height
;
1143 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1145 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1147 else // alignment & wxALIGN_TOP
1152 // draw the bitmap first
1158 DoDrawBitmap(bitmap
, x
, y
, true /* use mask */);
1160 wxCoord offset
= bitmap
.GetWidth() + 4;
1164 y
+= (height
- heightText
) / 2;
1167 // we will draw the underscore under the accel char later
1168 wxCoord startUnderscore
= 0,
1172 // split the string into lines and draw each of them separately
1174 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1176 if ( *pc
== _T('\n') || pc
== text
.end() )
1178 int xRealStart
= x
; // init it here to avoid compielr warnings
1180 if ( !curLine
.empty() )
1182 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1183 // wxALIGN_LEFT is 0
1184 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1187 m_owner
->GetTextExtent(curLine
, &widthLine
, NULL
);
1189 if ( alignment
& wxALIGN_RIGHT
)
1191 xRealStart
+= width
- widthLine
;
1193 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1195 xRealStart
+= (width
- widthLine
) / 2;
1198 //else: left aligned, nothing to do
1200 DoDrawText(curLine
, xRealStart
, y
);
1205 // do we have underscore in this line? we can check yUnderscore
1206 // because it is set below to just y + heightLine if we do
1207 if ( y
== yUnderscore
)
1209 // adjust the horz positions to account for the shift
1210 startUnderscore
+= xRealStart
;
1211 endUnderscore
+= xRealStart
;
1214 if ( pc
== text
.end() )
1219 else // not end of line
1221 if ( pc
- text
.begin() == indexAccel
)
1223 // remeber to draw underscore here
1224 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1226 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1228 yUnderscore
= y
+ heightLine
;
1237 // draw the underscore if found
1238 if ( startUnderscore
!= endUnderscore
)
1240 // it should be of the same colour as text
1241 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1245 DoDrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1248 // return bounding rect if requested
1251 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1254 CalcBoundingBox(x0
, y0
);
1255 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1259 void wxImplDC::DoGradientFillLinear(const wxRect
& rect
,
1260 const wxColour
& initialColour
,
1261 const wxColour
& destColour
,
1262 wxDirection nDirection
)
1265 wxPen oldPen
= m_pen
;
1266 wxBrush oldBrush
= m_brush
;
1268 wxUint8 nR1
= initialColour
.Red();
1269 wxUint8 nG1
= initialColour
.Green();
1270 wxUint8 nB1
= initialColour
.Blue();
1271 wxUint8 nR2
= destColour
.Red();
1272 wxUint8 nG2
= destColour
.Green();
1273 wxUint8 nB2
= destColour
.Blue();
1276 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
1278 wxInt32 x
= rect
.GetWidth();
1279 wxInt32 w
= x
; // width of area to shade
1280 wxInt32 xDelta
= w
/256; // height of one shade bend
1288 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1290 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1293 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1295 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1298 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1300 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1302 wxColour
colour(nR
,nG
,nB
);
1303 SetPen(wxPen(colour
, 1, wxSOLID
));
1304 SetBrush(wxBrush(colour
));
1305 if(nDirection
== wxEAST
)
1306 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1307 xDelta
, rect
.GetHeight());
1308 else //nDirection == wxWEST
1309 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1310 xDelta
, rect
.GetHeight());
1313 else // nDirection == wxNORTH || nDirection == wxSOUTH
1315 wxInt32 y
= rect
.GetHeight();
1316 wxInt32 w
= y
; // height of area to shade
1317 wxInt32 yDelta
= w
/255; // height of one shade bend
1325 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1327 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1330 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1332 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1335 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1337 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1339 wxColour
colour(nR
,nG
,nB
);
1340 SetPen(wxPen(colour
, 1, wxSOLID
));
1341 SetBrush(wxBrush(colour
));
1342 if(nDirection
== wxNORTH
)
1343 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1344 rect
.GetWidth(), yDelta
);
1345 else //nDirection == wxSOUTH
1346 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1347 rect
.GetWidth(), yDelta
);
1355 void wxImplDC::DoGradientFillConcentric(const wxRect
& rect
,
1356 const wxColour
& initialColour
,
1357 const wxColour
& destColour
,
1358 const wxPoint
& circleCenter
)
1360 //save the old pen color
1361 wxColour oldPenColour
= m_pen
.GetColour();
1363 wxUint8 nR1
= destColour
.Red();
1364 wxUint8 nG1
= destColour
.Green();
1365 wxUint8 nB1
= destColour
.Blue();
1366 wxUint8 nR2
= initialColour
.Red();
1367 wxUint8 nG2
= initialColour
.Green();
1368 wxUint8 nB2
= initialColour
.Blue();
1373 wxInt32 cx
= rect
.GetWidth() / 2;
1374 wxInt32 cy
= rect
.GetHeight() / 2;
1382 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1383 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1385 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1387 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1389 //get color difference
1390 wxInt32 nGradient
= ((nRadius
-
1392 pow((double)(x
- cx
- nCircleOffX
), 2) +
1393 pow((double)(y
- cy
- nCircleOffY
), 2)
1394 )) * 100) / nRadius
;
1396 //normalize Gradient
1401 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1402 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1403 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1406 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1407 DoDrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
1410 //return old pen color
1411 m_pen
.SetColour(oldPenColour
);
1414 //-----------------------------------------------------------------------------
1416 //-----------------------------------------------------------------------------
1418 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1420 #if WXWIN_COMPATIBILITY_2_8
1421 // for compatibility with the old code when wxCoord was long everywhere
1422 void wxDC::GetTextExtent(const wxString
& string
,
1425 long *externalLeading
,
1426 const wxFont
*theFont
) const
1428 wxCoord x2
, y2
, descent2
, externalLeading2
;
1429 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1430 &descent2
, &externalLeading2
,
1437 *descent
= descent2
;
1438 if ( externalLeading
)
1439 *externalLeading
= externalLeading2
;
1442 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1445 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1452 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1455 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1462 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1464 wxCoord xx
,yy
,ww
,hh
;
1465 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1472 #endif // WXWIN_COMPATIBILITY_2_8
1475 #else // wxUSE_NEW_DC
1478 // bool wxDCBase::sm_cacheing = false;
1480 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1482 // ============================================================================
1484 // ============================================================================
1486 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1487 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1489 wxDCBase::wxDCBase()
1490 : m_colour(wxColourDisplay())
1493 , m_isInteractive(0)
1494 , m_isBBoxValid(false)
1495 , m_logicalOriginX(0), m_logicalOriginY(0)
1496 , m_deviceOriginX(0), m_deviceOriginY(0)
1497 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1498 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1499 , m_userScaleX(1.0), m_userScaleY(1.0)
1500 , m_scaleX(1.0), m_scaleY(1.0)
1501 , m_signX(1), m_signY(1)
1502 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1503 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1504 , m_logicalFunction(wxCOPY
)
1505 , m_backgroundMode(wxTRANSPARENT
)
1506 , m_mappingMode(wxMM_TEXT
)
1509 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1510 , m_textForegroundColour(*wxBLACK
)
1511 , m_textBackgroundColour(*wxWHITE
)
1515 , m_hasCustomPalette(false)
1516 #endif // wxUSE_PALETTE
1518 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1519 (double)wxGetDisplaySizeMM().GetWidth();
1520 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1521 (double)wxGetDisplaySizeMM().GetHeight();
1527 wxDCBase::~wxDCBase()
1531 #if WXWIN_COMPATIBILITY_2_6
1532 void wxDCBase::BeginDrawing()
1536 void wxDCBase::EndDrawing()
1539 #endif // WXWIN_COMPATIBILITY_2_6
1541 #if WXWIN_COMPATIBILITY_2_8
1542 // for compatibility with the old code when wxCoord was long everywhere
1543 void wxDCBase::GetTextExtent(const wxString
& string
,
1546 long *externalLeading
,
1547 const wxFont
*theFont
) const
1549 wxCoord x2
, y2
, descent2
, externalLeading2
;
1550 DoGetTextExtent(string
, &x2
, &y2
,
1551 &descent2
, &externalLeading2
,
1558 *descent
= descent2
;
1559 if ( externalLeading
)
1560 *externalLeading
= externalLeading2
;
1563 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1566 DoGetLogicalOrigin(&x2
, &y2
);
1573 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1576 DoGetDeviceOrigin(&x2
, &y2
);
1583 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1585 wxCoord xx
,yy
,ww
,hh
;
1586 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1592 #endif // WXWIN_COMPATIBILITY_2_8
1596 // ----------------------------------------------------------------------------
1597 // coordinate conversions and transforms
1598 // ----------------------------------------------------------------------------
1600 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1602 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1605 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1607 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1610 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1612 return wxRound((double)(x
) / m_scaleX
);
1615 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1617 return wxRound((double)(y
) / m_scaleY
);
1620 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1622 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1625 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1627 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1630 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1632 return wxRound((double)(x
) * m_scaleX
);
1635 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1637 return wxRound((double)(y
) * m_scaleY
);
1640 void wxDCBase::ComputeScaleAndOrigin()
1642 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1643 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1646 void wxDCBase::SetMapMode( int mode
)
1651 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1654 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1657 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1660 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1664 SetLogicalScale( 1.0, 1.0 );
1667 m_mappingMode
= mode
;
1670 void wxDCBase::SetUserScale( double x
, double y
)
1672 // allow negative ? -> no
1675 ComputeScaleAndOrigin();
1678 void wxDCBase::SetLogicalScale( double x
, double y
)
1681 m_logicalScaleX
= x
;
1682 m_logicalScaleY
= y
;
1683 ComputeScaleAndOrigin();
1686 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1688 m_logicalOriginX
= x
* m_signX
;
1689 m_logicalOriginY
= y
* m_signY
;
1690 ComputeScaleAndOrigin();
1693 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1695 m_deviceOriginX
= x
;
1696 m_deviceOriginY
= y
;
1697 ComputeScaleAndOrigin();
1700 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1702 m_deviceLocalOriginX
= x
;
1703 m_deviceLocalOriginY
= y
;
1704 ComputeScaleAndOrigin();
1707 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1709 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1710 // wxWidgets 2.9: no longer override it
1711 m_signX
= (xLeftRight
? 1 : -1);
1712 m_signY
= (yBottomUp
? -1 : 1);
1713 ComputeScaleAndOrigin();
1716 // ----------------------------------------------------------------------------
1718 // ----------------------------------------------------------------------------
1720 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1721 wxCoord width
, wxCoord height
)
1723 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1725 wxCoord x2
= x1
+ width
,
1728 // the pen width is calibrated to give 3 for width == height == 10
1729 wxDCPenChanger
pen((wxDC
&)*this,
1730 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1732 // we're drawing a scaled version of wx/generic/tick.xpm here
1733 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1734 y3
= y1
+ height
/ 2; // y of the left tick branch
1735 DoDrawLine(x1
, y3
, x3
, y2
);
1736 DoDrawLine(x3
, y2
, x2
, y1
);
1738 CalcBoundingBox(x1
, y1
);
1739 CalcBoundingBox(x2
, y2
);
1742 // ----------------------------------------------------------------------------
1743 // stubs for functions not implemented in all ports
1744 // ----------------------------------------------------------------------------
1747 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1748 wxCoord dstWidth
, wxCoord dstHeight
,
1750 wxCoord xsrc
, wxCoord ysrc
,
1751 wxCoord srcWidth
, wxCoord srcHeight
,
1757 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1758 _T("invalid blit size") );
1760 // emulate the stretching by modifying the DC scale
1761 double xscale
= (double)srcWidth
/dstWidth
,
1762 yscale
= (double)srcHeight
/dstHeight
;
1764 double xscaleOld
, yscaleOld
;
1765 GetUserScale(&xscaleOld
, &yscaleOld
);
1766 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1768 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1769 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1771 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1773 SetUserScale(xscaleOld
, yscaleOld
);
1778 // ----------------------------------------------------------------------------
1780 // ----------------------------------------------------------------------------
1782 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1784 int n
= list
->GetCount();
1785 wxPoint
*points
= new wxPoint
[n
];
1788 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1790 wxPoint
*point
= (wxPoint
*)node
->GetData();
1791 points
[i
].x
= point
->x
;
1792 points
[i
].y
= point
->y
;
1795 DoDrawLines(n
, points
, xoffset
, yoffset
);
1801 void wxDCBase::DrawPolygon(const wxList
*list
,
1802 wxCoord xoffset
, wxCoord yoffset
,
1805 int n
= list
->GetCount();
1806 wxPoint
*points
= new wxPoint
[n
];
1809 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1811 wxPoint
*point
= (wxPoint
*)node
->GetData();
1812 points
[i
].x
= point
->x
;
1813 points
[i
].y
= point
->y
;
1816 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1822 wxDCBase::DoDrawPolyPolygon(int n
,
1825 wxCoord xoffset
, wxCoord yoffset
,
1830 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1838 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1843 pts
= new wxPoint
[j
+n
-1];
1844 for (i
= 0; i
< j
; i
++)
1846 for (i
= 2; i
<= n
; i
++)
1848 lastOfs
-= count
[n
-i
];
1849 pts
[j
++] = pts
[lastOfs
];
1853 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1854 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1856 for (i
= j
= 0; i
< n
; i
++)
1858 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1864 // ----------------------------------------------------------------------------
1866 // ----------------------------------------------------------------------------
1870 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
1871 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1875 wxPoint
*point1
= new wxPoint
;
1876 point1
->x
= x1
; point1
->y
= y1
;
1877 point_list
.Append((wxObject
*)point1
);
1879 wxPoint
*point2
= new wxPoint
;
1880 point2
->x
= x2
; point2
->y
= y2
;
1881 point_list
.Append((wxObject
*)point2
);
1883 wxPoint
*point3
= new wxPoint
;
1884 point3
->x
= x3
; point3
->y
= y3
;
1885 point_list
.Append((wxObject
*)point3
);
1887 DrawSpline(&point_list
);
1889 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
1891 wxPoint
*p
= (wxPoint
*)node
->GetData();
1896 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
1899 for (int i
=0; i
< n
; i
++)
1901 list
.Append((wxObject
*)&points
[i
]);
1907 // ----------------------------------- spline code ----------------------------------------
1909 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1910 double a3
, double b3
, double a4
, double b4
);
1911 void wx_clear_stack();
1912 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1913 double *y3
, double *x4
, double *y4
);
1914 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1915 double x4
, double y4
);
1916 static bool wx_spline_add_point(double x
, double y
);
1917 static void wx_spline_draw_point_array(wxDCBase
*dc
);
1919 wxList wx_spline_point_list
;
1921 #define half(z1, z2) ((z1+z2)/2.0)
1924 /* iterative version */
1926 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1929 register double xmid
, ymid
;
1930 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1933 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1935 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1936 xmid
= (double)half(x2
, x3
);
1937 ymid
= (double)half(y2
, y3
);
1938 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1939 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1940 wx_spline_add_point( x1
, y1
);
1941 wx_spline_add_point( xmid
, ymid
);
1943 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1944 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1945 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1946 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1951 /* utilities used by spline drawing routines */
1953 typedef struct wx_spline_stack_struct
{
1954 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1957 #define SPLINE_STACK_DEPTH 20
1958 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1959 static Stack
*wx_stack_top
;
1960 static int wx_stack_count
;
1962 void wx_clear_stack()
1964 wx_stack_top
= wx_spline_stack
;
1968 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1970 wx_stack_top
->x1
= x1
;
1971 wx_stack_top
->y1
= y1
;
1972 wx_stack_top
->x2
= x2
;
1973 wx_stack_top
->y2
= y2
;
1974 wx_stack_top
->x3
= x3
;
1975 wx_stack_top
->y3
= y3
;
1976 wx_stack_top
->x4
= x4
;
1977 wx_stack_top
->y4
= y4
;
1982 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1983 double *x3
, double *y3
, double *x4
, double *y4
)
1985 if (wx_stack_count
== 0)
1989 *x1
= wx_stack_top
->x1
;
1990 *y1
= wx_stack_top
->y1
;
1991 *x2
= wx_stack_top
->x2
;
1992 *y2
= wx_stack_top
->y2
;
1993 *x3
= wx_stack_top
->x3
;
1994 *y3
= wx_stack_top
->y3
;
1995 *x4
= wx_stack_top
->x4
;
1996 *y4
= wx_stack_top
->y4
;
2000 static bool wx_spline_add_point(double x
, double y
)
2002 wxPoint
*point
= new wxPoint
;
2005 wx_spline_point_list
.Append((wxObject
*)point
);
2009 static void wx_spline_draw_point_array(wxDCBase
*dc
)
2011 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2012 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
2015 wxPoint
*point
= (wxPoint
*)node
->GetData();
2017 wx_spline_point_list
.Erase(node
);
2018 node
= wx_spline_point_list
.GetFirst();
2022 void wxDCBase::DoDrawSpline( wxList
*points
)
2024 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2027 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2028 double x1
, y1
, x2
, y2
;
2030 wxList::compatibility_iterator node
= points
->GetFirst();
2035 p
= (wxPoint
*)node
->GetData();
2040 node
= node
->GetNext();
2041 p
= (wxPoint
*)node
->GetData();
2045 cx1
= (double)((x1
+ x2
) / 2);
2046 cy1
= (double)((y1
+ y2
) / 2);
2047 cx2
= (double)((cx1
+ x2
) / 2);
2048 cy2
= (double)((cy1
+ y2
) / 2);
2050 wx_spline_add_point(x1
, y1
);
2052 while ((node
= node
->GetNext())
2055 #endif // !wxUSE_STL
2058 p
= (wxPoint
*)node
->GetData();
2063 cx4
= (double)(x1
+ x2
) / 2;
2064 cy4
= (double)(y1
+ y2
) / 2;
2065 cx3
= (double)(x1
+ cx4
) / 2;
2066 cy3
= (double)(y1
+ cy4
) / 2;
2068 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2072 cx2
= (double)(cx1
+ x2
) / 2;
2073 cy2
= (double)(cy1
+ y2
) / 2;
2076 wx_spline_add_point( cx1
, cy1
);
2077 wx_spline_add_point( x2
, y2
);
2079 wx_spline_draw_point_array( this );
2082 #endif // wxUSE_SPLINES
2084 // ----------------------------------------------------------------------------
2085 // Partial Text Extents
2086 // ----------------------------------------------------------------------------
2089 // Each element of the widths array will be the width of the string up to and
2090 // including the corresponding character in text. This is the generic
2091 // implementation, the port-specific classes should do this with native APIs
2092 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2093 // than calling GetTextExtent!!
2095 #define FWC_SIZE 256
2097 class FontWidthCache
2100 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
2101 ~FontWidthCache() { delete []m_widths
; }
2106 m_widths
= new int[FWC_SIZE
];
2108 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2116 static FontWidthCache s_fontWidthCache
;
2118 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2122 const size_t len
= text
.length();
2126 // reset the cache if font or horizontal scale have changed
2127 if ( !s_fontWidthCache
.m_widths
||
2128 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2129 (s_fontWidthCache
.m_font
!= GetFont()) )
2131 s_fontWidthCache
.Reset();
2132 s_fontWidthCache
.m_font
= GetFont();
2133 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2136 // Calculate the position of each character based on the widths of
2137 // the previous characters
2139 for ( size_t i
= 0; i
< len
; i
++ )
2141 const wxChar c
= text
[i
];
2142 unsigned int c_int
= (unsigned int)c
;
2144 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2146 w
= s_fontWidthCache
.m_widths
[c_int
];
2150 GetTextExtent(c
, &w
, &h
);
2151 if (c_int
< FWC_SIZE
)
2152 s_fontWidthCache
.m_widths
[c_int
] = w
;
2156 widths
[i
] = totalWidth
;
2163 // ----------------------------------------------------------------------------
2164 // enhanced text drawing
2165 // ----------------------------------------------------------------------------
2167 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2171 const wxFont
*font
) const
2173 wxCoord widthTextMax
= 0, widthLine
,
2174 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2177 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2179 if ( pc
== text
.end() || *pc
== _T('\n') )
2181 if ( curLine
.empty() )
2183 // we can't use GetTextExtent - it will return 0 for both width
2184 // and height and an empty line should count in height
2187 // assume that this line has the same height as the previous
2189 if ( !heightLineDefault
)
2190 heightLineDefault
= heightLine
;
2192 if ( !heightLineDefault
)
2194 // but we don't know it yet - choose something reasonable
2195 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2199 heightTextTotal
+= heightLineDefault
;
2203 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2205 if ( widthLine
> widthTextMax
)
2206 widthTextMax
= widthLine
;
2207 heightTextTotal
+= heightLine
;
2210 if ( pc
== text
.end() )
2228 *y
= heightTextTotal
;
2233 void wxDCBase::DrawLabel(const wxString
& text
,
2234 const wxBitmap
& bitmap
,
2238 wxRect
*rectBounding
)
2240 // find the text position
2241 wxCoord widthText
, heightText
, heightLine
;
2242 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2244 wxCoord width
, height
;
2247 width
= widthText
+ bitmap
.GetWidth();
2248 height
= bitmap
.GetHeight();
2253 height
= heightText
;
2257 if ( alignment
& wxALIGN_RIGHT
)
2259 x
= rect
.GetRight() - width
;
2261 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2263 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2265 else // alignment & wxALIGN_LEFT
2270 if ( alignment
& wxALIGN_BOTTOM
)
2272 y
= rect
.GetBottom() - height
;
2274 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2276 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2278 else // alignment & wxALIGN_TOP
2283 // draw the bitmap first
2289 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2291 wxCoord offset
= bitmap
.GetWidth() + 4;
2295 y
+= (height
- heightText
) / 2;
2298 // we will draw the underscore under the accel char later
2299 wxCoord startUnderscore
= 0,
2303 // split the string into lines and draw each of them separately
2305 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2307 if ( pc
== text
.end() || *pc
== _T('\n') )
2309 int xRealStart
= x
; // init it here to avoid compielr warnings
2311 if ( !curLine
.empty() )
2313 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2314 // wxALIGN_LEFT is 0
2315 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2318 GetTextExtent(curLine
, &widthLine
, NULL
);
2320 if ( alignment
& wxALIGN_RIGHT
)
2322 xRealStart
+= width
- widthLine
;
2324 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2326 xRealStart
+= (width
- widthLine
) / 2;
2329 //else: left aligned, nothing to do
2331 DrawText(curLine
, xRealStart
, y
);
2336 // do we have underscore in this line? we can check yUnderscore
2337 // because it is set below to just y + heightLine if we do
2338 if ( y
== yUnderscore
)
2340 // adjust the horz positions to account for the shift
2341 startUnderscore
+= xRealStart
;
2342 endUnderscore
+= xRealStart
;
2345 if ( pc
== text
.end() )
2350 else // not end of line
2352 if ( pc
- text
.begin() == indexAccel
)
2354 // remeber to draw underscore here
2355 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2357 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2359 yUnderscore
= y
+ heightLine
;
2368 // draw the underscore if found
2369 if ( startUnderscore
!= endUnderscore
)
2371 // it should be of the same colour as text
2372 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2376 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2379 // return bounding rect if requested
2382 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2385 CalcBoundingBox(x0
, y0
);
2386 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2390 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2391 const wxColour
& initialColour
,
2392 const wxColour
& destColour
,
2393 wxDirection nDirection
)
2396 wxPen oldPen
= m_pen
;
2397 wxBrush oldBrush
= m_brush
;
2399 wxUint8 nR1
= initialColour
.Red();
2400 wxUint8 nG1
= initialColour
.Green();
2401 wxUint8 nB1
= initialColour
.Blue();
2402 wxUint8 nR2
= destColour
.Red();
2403 wxUint8 nG2
= destColour
.Green();
2404 wxUint8 nB2
= destColour
.Blue();
2407 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2409 wxInt32 x
= rect
.GetWidth();
2410 wxInt32 w
= x
; // width of area to shade
2411 wxInt32 xDelta
= w
/256; // height of one shade bend
2419 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2421 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2424 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2426 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2429 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2431 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2433 wxColour
colour(nR
,nG
,nB
);
2434 SetPen(wxPen(colour
, 1, wxSOLID
));
2435 SetBrush(wxBrush(colour
));
2436 if(nDirection
== wxEAST
)
2437 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
2438 xDelta
, rect
.GetHeight());
2439 else //nDirection == wxWEST
2440 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2441 xDelta
, rect
.GetHeight());
2444 else // nDirection == wxNORTH || nDirection == wxSOUTH
2446 wxInt32 y
= rect
.GetHeight();
2447 wxInt32 w
= y
; // height of area to shade
2448 wxInt32 yDelta
= w
/255; // height of one shade bend
2456 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2458 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2461 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2463 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2466 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2468 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2470 wxColour
colour(nR
,nG
,nB
);
2471 SetPen(wxPen(colour
, 1, wxSOLID
));
2472 SetBrush(wxBrush(colour
));
2473 if(nDirection
== wxNORTH
)
2474 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2475 rect
.GetWidth(), yDelta
);
2476 else //nDirection == wxSOUTH
2477 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
2478 rect
.GetWidth(), yDelta
);
2486 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2487 const wxColour
& initialColour
,
2488 const wxColour
& destColour
,
2489 const wxPoint
& circleCenter
)
2491 //save the old pen color
2492 wxColour oldPenColour
= m_pen
.GetColour();
2494 wxUint8 nR1
= destColour
.Red();
2495 wxUint8 nG1
= destColour
.Green();
2496 wxUint8 nB1
= destColour
.Blue();
2497 wxUint8 nR2
= initialColour
.Red();
2498 wxUint8 nG2
= initialColour
.Green();
2499 wxUint8 nB2
= initialColour
.Blue();
2504 wxInt32 cx
= rect
.GetWidth() / 2;
2505 wxInt32 cy
= rect
.GetHeight() / 2;
2513 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2514 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2516 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2518 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2520 //get color difference
2521 wxInt32 nGradient
= ((nRadius
-
2523 pow((double)(x
- cx
- nCircleOffX
), 2) +
2524 pow((double)(y
- cy
- nCircleOffY
), 2)
2525 )) * 100) / nRadius
;
2527 //normalize Gradient
2532 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2533 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2534 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2537 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2538 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2541 //return old pen color
2542 m_pen
.SetColour(oldPenColour
);
2546 Notes for wxWidgets DrawEllipticArcRot(...)
2548 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2549 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2552 All methods are generic, so they can be implemented in wxDCBase.
2553 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2554 methods like (WinCE) wxDC::DoDrawArc(...).
2556 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2557 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2558 parts) or every column (in steep parts) only one pixel is calculated.
2559 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2560 starting angle is not equal to the ending angle. The calculation of the
2561 pixels is done using simple arithmetic only and should perform not too
2562 bad even on devices without floating point processor. I didn't test this yet.
2564 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2565 For instance: an ellipse rotated 180 degrees is drawn
2566 slightly different from the original.
2568 The points are then moved to an array and used to draw a polyline and/or polygon
2569 (with center added, the pie).
2570 The result looks quite similar to the native ellipse, only e few pixels differ.
2572 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2573 slower as DrawEllipse(...), which calls the native API.
2574 An rotated ellipse outside the clipping region takes nearly the same time,
2575 while an native ellipse outside takes nearly no time to draw.
2577 If you draw an arc with this new method, you will see the starting and ending angles
2578 are calculated properly.
2579 If you use DrawEllipticArc(...), you will see they are only correct for circles
2580 and not properly calculated for ellipses.
2583 p.lenhard@t-online.de
2587 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2588 wxCoord w
, wxCoord h
,
2589 double sa
, double ea
, double angle
)
2593 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2594 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2596 // Add center (for polygon/pie)
2597 list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) );
2599 // copy list into array and delete list elements
2600 int n
= list
.GetCount();
2601 wxPoint
*points
= new wxPoint
[n
];
2604 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2606 wxPoint
*point
= (wxPoint
*)node
->GetData();
2607 points
[i
].x
= point
->x
;
2608 points
[i
].y
= point
->y
;
2612 // first draw the pie without pen, if necessary
2613 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2615 wxPen
tempPen( GetPen() );
2616 SetPen( *wxTRANSPARENT_PEN
);
2617 DoDrawPolygon( n
, points
, 0, 0 );
2621 // then draw the arc without brush, if necessary
2622 if( GetPen() != *wxTRANSPARENT_PEN
)
2625 DoDrawLines( n
-1, points
, 0, 0 );
2630 } // DrawEllipticArcRot
2632 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center
)
2637 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2638 double dCosA
= cos(angle
*2.0*pi
/360.0);
2639 for ( wxNode
* node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2641 wxPoint
* point
= (wxPoint
*)node
->GetData();
2643 // transform coordinates, if necessary
2644 if( center
.x
) point
->x
-= center
.x
;
2645 if( center
.y
) point
->y
-= center
.y
;
2647 // calculate rotation, rounding simply by implicit cast to integer
2648 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2649 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2652 // back transform coordinates, if necessary
2653 if( center
.x
) point
->x
+= center
.x
;
2654 if( center
.y
) point
->y
+= center
.y
;
2659 void wxDCBase::CalculateEllipticPoints( wxList
* points
,
2660 wxCoord xStart
, wxCoord yStart
,
2661 wxCoord w
, wxCoord h
,
2662 double sa
, double ea
)
2673 bool bUseAngles
= false;
2679 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2681 if( 2*a
== w
) decrX
= 1;
2683 if( 2*b
== h
) decrY
= 1;
2685 wxCoord xCenter
= xStart
+ a
;
2686 wxCoord yCenter
= yStart
+ b
;
2687 // calculate data for start and end, if necessary
2691 // normalisation of angles
2692 while( sa
<0 ) sa
+= 360;
2693 while( ea
<0 ) ea
+= 360;
2694 while( sa
>=360 ) sa
-= 360;
2695 while( ea
>=360 ) ea
-= 360;
2696 // calculate quadrant numbers
2697 if( sa
> 270 ) sq
= 3;
2698 else if( sa
> 180 ) sq
= 2;
2699 else if( sa
> 90 ) sq
= 1;
2700 if( ea
> 270 ) eq
= 3;
2701 else if( ea
> 180 ) eq
= 2;
2702 else if( ea
> 90 ) eq
= 1;
2703 sar
= sa
* pi
/ 180.0;
2704 ear
= ea
* pi
/ 180.0;
2705 // correct angle circle -> ellipse
2706 sar
= atan( -a
/(double)b
* tan( sar
) );
2707 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2708 ear
= atan( -a
/(double)b
* tan( ear
) );
2709 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2710 // coordinates of points
2711 xsa
= xCenter
+ a
* cos( sar
);
2712 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2713 ysa
= yCenter
+ b
* sin( sar
);
2714 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2715 xea
= xCenter
+ a
* cos( ear
);
2716 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2717 yea
= yCenter
+ b
* sin( ear
);
2718 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2720 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2722 double c2
= 2.0 / w
;
2731 // Lists for quadrant 1 to 4
2732 wxList pointsarray
[4];
2733 // Calculate points for first quadrant and set in all quadrants
2734 for( x
= 0; x
<= a
; ++x
)
2739 bool bNewPoint
= false;
2740 while( y2
> c1
- c2
* x2
&& y
> 0 )
2746 // old y now to big: set point with old y, old x
2747 if( bNewPoint
&& x
>1)
2750 // remove points on the same line
2751 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2752 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2753 pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2754 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2756 } // calculate point
2758 // Starting and/or ending points for the quadrants, first quadrant gets both.
2759 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2760 pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
- b
) );
2761 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- a
, yCenter
) );
2762 pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2763 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2765 // copy quadrants in original list
2768 // Copy the right part of the points in the lists
2769 // and delete the wxPoints, because they do not leave this method.
2770 points
->Append( (wxObject
*) new wxPoint( xsa
, ysa
) );
2772 bool bStarted
= false;
2773 bool bReady
= false;
2774 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2777 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2779 // once: go to starting point in start quadrant
2782 ( (wxPoint
*) node
->GetData() )->x
< xsa
+1 && q
<= 1
2784 ( (wxPoint
*) node
->GetData() )->x
> xsa
-1 && q
>= 2
2791 // copy point, if not at ending point
2794 if( q
!= eq
|| bForceTurn
2796 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2798 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2802 wxPoint
* pPoint
= new wxPoint( *((wxPoint
*) node
->GetData() ) );
2803 points
->Append( (wxObject
*) pPoint
);
2805 else if( q
== eq
&& !bForceTurn
|| ( (wxPoint
*) node
->GetData() )->x
== xea
)
2815 } // while not bReady
2816 points
->Append( (wxObject
*) new wxPoint( xea
, yea
) );
2819 for( q
= 0; q
< 4; ++q
)
2821 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2823 wxPoint
*p
= (wxPoint
*)node
->GetData();
2831 // copy whole ellipse, wxPoints will be deleted outside
2832 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2834 wxObject
*p
= node
->GetData();
2835 points
->Append( p
);
2837 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2839 wxObject
*p
= node
->GetData();
2840 points
->Append( p
);
2842 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2844 wxObject
*p
= node
->GetData();
2845 points
->Append( p
);
2847 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2849 wxObject
*p
= node
->GetData();
2850 points
->Append( p
);
2853 } // CalculateEllipticPoints
2855 #endif // __WXWINCE__
2857 #endif // wxUSE_NEW_DC