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 ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2177 if ( pc
== text
.end() || *pc
== _T('\n') )
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
== text
.end() )
2226 *y
= heightTextTotal
;
2231 void wxDCBase::DrawLabel(const wxString
& text
,
2232 const wxBitmap
& bitmap
,
2236 wxRect
*rectBounding
)
2238 // find the text position
2239 wxCoord widthText
, heightText
, heightLine
;
2240 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2242 wxCoord width
, height
;
2245 width
= widthText
+ bitmap
.GetWidth();
2246 height
= bitmap
.GetHeight();
2251 height
= heightText
;
2255 if ( alignment
& wxALIGN_RIGHT
)
2257 x
= rect
.GetRight() - width
;
2259 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2261 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2263 else // alignment & wxALIGN_LEFT
2268 if ( alignment
& wxALIGN_BOTTOM
)
2270 y
= rect
.GetBottom() - height
;
2272 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2274 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2276 else // alignment & wxALIGN_TOP
2281 // draw the bitmap first
2287 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2289 wxCoord offset
= bitmap
.GetWidth() + 4;
2293 y
+= (height
- heightText
) / 2;
2296 // we will draw the underscore under the accel char later
2297 wxCoord startUnderscore
= 0,
2301 // split the string into lines and draw each of them separately
2303 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2305 if ( pc
== text
.end() || *pc
== _T('\n') )
2307 int xRealStart
= x
; // init it here to avoid compielr warnings
2309 if ( !curLine
.empty() )
2311 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2312 // wxALIGN_LEFT is 0
2313 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2316 GetTextExtent(curLine
, &widthLine
, NULL
);
2318 if ( alignment
& wxALIGN_RIGHT
)
2320 xRealStart
+= width
- widthLine
;
2322 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2324 xRealStart
+= (width
- widthLine
) / 2;
2327 //else: left aligned, nothing to do
2329 DrawText(curLine
, xRealStart
, y
);
2334 // do we have underscore in this line? we can check yUnderscore
2335 // because it is set below to just y + heightLine if we do
2336 if ( y
== yUnderscore
)
2338 // adjust the horz positions to account for the shift
2339 startUnderscore
+= xRealStart
;
2340 endUnderscore
+= xRealStart
;
2343 if ( pc
== text
.end() )
2348 else // not end of line
2350 if ( pc
- text
.begin() == indexAccel
)
2352 // remeber to draw underscore here
2353 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2355 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2357 yUnderscore
= y
+ heightLine
;
2366 // draw the underscore if found
2367 if ( startUnderscore
!= endUnderscore
)
2369 // it should be of the same colour as text
2370 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2374 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2377 // return bounding rect if requested
2380 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2383 CalcBoundingBox(x0
, y0
);
2384 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2388 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2389 const wxColour
& initialColour
,
2390 const wxColour
& destColour
,
2391 wxDirection nDirection
)
2394 wxPen oldPen
= m_pen
;
2395 wxBrush oldBrush
= m_brush
;
2397 wxUint8 nR1
= initialColour
.Red();
2398 wxUint8 nG1
= initialColour
.Green();
2399 wxUint8 nB1
= initialColour
.Blue();
2400 wxUint8 nR2
= destColour
.Red();
2401 wxUint8 nG2
= destColour
.Green();
2402 wxUint8 nB2
= destColour
.Blue();
2405 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2407 wxInt32 x
= rect
.GetWidth();
2408 wxInt32 w
= x
; // width of area to shade
2409 wxInt32 xDelta
= w
/256; // height of one shade bend
2417 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2419 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2422 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2424 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2427 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2429 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2431 wxColour
colour(nR
,nG
,nB
);
2432 SetPen(wxPen(colour
, 1, wxSOLID
));
2433 SetBrush(wxBrush(colour
));
2434 if(nDirection
== wxEAST
)
2435 DrawRectangle(rect
.GetRight()-x
-xDelta
, rect
.GetTop(),
2436 xDelta
, rect
.GetHeight());
2437 else //nDirection == wxWEST
2438 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2439 xDelta
, rect
.GetHeight());
2442 else // nDirection == wxNORTH || nDirection == wxSOUTH
2444 wxInt32 y
= rect
.GetHeight();
2445 wxInt32 w
= y
; // height of area to shade
2446 wxInt32 yDelta
= w
/255; // height of one shade bend
2454 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2456 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2459 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2461 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2464 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2466 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2468 wxColour
colour(nR
,nG
,nB
);
2469 SetPen(wxPen(colour
, 1, wxSOLID
));
2470 SetBrush(wxBrush(colour
));
2471 if(nDirection
== wxNORTH
)
2472 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2473 rect
.GetWidth(), yDelta
);
2474 else //nDirection == wxSOUTH
2475 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
,
2476 rect
.GetWidth(), yDelta
);
2484 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2485 const wxColour
& initialColour
,
2486 const wxColour
& destColour
,
2487 const wxPoint
& circleCenter
)
2489 //save the old pen color
2490 wxColour oldPenColour
= m_pen
.GetColour();
2492 wxUint8 nR1
= destColour
.Red();
2493 wxUint8 nG1
= destColour
.Green();
2494 wxUint8 nB1
= destColour
.Blue();
2495 wxUint8 nR2
= initialColour
.Red();
2496 wxUint8 nG2
= initialColour
.Green();
2497 wxUint8 nB2
= initialColour
.Blue();
2502 wxInt32 cx
= rect
.GetWidth() / 2;
2503 wxInt32 cy
= rect
.GetHeight() / 2;
2511 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2512 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2514 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2516 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2518 //get color difference
2519 wxInt32 nGradient
= ((nRadius
-
2521 pow((double)(x
- cx
- nCircleOffX
), 2) +
2522 pow((double)(y
- cy
- nCircleOffY
), 2)
2523 )) * 100) / nRadius
;
2525 //normalize Gradient
2530 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2531 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2532 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2535 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2536 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2539 //return old pen color
2540 m_pen
.SetColour(oldPenColour
);
2544 Notes for wxWidgets DrawEllipticArcRot(...)
2546 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2547 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2550 All methods are generic, so they can be implemented in wxDCBase.
2551 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2552 methods like (WinCE) wxDC::DoDrawArc(...).
2554 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2555 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2556 parts) or every column (in steep parts) only one pixel is calculated.
2557 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2558 starting angle is not equal to the ending angle. The calculation of the
2559 pixels is done using simple arithmetic only and should perform not too
2560 bad even on devices without floating point processor. I didn't test this yet.
2562 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2563 For instance: an ellipse rotated 180 degrees is drawn
2564 slightly different from the original.
2566 The points are then moved to an array and used to draw a polyline and/or polygon
2567 (with center added, the pie).
2568 The result looks quite similar to the native ellipse, only e few pixels differ.
2570 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2571 slower as DrawEllipse(...), which calls the native API.
2572 An rotated ellipse outside the clipping region takes nearly the same time,
2573 while an native ellipse outside takes nearly no time to draw.
2575 If you draw an arc with this new method, you will see the starting and ending angles
2576 are calculated properly.
2577 If you use DrawEllipticArc(...), you will see they are only correct for circles
2578 and not properly calculated for ellipses.
2581 p.lenhard@t-online.de
2585 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2586 wxCoord w
, wxCoord h
,
2587 double sa
, double ea
, double angle
)
2591 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2592 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2594 // Add center (for polygon/pie)
2595 list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) );
2597 // copy list into array and delete list elements
2598 int n
= list
.GetCount();
2599 wxPoint
*points
= new wxPoint
[n
];
2602 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2604 wxPoint
*point
= (wxPoint
*)node
->GetData();
2605 points
[i
].x
= point
->x
;
2606 points
[i
].y
= point
->y
;
2610 // first draw the pie without pen, if necessary
2611 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2613 wxPen
tempPen( GetPen() );
2614 SetPen( *wxTRANSPARENT_PEN
);
2615 DoDrawPolygon( n
, points
, 0, 0 );
2619 // then draw the arc without brush, if necessary
2620 if( GetPen() != *wxTRANSPARENT_PEN
)
2623 DoDrawLines( n
-1, points
, 0, 0 );
2628 } // DrawEllipticArcRot
2630 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center
)
2635 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2636 double dCosA
= cos(angle
*2.0*pi
/360.0);
2637 for ( wxNode
* node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2639 wxPoint
* point
= (wxPoint
*)node
->GetData();
2641 // transform coordinates, if necessary
2642 if( center
.x
) point
->x
-= center
.x
;
2643 if( center
.y
) point
->y
-= center
.y
;
2645 // calculate rotation, rounding simply by implicit cast to integer
2646 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2647 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2650 // back transform coordinates, if necessary
2651 if( center
.x
) point
->x
+= center
.x
;
2652 if( center
.y
) point
->y
+= center
.y
;
2657 void wxDCBase::CalculateEllipticPoints( wxList
* points
,
2658 wxCoord xStart
, wxCoord yStart
,
2659 wxCoord w
, wxCoord h
,
2660 double sa
, double ea
)
2671 bool bUseAngles
= false;
2677 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2679 if( 2*a
== w
) decrX
= 1;
2681 if( 2*b
== h
) decrY
= 1;
2683 wxCoord xCenter
= xStart
+ a
;
2684 wxCoord yCenter
= yStart
+ b
;
2685 // calculate data for start and end, if necessary
2689 // normalisation of angles
2690 while( sa
<0 ) sa
+= 360;
2691 while( ea
<0 ) ea
+= 360;
2692 while( sa
>=360 ) sa
-= 360;
2693 while( ea
>=360 ) ea
-= 360;
2694 // calculate quadrant numbers
2695 if( sa
> 270 ) sq
= 3;
2696 else if( sa
> 180 ) sq
= 2;
2697 else if( sa
> 90 ) sq
= 1;
2698 if( ea
> 270 ) eq
= 3;
2699 else if( ea
> 180 ) eq
= 2;
2700 else if( ea
> 90 ) eq
= 1;
2701 sar
= sa
* pi
/ 180.0;
2702 ear
= ea
* pi
/ 180.0;
2703 // correct angle circle -> ellipse
2704 sar
= atan( -a
/(double)b
* tan( sar
) );
2705 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2706 ear
= atan( -a
/(double)b
* tan( ear
) );
2707 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2708 // coordinates of points
2709 xsa
= xCenter
+ a
* cos( sar
);
2710 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2711 ysa
= yCenter
+ b
* sin( sar
);
2712 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2713 xea
= xCenter
+ a
* cos( ear
);
2714 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2715 yea
= yCenter
+ b
* sin( ear
);
2716 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2718 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2720 double c2
= 2.0 / w
;
2729 // Lists for quadrant 1 to 4
2730 wxList pointsarray
[4];
2731 // Calculate points for first quadrant and set in all quadrants
2732 for( x
= 0; x
<= a
; ++x
)
2737 bool bNewPoint
= false;
2738 while( y2
> c1
- c2
* x2
&& y
> 0 )
2744 // old y now to big: set point with old y, old x
2745 if( bNewPoint
&& x
>1)
2748 // remove points on the same line
2749 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2750 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2751 pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2752 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2754 } // calculate point
2756 // Starting and/or ending points for the quadrants, first quadrant gets both.
2757 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2758 pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
- b
) );
2759 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- a
, yCenter
) );
2760 pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2761 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2763 // copy quadrants in original list
2766 // Copy the right part of the points in the lists
2767 // and delete the wxPoints, because they do not leave this method.
2768 points
->Append( (wxObject
*) new wxPoint( xsa
, ysa
) );
2770 bool bStarted
= false;
2771 bool bReady
= false;
2772 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2775 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2777 // once: go to starting point in start quadrant
2780 ( (wxPoint
*) node
->GetData() )->x
< xsa
+1 && q
<= 1
2782 ( (wxPoint
*) node
->GetData() )->x
> xsa
-1 && q
>= 2
2789 // copy point, if not at ending point
2792 if( q
!= eq
|| bForceTurn
2794 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2796 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2800 wxPoint
* pPoint
= new wxPoint( *((wxPoint
*) node
->GetData() ) );
2801 points
->Append( (wxObject
*) pPoint
);
2803 else if( q
== eq
&& !bForceTurn
|| ( (wxPoint
*) node
->GetData() )->x
== xea
)
2813 } // while not bReady
2814 points
->Append( (wxObject
*) new wxPoint( xea
, yea
) );
2817 for( q
= 0; q
< 4; ++q
)
2819 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2821 wxPoint
*p
= (wxPoint
*)node
->GetData();
2829 // copy whole ellipse, wxPoints will be deleted outside
2830 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2832 wxObject
*p
= node
->GetData();
2833 points
->Append( p
);
2835 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2837 wxObject
*p
= node
->GetData();
2838 points
->Append( p
);
2840 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2842 wxObject
*p
= node
->GetData();
2843 points
->Append( p
);
2845 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2847 wxObject
*p
= node
->GetData();
2848 points
->Append( p
);
2851 } // CalculateEllipticPoints
2853 #endif // __WXWINCE__
2855 #endif // wxUSE_NEW_DC