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_deviceLocalOriginX
;
519 wxCoord
wxImplDC::LogicalToDeviceY(wxCoord y
) const
521 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ 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 m_signX
= (xLeftRight
? 1 : -1);
605 m_signY
= (yBottomUp
? -1 : 1);
606 ComputeScaleAndOrigin();
610 // Each element of the widths array will be the width of the string up to and
611 // including the corresponding character in text. This is the generic
612 // implementation, the port-specific classes should do this with native APIs
613 // if available and if faster. Note: pango_layout_index_to_pos is much slower
614 // than calling GetTextExtent!!
621 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
622 ~FontWidthCache() { delete []m_widths
; }
627 m_widths
= new int[FWC_SIZE
];
629 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
637 static FontWidthCache s_fontWidthCache
;
639 bool wxImplDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
643 const size_t len
= text
.length();
647 // reset the cache if font or horizontal scale have changed
648 if ( !s_fontWidthCache
.m_widths
||
649 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
650 (s_fontWidthCache
.m_font
!= GetFont()) )
652 s_fontWidthCache
.Reset();
653 s_fontWidthCache
.m_font
= GetFont();
654 s_fontWidthCache
.m_scaleX
= m_scaleX
;
657 // Calculate the position of each character based on the widths of
658 // the previous characters
660 for ( size_t i
= 0; i
< len
; i
++ )
662 const wxChar c
= text
[i
];
663 unsigned int c_int
= (unsigned int)c
;
665 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
667 w
= s_fontWidthCache
.m_widths
[c_int
];
671 GetTextExtent(c
, &w
, &h
);
672 if (c_int
< FWC_SIZE
)
673 s_fontWidthCache
.m_widths
[c_int
] = w
;
677 widths
[i
] = totalWidth
;
683 void wxImplDC::GetMultiLineTextExtent(const wxString
& text
,
687 const wxFont
*font
) const
689 wxCoord widthTextMax
= 0, widthLine
,
690 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
693 for ( const wxChar
*pc
= text
; ; pc
++ )
695 if ( *pc
== _T('\n') || *pc
== _T('\0') )
697 if ( curLine
.empty() )
699 // we can't use GetTextExtent - it will return 0 for both width
700 // and height and an empty line should count in height
703 // assume that this line has the same height as the previous
705 if ( !heightLineDefault
)
706 heightLineDefault
= heightLine
;
708 if ( !heightLineDefault
)
710 // but we don't know it yet - choose something reasonable
711 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
715 heightTextTotal
+= heightLineDefault
;
719 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
721 if ( widthLine
> widthTextMax
)
722 widthTextMax
= widthLine
;
723 heightTextTotal
+= heightLine
;
726 if ( *pc
== _T('\n') )
745 *y
= heightTextTotal
;
750 void wxImplDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
751 wxCoord width
, wxCoord height
)
753 wxCHECK_RET( Ok(), wxT("invalid window dc") );
755 wxCoord x2
= x1
+ width
,
758 // the pen width is calibrated to give 3 for width == height == 10
759 wxDCPenChanger
pen(m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
761 // we're drawing a scaled version of wx/generic/tick.xpm here
762 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
763 y3
= y1
+ height
/ 2; // y of the left tick branch
764 DoDrawLine(x1
, y3
, x3
, y2
);
765 DoDrawLine(x3
, y2
, x2
, y1
);
767 CalcBoundingBox(x1
, y1
);
768 CalcBoundingBox(x2
, y2
);
772 wxImplDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
773 wxCoord dstWidth
, wxCoord dstHeight
,
775 wxCoord xsrc
, wxCoord ysrc
,
776 wxCoord srcWidth
, wxCoord srcHeight
,
782 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
783 _T("invalid blit size") );
785 // emulate the stretching by modifying the DC scale
786 double xscale
= (double)srcWidth
/dstWidth
,
787 yscale
= (double)srcHeight
/dstHeight
;
789 double xscaleOld
, yscaleOld
;
790 GetUserScale(&xscaleOld
, &yscaleOld
);
791 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
793 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
794 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
796 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
798 SetUserScale(xscaleOld
, yscaleOld
);
803 void wxImplDC::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
805 int n
= list
->GetCount();
806 wxPoint
*points
= new wxPoint
[n
];
809 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
811 wxPoint
*point
= (wxPoint
*)node
->GetData();
812 points
[i
].x
= point
->x
;
813 points
[i
].y
= point
->y
;
816 DoDrawLines(n
, points
, xoffset
, yoffset
);
821 void wxImplDC::DrawPolygon(const wxList
*list
,
822 wxCoord xoffset
, wxCoord yoffset
,
825 int n
= list
->GetCount();
826 wxPoint
*points
= new wxPoint
[n
];
829 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
831 wxPoint
*point
= (wxPoint
*)node
->GetData();
832 points
[i
].x
= point
->x
;
833 points
[i
].y
= point
->y
;
836 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
842 wxImplDC::DoDrawPolyPolygon(int n
,
845 wxCoord xoffset
, wxCoord yoffset
,
850 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
858 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
863 pts
= new wxPoint
[j
+n
-1];
864 for (i
= 0; i
< j
; i
++)
866 for (i
= 2; i
<= n
; i
++)
868 lastOfs
-= count
[n
-i
];
869 pts
[j
++] = pts
[lastOfs
];
873 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
874 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
876 for (i
= j
= 0; i
< n
; i
++)
878 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
886 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
887 void wxImplDC::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
891 wxPoint
*point1
= new wxPoint
;
892 point1
->x
= x1
; point1
->y
= y1
;
893 point_list
.Append((wxObject
*)point1
);
895 wxPoint
*point2
= new wxPoint
;
896 point2
->x
= x2
; point2
->y
= y2
;
897 point_list
.Append((wxObject
*)point2
);
899 wxPoint
*point3
= new wxPoint
;
900 point3
->x
= x3
; point3
->y
= y3
;
901 point_list
.Append((wxObject
*)point3
);
903 DrawSpline(&point_list
);
905 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
907 wxPoint
*p
= (wxPoint
*)node
->GetData();
912 void wxImplDC::DrawSpline(int n
, wxPoint points
[])
915 for (int i
=0; i
< n
; i
++)
917 list
.Append((wxObject
*)&points
[i
]);
923 // ----------------------------------- spline code ----------------------------------------
925 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
926 double a3
, double b3
, double a4
, double b4
);
927 void wx_clear_stack();
928 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
929 double *y3
, double *x4
, double *y4
);
930 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
931 double x4
, double y4
);
932 static bool wx_spline_add_point(double x
, double y
);
933 static void wx_spline_draw_point_array(wxDCBase
*dc
);
935 wxList wx_spline_point_list
;
937 #define half(z1, z2) ((z1+z2)/2.0)
940 /* iterative version */
942 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
945 register double xmid
, ymid
;
946 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
949 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
951 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
952 xmid
= (double)half(x2
, x3
);
953 ymid
= (double)half(y2
, y3
);
954 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
955 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
956 wx_spline_add_point( x1
, y1
);
957 wx_spline_add_point( xmid
, ymid
);
959 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
960 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
961 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
962 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
967 /* utilities used by spline drawing routines */
969 typedef struct wx_spline_stack_struct
{
970 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
973 #define SPLINE_STACK_DEPTH 20
974 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
975 static Stack
*wx_stack_top
;
976 static int wx_stack_count
;
978 void wx_clear_stack()
980 wx_stack_top
= wx_spline_stack
;
984 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
986 wx_stack_top
->x1
= x1
;
987 wx_stack_top
->y1
= y1
;
988 wx_stack_top
->x2
= x2
;
989 wx_stack_top
->y2
= y2
;
990 wx_stack_top
->x3
= x3
;
991 wx_stack_top
->y3
= y3
;
992 wx_stack_top
->x4
= x4
;
993 wx_stack_top
->y4
= y4
;
998 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
999 double *x3
, double *y3
, double *x4
, double *y4
)
1001 if (wx_stack_count
== 0)
1005 *x1
= wx_stack_top
->x1
;
1006 *y1
= wx_stack_top
->y1
;
1007 *x2
= wx_stack_top
->x2
;
1008 *y2
= wx_stack_top
->y2
;
1009 *x3
= wx_stack_top
->x3
;
1010 *y3
= wx_stack_top
->y3
;
1011 *x4
= wx_stack_top
->x4
;
1012 *y4
= wx_stack_top
->y4
;
1016 static bool wx_spline_add_point(double x
, double y
)
1018 wxPoint
*point
= new wxPoint
;
1021 wx_spline_point_list
.Append((wxObject
*)point
);
1025 static void wx_spline_draw_point_array(wxDC
*dc
)
1027 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1028 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1031 wxPoint
*point
= (wxPoint
*)node
->GetData();
1033 wx_spline_point_list
.Erase(node
);
1034 node
= wx_spline_point_list
.GetFirst();
1038 void wxImplDC::DoDrawSpline( wxList
*points
)
1040 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1043 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1044 double x1
, y1
, x2
, y2
;
1046 wxList::compatibility_iterator node
= points
->GetFirst();
1051 p
= (wxPoint
*)node
->GetData();
1056 node
= node
->GetNext();
1057 p
= (wxPoint
*)node
->GetData();
1061 cx1
= (double)((x1
+ x2
) / 2);
1062 cy1
= (double)((y1
+ y2
) / 2);
1063 cx2
= (double)((cx1
+ x2
) / 2);
1064 cy2
= (double)((cy1
+ y2
) / 2);
1066 wx_spline_add_point(x1
, y1
);
1068 while ((node
= node
->GetNext())
1071 #endif // !wxUSE_STL
1074 p
= (wxPoint
*)node
->GetData();
1079 cx4
= (double)(x1
+ x2
) / 2;
1080 cy4
= (double)(y1
+ y2
) / 2;
1081 cx3
= (double)(x1
+ cx4
) / 2;
1082 cy3
= (double)(y1
+ cy4
) / 2;
1084 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1088 cx2
= (double)(cx1
+ x2
) / 2;
1089 cy2
= (double)(cy1
+ y2
) / 2;
1092 wx_spline_add_point( cx1
, cy1
);
1093 wx_spline_add_point( x2
, y2
);
1095 wx_spline_draw_point_array( m_owner
);
1098 #endif // wxUSE_SPLINES
1101 void wxImplDC::DrawLabel(const wxString
& text
,
1102 const wxBitmap
& bitmap
,
1106 wxRect
*rectBounding
)
1108 // find the text position
1109 wxCoord widthText
, heightText
, heightLine
;
1110 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1112 wxCoord width
, height
;
1115 width
= widthText
+ bitmap
.GetWidth();
1116 height
= bitmap
.GetHeight();
1121 height
= heightText
;
1125 if ( alignment
& wxALIGN_RIGHT
)
1127 x
= rect
.GetRight() - width
;
1129 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1131 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1133 else // alignment & wxALIGN_LEFT
1138 if ( alignment
& wxALIGN_BOTTOM
)
1140 y
= rect
.GetBottom() - height
;
1142 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1144 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1146 else // alignment & wxALIGN_TOP
1151 // draw the bitmap first
1157 DoDrawBitmap(bitmap
, x
, y
, true /* use mask */);
1159 wxCoord offset
= bitmap
.GetWidth() + 4;
1163 y
+= (height
- heightText
) / 2;
1166 // we will draw the underscore under the accel char later
1167 wxCoord startUnderscore
= 0,
1171 // split the string into lines and draw each of them separately
1173 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1175 if ( *pc
== _T('\n') || pc
== text
.end() )
1177 int xRealStart
= x
; // init it here to avoid compielr warnings
1179 if ( !curLine
.empty() )
1181 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1182 // wxALIGN_LEFT is 0
1183 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1186 m_owner
->GetTextExtent(curLine
, &widthLine
, NULL
);
1188 if ( alignment
& wxALIGN_RIGHT
)
1190 xRealStart
+= width
- widthLine
;
1192 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1194 xRealStart
+= (width
- widthLine
) / 2;
1197 //else: left aligned, nothing to do
1199 DoDrawText(curLine
, xRealStart
, y
);
1204 // do we have underscore in this line? we can check yUnderscore
1205 // because it is set below to just y + heightLine if we do
1206 if ( y
== yUnderscore
)
1208 // adjust the horz positions to account for the shift
1209 startUnderscore
+= xRealStart
;
1210 endUnderscore
+= xRealStart
;
1213 if ( pc
== text
.end() )
1218 else // not end of line
1220 if ( pc
- text
.begin() == indexAccel
)
1222 // remeber to draw underscore here
1223 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1225 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1227 yUnderscore
= y
+ heightLine
;
1236 // draw the underscore if found
1237 if ( startUnderscore
!= endUnderscore
)
1239 // it should be of the same colour as text
1240 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1244 DoDrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1247 // return bounding rect if requested
1250 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1253 CalcBoundingBox(x0
, y0
);
1254 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1258 void wxImplDC::DoGradientFillLinear(const wxRect
& rect
,
1259 const wxColour
& initialColour
,
1260 const wxColour
& destColour
,
1261 wxDirection nDirection
)
1264 wxPen oldPen
= m_pen
;
1265 wxBrush oldBrush
= m_brush
;
1267 wxUint8 nR1
= initialColour
.Red();
1268 wxUint8 nG1
= initialColour
.Green();
1269 wxUint8 nB1
= initialColour
.Blue();
1270 wxUint8 nR2
= destColour
.Red();
1271 wxUint8 nG2
= destColour
.Green();
1272 wxUint8 nB2
= destColour
.Blue();
1275 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
1277 wxInt32 x
= rect
.GetWidth();
1278 wxInt32 w
= x
; // width of area to shade
1279 wxInt32 xDelta
= w
/256; // height of one shade bend
1287 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1289 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1292 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1294 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1297 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1299 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1301 wxColour
colour(nR
,nG
,nB
);
1302 SetPen(wxPen(colour
, 1, wxSOLID
));
1303 SetBrush(wxBrush(colour
));
1304 if(nDirection
== wxEAST
)
1305 DoDrawRectangle(rect
.GetRight()-x
-xDelta
, rect
.GetTop(),
1306 xDelta
, rect
.GetHeight());
1307 else //nDirection == wxWEST
1308 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1309 xDelta
, rect
.GetHeight());
1312 else // nDirection == wxNORTH || nDirection == wxSOUTH
1314 wxInt32 y
= rect
.GetHeight();
1315 wxInt32 w
= y
; // height of area to shade
1316 wxInt32 yDelta
= w
/255; // height of one shade bend
1324 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1326 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1329 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1331 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1334 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1336 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1338 wxColour
colour(nR
,nG
,nB
);
1339 SetPen(wxPen(colour
, 1, wxSOLID
));
1340 SetBrush(wxBrush(colour
));
1341 if(nDirection
== wxNORTH
)
1342 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1343 rect
.GetWidth(), yDelta
);
1344 else //nDirection == wxSOUTH
1345 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
,
1346 rect
.GetWidth(), yDelta
);
1354 void wxImplDC::DoGradientFillConcentric(const wxRect
& rect
,
1355 const wxColour
& initialColour
,
1356 const wxColour
& destColour
,
1357 const wxPoint
& circleCenter
)
1359 //save the old pen color
1360 wxColour oldPenColour
= m_pen
.GetColour();
1362 wxUint8 nR1
= destColour
.Red();
1363 wxUint8 nG1
= destColour
.Green();
1364 wxUint8 nB1
= destColour
.Blue();
1365 wxUint8 nR2
= initialColour
.Red();
1366 wxUint8 nG2
= initialColour
.Green();
1367 wxUint8 nB2
= initialColour
.Blue();
1372 wxInt32 cx
= rect
.GetWidth() / 2;
1373 wxInt32 cy
= rect
.GetHeight() / 2;
1381 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1382 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1384 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1386 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1388 //get color difference
1389 wxInt32 nGradient
= ((nRadius
-
1391 pow((double)(x
- cx
- nCircleOffX
), 2) +
1392 pow((double)(y
- cy
- nCircleOffY
), 2)
1393 )) * 100) / nRadius
;
1395 //normalize Gradient
1400 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1401 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1402 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1405 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1406 DoDrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
1409 //return old pen color
1410 m_pen
.SetColour(oldPenColour
);
1413 //-----------------------------------------------------------------------------
1415 //-----------------------------------------------------------------------------
1417 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1419 #if WXWIN_COMPATIBILITY_2_8
1420 // for compatibility with the old code when wxCoord was long everywhere
1421 void wxDC::GetTextExtent(const wxString
& string
,
1424 long *externalLeading
,
1425 const wxFont
*theFont
) const
1427 wxCoord x2
, y2
, descent2
, externalLeading2
;
1428 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1429 &descent2
, &externalLeading2
,
1436 *descent
= descent2
;
1437 if ( externalLeading
)
1438 *externalLeading
= externalLeading2
;
1441 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1444 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1451 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1454 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1461 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1463 wxCoord xx
,yy
,ww
,hh
;
1464 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1471 #endif // WXWIN_COMPATIBILITY_2_8
1474 #else // wxUSE_NEW_DC
1477 // bool wxDCBase::sm_cacheing = false;
1479 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1481 // ============================================================================
1483 // ============================================================================
1485 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1486 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1488 wxDCBase::wxDCBase()
1489 : m_colour(wxColourDisplay())
1492 , m_isInteractive(0)
1493 , m_isBBoxValid(false)
1494 , m_logicalOriginX(0), m_logicalOriginY(0)
1495 , m_deviceOriginX(0), m_deviceOriginY(0)
1496 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1497 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1498 , m_userScaleX(1.0), m_userScaleY(1.0)
1499 , m_scaleX(1.0), m_scaleY(1.0)
1500 , m_signX(1), m_signY(1)
1501 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1502 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1503 , m_logicalFunction(wxCOPY
)
1504 , m_backgroundMode(wxTRANSPARENT
)
1505 , m_mappingMode(wxMM_TEXT
)
1508 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1509 , m_textForegroundColour(*wxBLACK
)
1510 , m_textBackgroundColour(*wxWHITE
)
1514 , m_hasCustomPalette(false)
1515 #endif // wxUSE_PALETTE
1517 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1518 (double)wxGetDisplaySizeMM().GetWidth();
1519 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1520 (double)wxGetDisplaySizeMM().GetHeight();
1526 wxDCBase::~wxDCBase()
1530 #if WXWIN_COMPATIBILITY_2_6
1531 void wxDCBase::BeginDrawing()
1535 void wxDCBase::EndDrawing()
1538 #endif // WXWIN_COMPATIBILITY_2_6
1540 #if WXWIN_COMPATIBILITY_2_8
1541 // for compatibility with the old code when wxCoord was long everywhere
1542 void wxDCBase::GetTextExtent(const wxString
& string
,
1545 long *externalLeading
,
1546 const wxFont
*theFont
) const
1548 wxCoord x2
, y2
, descent2
, externalLeading2
;
1549 DoGetTextExtent(string
, &x2
, &y2
,
1550 &descent2
, &externalLeading2
,
1557 *descent
= descent2
;
1558 if ( externalLeading
)
1559 *externalLeading
= externalLeading2
;
1562 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1565 DoGetLogicalOrigin(&x2
, &y2
);
1572 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1575 DoGetDeviceOrigin(&x2
, &y2
);
1582 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1584 wxCoord xx
,yy
,ww
,hh
;
1585 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1591 #endif // WXWIN_COMPATIBILITY_2_8
1595 // ----------------------------------------------------------------------------
1596 // coordinate conversions and transforms
1597 // ----------------------------------------------------------------------------
1599 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1601 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1604 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1606 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1609 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1611 return wxRound((double)(x
) / m_scaleX
);
1614 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1616 return wxRound((double)(y
) / m_scaleY
);
1619 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1621 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1624 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1626 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1629 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1631 return wxRound((double)(x
) * m_scaleX
);
1634 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1636 return wxRound((double)(y
) * m_scaleY
);
1639 void wxDCBase::ComputeScaleAndOrigin()
1641 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1642 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1645 void wxDCBase::SetMapMode( int mode
)
1650 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1653 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1656 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1659 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1663 SetLogicalScale( 1.0, 1.0 );
1666 m_mappingMode
= mode
;
1669 void wxDCBase::SetUserScale( double x
, double y
)
1671 // allow negative ? -> no
1674 ComputeScaleAndOrigin();
1677 void wxDCBase::SetLogicalScale( double x
, double y
)
1680 m_logicalScaleX
= x
;
1681 m_logicalScaleY
= y
;
1682 ComputeScaleAndOrigin();
1685 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1687 m_logicalOriginX
= x
* m_signX
;
1688 m_logicalOriginY
= y
* m_signY
;
1689 ComputeScaleAndOrigin();
1692 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1694 m_deviceOriginX
= x
;
1695 m_deviceOriginY
= y
;
1696 ComputeScaleAndOrigin();
1699 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1701 m_deviceLocalOriginX
= x
;
1702 m_deviceLocalOriginY
= y
;
1703 ComputeScaleAndOrigin();
1706 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1708 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1709 m_signX
= (xLeftRight
? 1 : -1);
1710 m_signY
= (yBottomUp
? -1 : 1);
1711 ComputeScaleAndOrigin();
1714 // ----------------------------------------------------------------------------
1716 // ----------------------------------------------------------------------------
1718 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1719 wxCoord width
, wxCoord height
)
1721 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1723 wxCoord x2
= x1
+ width
,
1726 // the pen width is calibrated to give 3 for width == height == 10
1727 wxDCPenChanger
pen((wxDC
&)*this,
1728 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1730 // we're drawing a scaled version of wx/generic/tick.xpm here
1731 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1732 y3
= y1
+ height
/ 2; // y of the left tick branch
1733 DoDrawLine(x1
, y3
, x3
, y2
);
1734 DoDrawLine(x3
, y2
, x2
, y1
);
1736 CalcBoundingBox(x1
, y1
);
1737 CalcBoundingBox(x2
, y2
);
1740 // ----------------------------------------------------------------------------
1741 // stubs for functions not implemented in all ports
1742 // ----------------------------------------------------------------------------
1745 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1746 wxCoord dstWidth
, wxCoord dstHeight
,
1748 wxCoord xsrc
, wxCoord ysrc
,
1749 wxCoord srcWidth
, wxCoord srcHeight
,
1755 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1756 _T("invalid blit size") );
1758 // emulate the stretching by modifying the DC scale
1759 double xscale
= (double)srcWidth
/dstWidth
,
1760 yscale
= (double)srcHeight
/dstHeight
;
1762 double xscaleOld
, yscaleOld
;
1763 GetUserScale(&xscaleOld
, &yscaleOld
);
1764 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1766 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1767 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1769 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1771 SetUserScale(xscaleOld
, yscaleOld
);
1776 // ----------------------------------------------------------------------------
1778 // ----------------------------------------------------------------------------
1780 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1782 int n
= list
->GetCount();
1783 wxPoint
*points
= new wxPoint
[n
];
1786 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1788 wxPoint
*point
= (wxPoint
*)node
->GetData();
1789 points
[i
].x
= point
->x
;
1790 points
[i
].y
= point
->y
;
1793 DoDrawLines(n
, points
, xoffset
, yoffset
);
1799 void wxDCBase::DrawPolygon(const wxList
*list
,
1800 wxCoord xoffset
, wxCoord yoffset
,
1803 int n
= list
->GetCount();
1804 wxPoint
*points
= new wxPoint
[n
];
1807 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1809 wxPoint
*point
= (wxPoint
*)node
->GetData();
1810 points
[i
].x
= point
->x
;
1811 points
[i
].y
= point
->y
;
1814 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1820 wxDCBase::DoDrawPolyPolygon(int n
,
1823 wxCoord xoffset
, wxCoord yoffset
,
1828 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1836 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1841 pts
= new wxPoint
[j
+n
-1];
1842 for (i
= 0; i
< j
; i
++)
1844 for (i
= 2; i
<= n
; i
++)
1846 lastOfs
-= count
[n
-i
];
1847 pts
[j
++] = pts
[lastOfs
];
1851 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1852 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1854 for (i
= j
= 0; i
< n
; i
++)
1856 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1862 // ----------------------------------------------------------------------------
1864 // ----------------------------------------------------------------------------
1868 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
1869 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1873 wxPoint
*point1
= new wxPoint
;
1874 point1
->x
= x1
; point1
->y
= y1
;
1875 point_list
.Append((wxObject
*)point1
);
1877 wxPoint
*point2
= new wxPoint
;
1878 point2
->x
= x2
; point2
->y
= y2
;
1879 point_list
.Append((wxObject
*)point2
);
1881 wxPoint
*point3
= new wxPoint
;
1882 point3
->x
= x3
; point3
->y
= y3
;
1883 point_list
.Append((wxObject
*)point3
);
1885 DrawSpline(&point_list
);
1887 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
1889 wxPoint
*p
= (wxPoint
*)node
->GetData();
1894 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
1897 for (int i
=0; i
< n
; i
++)
1899 list
.Append((wxObject
*)&points
[i
]);
1905 // ----------------------------------- spline code ----------------------------------------
1907 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1908 double a3
, double b3
, double a4
, double b4
);
1909 void wx_clear_stack();
1910 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1911 double *y3
, double *x4
, double *y4
);
1912 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1913 double x4
, double y4
);
1914 static bool wx_spline_add_point(double x
, double y
);
1915 static void wx_spline_draw_point_array(wxDCBase
*dc
);
1917 wxList wx_spline_point_list
;
1919 #define half(z1, z2) ((z1+z2)/2.0)
1922 /* iterative version */
1924 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1927 register double xmid
, ymid
;
1928 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1931 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1933 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1934 xmid
= (double)half(x2
, x3
);
1935 ymid
= (double)half(y2
, y3
);
1936 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1937 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1938 wx_spline_add_point( x1
, y1
);
1939 wx_spline_add_point( xmid
, ymid
);
1941 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1942 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1943 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1944 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1949 /* utilities used by spline drawing routines */
1951 typedef struct wx_spline_stack_struct
{
1952 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1955 #define SPLINE_STACK_DEPTH 20
1956 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1957 static Stack
*wx_stack_top
;
1958 static int wx_stack_count
;
1960 void wx_clear_stack()
1962 wx_stack_top
= wx_spline_stack
;
1966 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1968 wx_stack_top
->x1
= x1
;
1969 wx_stack_top
->y1
= y1
;
1970 wx_stack_top
->x2
= x2
;
1971 wx_stack_top
->y2
= y2
;
1972 wx_stack_top
->x3
= x3
;
1973 wx_stack_top
->y3
= y3
;
1974 wx_stack_top
->x4
= x4
;
1975 wx_stack_top
->y4
= y4
;
1980 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1981 double *x3
, double *y3
, double *x4
, double *y4
)
1983 if (wx_stack_count
== 0)
1987 *x1
= wx_stack_top
->x1
;
1988 *y1
= wx_stack_top
->y1
;
1989 *x2
= wx_stack_top
->x2
;
1990 *y2
= wx_stack_top
->y2
;
1991 *x3
= wx_stack_top
->x3
;
1992 *y3
= wx_stack_top
->y3
;
1993 *x4
= wx_stack_top
->x4
;
1994 *y4
= wx_stack_top
->y4
;
1998 static bool wx_spline_add_point(double x
, double y
)
2000 wxPoint
*point
= new wxPoint
;
2003 wx_spline_point_list
.Append((wxObject
*)point
);
2007 static void wx_spline_draw_point_array(wxDCBase
*dc
)
2009 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2010 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
2013 wxPoint
*point
= (wxPoint
*)node
->GetData();
2015 wx_spline_point_list
.Erase(node
);
2016 node
= wx_spline_point_list
.GetFirst();
2020 void wxDCBase::DoDrawSpline( wxList
*points
)
2022 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2025 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2026 double x1
, y1
, x2
, y2
;
2028 wxList::compatibility_iterator node
= points
->GetFirst();
2033 p
= (wxPoint
*)node
->GetData();
2038 node
= node
->GetNext();
2039 p
= (wxPoint
*)node
->GetData();
2043 cx1
= (double)((x1
+ x2
) / 2);
2044 cy1
= (double)((y1
+ y2
) / 2);
2045 cx2
= (double)((cx1
+ x2
) / 2);
2046 cy2
= (double)((cy1
+ y2
) / 2);
2048 wx_spline_add_point(x1
, y1
);
2050 while ((node
= node
->GetNext())
2053 #endif // !wxUSE_STL
2056 p
= (wxPoint
*)node
->GetData();
2061 cx4
= (double)(x1
+ x2
) / 2;
2062 cy4
= (double)(y1
+ y2
) / 2;
2063 cx3
= (double)(x1
+ cx4
) / 2;
2064 cy3
= (double)(y1
+ cy4
) / 2;
2066 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2070 cx2
= (double)(cx1
+ x2
) / 2;
2071 cy2
= (double)(cy1
+ y2
) / 2;
2074 wx_spline_add_point( cx1
, cy1
);
2075 wx_spline_add_point( x2
, y2
);
2077 wx_spline_draw_point_array( this );
2080 #endif // wxUSE_SPLINES
2082 // ----------------------------------------------------------------------------
2083 // Partial Text Extents
2084 // ----------------------------------------------------------------------------
2087 // Each element of the widths array will be the width of the string up to and
2088 // including the corresponding character in text. This is the generic
2089 // implementation, the port-specific classes should do this with native APIs
2090 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2091 // than calling GetTextExtent!!
2093 #define FWC_SIZE 256
2095 class FontWidthCache
2098 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
2099 ~FontWidthCache() { delete []m_widths
; }
2104 m_widths
= new int[FWC_SIZE
];
2106 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2114 static FontWidthCache s_fontWidthCache
;
2116 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2120 const size_t len
= text
.length();
2124 // reset the cache if font or horizontal scale have changed
2125 if ( !s_fontWidthCache
.m_widths
||
2126 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2127 (s_fontWidthCache
.m_font
!= GetFont()) )
2129 s_fontWidthCache
.Reset();
2130 s_fontWidthCache
.m_font
= GetFont();
2131 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2134 // Calculate the position of each character based on the widths of
2135 // the previous characters
2137 for ( size_t i
= 0; i
< len
; i
++ )
2139 const wxChar c
= text
[i
];
2140 unsigned int c_int
= (unsigned int)c
;
2142 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2144 w
= s_fontWidthCache
.m_widths
[c_int
];
2148 GetTextExtent(c
, &w
, &h
);
2149 if (c_int
< FWC_SIZE
)
2150 s_fontWidthCache
.m_widths
[c_int
] = w
;
2154 widths
[i
] = totalWidth
;
2161 // ----------------------------------------------------------------------------
2162 // enhanced text drawing
2163 // ----------------------------------------------------------------------------
2165 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2169 const wxFont
*font
) const
2171 wxCoord widthTextMax
= 0, widthLine
,
2172 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2175 for ( const wxChar
*pc
= text
; ; pc
++ )
2177 if ( *pc
== _T('\n') || *pc
== _T('\0') )
2179 if ( curLine
.empty() )
2181 // we can't use GetTextExtent - it will return 0 for both width
2182 // and height and an empty line should count in height
2185 // assume that this line has the same height as the previous
2187 if ( !heightLineDefault
)
2188 heightLineDefault
= heightLine
;
2190 if ( !heightLineDefault
)
2192 // but we don't know it yet - choose something reasonable
2193 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2197 heightTextTotal
+= heightLineDefault
;
2201 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2203 if ( widthLine
> widthTextMax
)
2204 widthTextMax
= widthLine
;
2205 heightTextTotal
+= heightLine
;
2208 if ( *pc
== _T('\n') )
2214 // the end of string
2227 *y
= heightTextTotal
;
2232 void wxDCBase::DrawLabel(const wxString
& text
,
2233 const wxBitmap
& bitmap
,
2237 wxRect
*rectBounding
)
2239 // find the text position
2240 wxCoord widthText
, heightText
, heightLine
;
2241 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2243 wxCoord width
, height
;
2246 width
= widthText
+ bitmap
.GetWidth();
2247 height
= bitmap
.GetHeight();
2252 height
= heightText
;
2256 if ( alignment
& wxALIGN_RIGHT
)
2258 x
= rect
.GetRight() - width
;
2260 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2262 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2264 else // alignment & wxALIGN_LEFT
2269 if ( alignment
& wxALIGN_BOTTOM
)
2271 y
= rect
.GetBottom() - height
;
2273 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2275 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2277 else // alignment & wxALIGN_TOP
2282 // draw the bitmap first
2288 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2290 wxCoord offset
= bitmap
.GetWidth() + 4;
2294 y
+= (height
- heightText
) / 2;
2297 // we will draw the underscore under the accel char later
2298 wxCoord startUnderscore
= 0,
2302 // split the string into lines and draw each of them separately
2304 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2306 if ( *pc
== _T('\n') || pc
== text
.end() )
2308 int xRealStart
= x
; // init it here to avoid compielr warnings
2310 if ( !curLine
.empty() )
2312 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2313 // wxALIGN_LEFT is 0
2314 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2317 GetTextExtent(curLine
, &widthLine
, NULL
);
2319 if ( alignment
& wxALIGN_RIGHT
)
2321 xRealStart
+= width
- widthLine
;
2323 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2325 xRealStart
+= (width
- widthLine
) / 2;
2328 //else: left aligned, nothing to do
2330 DrawText(curLine
, xRealStart
, y
);
2335 // do we have underscore in this line? we can check yUnderscore
2336 // because it is set below to just y + heightLine if we do
2337 if ( y
== yUnderscore
)
2339 // adjust the horz positions to account for the shift
2340 startUnderscore
+= xRealStart
;
2341 endUnderscore
+= xRealStart
;
2344 if ( pc
== text
.end() )
2349 else // not end of line
2351 if ( pc
- text
.begin() == indexAccel
)
2353 // remeber to draw underscore here
2354 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2356 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2358 yUnderscore
= y
+ heightLine
;
2367 // draw the underscore if found
2368 if ( startUnderscore
!= endUnderscore
)
2370 // it should be of the same colour as text
2371 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2375 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2378 // return bounding rect if requested
2381 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2384 CalcBoundingBox(x0
, y0
);
2385 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2389 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2390 const wxColour
& initialColour
,
2391 const wxColour
& destColour
,
2392 wxDirection nDirection
)
2395 wxPen oldPen
= m_pen
;
2396 wxBrush oldBrush
= m_brush
;
2398 wxUint8 nR1
= initialColour
.Red();
2399 wxUint8 nG1
= initialColour
.Green();
2400 wxUint8 nB1
= initialColour
.Blue();
2401 wxUint8 nR2
= destColour
.Red();
2402 wxUint8 nG2
= destColour
.Green();
2403 wxUint8 nB2
= destColour
.Blue();
2406 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2408 wxInt32 x
= rect
.GetWidth();
2409 wxInt32 w
= x
; // width of area to shade
2410 wxInt32 xDelta
= w
/256; // height of one shade bend
2418 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2420 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2423 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2425 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2428 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2430 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2432 wxColour
colour(nR
,nG
,nB
);
2433 SetPen(wxPen(colour
, 1, wxSOLID
));
2434 SetBrush(wxBrush(colour
));
2435 if(nDirection
== wxEAST
)
2436 DrawRectangle(rect
.GetRight()-x
-xDelta
, rect
.GetTop(),
2437 xDelta
, rect
.GetHeight());
2438 else //nDirection == wxWEST
2439 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2440 xDelta
, rect
.GetHeight());
2443 else // nDirection == wxNORTH || nDirection == wxSOUTH
2445 wxInt32 y
= rect
.GetHeight();
2446 wxInt32 w
= y
; // height of area to shade
2447 wxInt32 yDelta
= w
/255; // height of one shade bend
2455 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2457 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2460 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2462 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2465 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2467 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2469 wxColour
colour(nR
,nG
,nB
);
2470 SetPen(wxPen(colour
, 1, wxSOLID
));
2471 SetBrush(wxBrush(colour
));
2472 if(nDirection
== wxNORTH
)
2473 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2474 rect
.GetWidth(), yDelta
);
2475 else //nDirection == wxSOUTH
2476 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
,
2477 rect
.GetWidth(), yDelta
);
2485 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2486 const wxColour
& initialColour
,
2487 const wxColour
& destColour
,
2488 const wxPoint
& circleCenter
)
2490 //save the old pen color
2491 wxColour oldPenColour
= m_pen
.GetColour();
2493 wxUint8 nR1
= destColour
.Red();
2494 wxUint8 nG1
= destColour
.Green();
2495 wxUint8 nB1
= destColour
.Blue();
2496 wxUint8 nR2
= initialColour
.Red();
2497 wxUint8 nG2
= initialColour
.Green();
2498 wxUint8 nB2
= initialColour
.Blue();
2503 wxInt32 cx
= rect
.GetWidth() / 2;
2504 wxInt32 cy
= rect
.GetHeight() / 2;
2512 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2513 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2515 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2517 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2519 //get color difference
2520 wxInt32 nGradient
= ((nRadius
-
2522 pow((double)(x
- cx
- nCircleOffX
), 2) +
2523 pow((double)(y
- cy
- nCircleOffY
), 2)
2524 )) * 100) / nRadius
;
2526 //normalize Gradient
2531 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2532 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2533 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2536 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2537 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2540 //return old pen color
2541 m_pen
.SetColour(oldPenColour
);
2545 Notes for wxWidgets DrawEllipticArcRot(...)
2547 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2548 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2551 All methods are generic, so they can be implemented in wxDCBase.
2552 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2553 methods like (WinCE) wxDC::DoDrawArc(...).
2555 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2556 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2557 parts) or every column (in steep parts) only one pixel is calculated.
2558 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2559 starting angle is not equal to the ending angle. The calculation of the
2560 pixels is done using simple arithmetic only and should perform not too
2561 bad even on devices without floating point processor. I didn't test this yet.
2563 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2564 For instance: an ellipse rotated 180 degrees is drawn
2565 slightly different from the original.
2567 The points are then moved to an array and used to draw a polyline and/or polygon
2568 (with center added, the pie).
2569 The result looks quite similar to the native ellipse, only e few pixels differ.
2571 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2572 slower as DrawEllipse(...), which calls the native API.
2573 An rotated ellipse outside the clipping region takes nearly the same time,
2574 while an native ellipse outside takes nearly no time to draw.
2576 If you draw an arc with this new method, you will see the starting and ending angles
2577 are calculated properly.
2578 If you use DrawEllipticArc(...), you will see they are only correct for circles
2579 and not properly calculated for ellipses.
2582 p.lenhard@t-online.de
2586 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2587 wxCoord w
, wxCoord h
,
2588 double sa
, double ea
, double angle
)
2592 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2593 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2595 // Add center (for polygon/pie)
2596 list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) );
2598 // copy list into array and delete list elements
2599 int n
= list
.GetCount();
2600 wxPoint
*points
= new wxPoint
[n
];
2603 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2605 wxPoint
*point
= (wxPoint
*)node
->GetData();
2606 points
[i
].x
= point
->x
;
2607 points
[i
].y
= point
->y
;
2611 // first draw the pie without pen, if necessary
2612 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2614 wxPen
tempPen( GetPen() );
2615 SetPen( *wxTRANSPARENT_PEN
);
2616 DoDrawPolygon( n
, points
, 0, 0 );
2620 // then draw the arc without brush, if necessary
2621 if( GetPen() != *wxTRANSPARENT_PEN
)
2624 DoDrawLines( n
-1, points
, 0, 0 );
2629 } // DrawEllipticArcRot
2631 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center
)
2636 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2637 double dCosA
= cos(angle
*2.0*pi
/360.0);
2638 for ( wxNode
* node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2640 wxPoint
* point
= (wxPoint
*)node
->GetData();
2642 // transform coordinates, if necessary
2643 if( center
.x
) point
->x
-= center
.x
;
2644 if( center
.y
) point
->y
-= center
.y
;
2646 // calculate rotation, rounding simply by implicit cast to integer
2647 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2648 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2651 // back transform coordinates, if necessary
2652 if( center
.x
) point
->x
+= center
.x
;
2653 if( center
.y
) point
->y
+= center
.y
;
2658 void wxDCBase::CalculateEllipticPoints( wxList
* points
,
2659 wxCoord xStart
, wxCoord yStart
,
2660 wxCoord w
, wxCoord h
,
2661 double sa
, double ea
)
2672 bool bUseAngles
= false;
2678 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2680 if( 2*a
== w
) decrX
= 1;
2682 if( 2*b
== h
) decrY
= 1;
2684 wxCoord xCenter
= xStart
+ a
;
2685 wxCoord yCenter
= yStart
+ b
;
2686 // calculate data for start and end, if necessary
2690 // normalisation of angles
2691 while( sa
<0 ) sa
+= 360;
2692 while( ea
<0 ) ea
+= 360;
2693 while( sa
>=360 ) sa
-= 360;
2694 while( ea
>=360 ) ea
-= 360;
2695 // calculate quadrant numbers
2696 if( sa
> 270 ) sq
= 3;
2697 else if( sa
> 180 ) sq
= 2;
2698 else if( sa
> 90 ) sq
= 1;
2699 if( ea
> 270 ) eq
= 3;
2700 else if( ea
> 180 ) eq
= 2;
2701 else if( ea
> 90 ) eq
= 1;
2702 sar
= sa
* pi
/ 180.0;
2703 ear
= ea
* pi
/ 180.0;
2704 // correct angle circle -> ellipse
2705 sar
= atan( -a
/(double)b
* tan( sar
) );
2706 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2707 ear
= atan( -a
/(double)b
* tan( ear
) );
2708 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2709 // coordinates of points
2710 xsa
= xCenter
+ a
* cos( sar
);
2711 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2712 ysa
= yCenter
+ b
* sin( sar
);
2713 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2714 xea
= xCenter
+ a
* cos( ear
);
2715 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2716 yea
= yCenter
+ b
* sin( ear
);
2717 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2719 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2721 double c2
= 2.0 / w
;
2730 // Lists for quadrant 1 to 4
2731 wxList pointsarray
[4];
2732 // Calculate points for first quadrant and set in all quadrants
2733 for( x
= 0; x
<= a
; ++x
)
2738 bool bNewPoint
= false;
2739 while( y2
> c1
- c2
* x2
&& y
> 0 )
2745 // old y now to big: set point with old y, old x
2746 if( bNewPoint
&& x
>1)
2749 // remove points on the same line
2750 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2751 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2752 pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2753 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2755 } // calculate point
2757 // Starting and/or ending points for the quadrants, first quadrant gets both.
2758 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2759 pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
- b
) );
2760 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- a
, yCenter
) );
2761 pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2762 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2764 // copy quadrants in original list
2767 // Copy the right part of the points in the lists
2768 // and delete the wxPoints, because they do not leave this method.
2769 points
->Append( (wxObject
*) new wxPoint( xsa
, ysa
) );
2771 bool bStarted
= false;
2772 bool bReady
= false;
2773 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2776 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2778 // once: go to starting point in start quadrant
2781 ( (wxPoint
*) node
->GetData() )->x
< xsa
+1 && q
<= 1
2783 ( (wxPoint
*) node
->GetData() )->x
> xsa
-1 && q
>= 2
2790 // copy point, if not at ending point
2793 if( q
!= eq
|| bForceTurn
2795 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2797 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2801 wxPoint
* pPoint
= new wxPoint( *((wxPoint
*) node
->GetData() ) );
2802 points
->Append( (wxObject
*) pPoint
);
2804 else if( q
== eq
&& !bForceTurn
|| ( (wxPoint
*) node
->GetData() )->x
== xea
)
2814 } // while not bReady
2815 points
->Append( (wxObject
*) new wxPoint( xea
, yea
) );
2818 for( q
= 0; q
< 4; ++q
)
2820 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2822 wxPoint
*p
= (wxPoint
*)node
->GetData();
2830 // copy whole ellipse, wxPoints will be deleted outside
2831 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2833 wxObject
*p
= node
->GetData();
2834 points
->Append( p
);
2836 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2838 wxObject
*p
= node
->GetData();
2839 points
->Append( p
);
2841 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2843 wxObject
*p
= node
->GetData();
2844 points
->Append( p
);
2846 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2848 wxObject
*p
= node
->GetData();
2849 points
->Append( p
);
2852 } // CalculateEllipticPoints
2854 #endif // __WXWINCE__
2856 #endif // wxUSE_NEW_DC