1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.h"
30 #include "wx/dcscreen.h"
31 #include "wx/dcprint.h"
32 #include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
33 #include "wx/prntbase.h"
43 //----------------------------------------------------------------------------
45 //----------------------------------------------------------------------------
47 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
49 void wxDCFactory::SetDCFactory( wxDCFactory
*factory
)
51 if (wxDCFactory::m_factory
)
52 delete wxDCFactory::m_factory
;
54 wxDCFactory::m_factory
= factory
;
57 wxDCFactory
*wxDCFactory::GetFactory()
59 if (!wxDCFactory::m_factory
)
60 wxDCFactory::m_factory
= new wxNativeDCFactory
;
62 return wxDCFactory::m_factory
;
65 //-----------------------------------------------------------------------------
67 //-----------------------------------------------------------------------------
69 wxImplDC
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
)
71 #if defined(__WXMSW__)
72 return new wxWindowsWindowImplDC( owner
);
73 #elif defined(__WXGTK20__)
74 return new wxGTKWindowImplDC( owner
);
75 #elif defined(__WXGTK__)
76 return new wxGTKWindowImplDC( owner
);
77 #elif defined(__WXMAC__)
78 return new wxMacWindowImplDC( owner
);
79 #elif defined(__WXCOCOA__)
80 return new wxCocoaWindowImplDC( owner
);
81 #elif defined(__WXMOTIF__)
82 return new wxMotifWindowImplDC( owner
);
83 #elif defined(__WXX11__)
84 return new wxX11WindowImplDC( owner
);
85 #elif defined(__WXMGL__)
86 return new wxMGLWindowImplDC( owner
);
87 #elif defined(__WXDFB__)
88 return new wxDFBWindowImplDC( owner
);
89 #elif defined(__WXPM__)
90 return new wxPMWindowImplDC( owner
);
91 #elif defined(__PALMOS__)
92 return new wxPalmWindowImplDC( owner
);
96 wxImplDC
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
98 #if defined(__WXMSW__)
99 return new wxWindowsWindowImplDC( owner
, window
);
100 #elif defined(__WXGTK20__)
101 return new wxGTKWindowImplDC( owner
, window
);
102 #elif defined(__WXGTK__)
103 return new wxGTKWindowImplDC( owner
, window
);
104 #elif defined(__WXMAC__)
105 return new wxMacWindowImplDC( owner
, window
);
106 #elif defined(__WXCOCOA__)
107 return new wxCocoaWindowImplDC( owner
, window
);
108 #elif defined(__WXMOTIF__)
109 return new wxMotifWindowImplDC( owner
, window
);
110 #elif defined(__WXX11__)
111 return new wxX11WindowImplDC( owner
, window
);
112 #elif defined(__WXMGL__)
113 return new wxMGLWindowImplDC( owner
, window
);
114 #elif defined(__WXDFB__)
115 return new wxDFBWindowImplDC( owner
, window
);
116 #elif defined(__WXPM__)
117 return new wxPMWindowImplDC( owner
, window
);
118 #elif defined(__PALMOS__)
119 return new wxPalmWindowImplDC( owner
, window
);
123 wxImplDC
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
)
125 #if defined(__WXMSW__)
126 return new wxWindowsClientImplDC( owner
);
127 #elif defined(__WXGTK20__)
128 return new wxGTKClientImplDC( owner
);
129 #elif defined(__WXGTK__)
130 return new wxGTKClientImplDC( owner
);
131 #elif defined(__WXMAC__)
132 return new wxMacClientImplDC( owner
);
133 #elif defined(__WXCOCOA__)
134 return new wxCocoaClientImplDC( owner
);
135 #elif defined(__WXMOTIF__)
136 return new wxMotifClientImplDC( owner
);
137 #elif defined(__WXX11__)
138 return new wxX11ClientImplDC( owner
);
139 #elif defined(__WXMGL__)
140 return new wxMGLClientImplDC( owner
);
141 #elif defined(__WXDFB__)
142 return new wxDFBClientImplDC( owner
);
143 #elif defined(__WXPM__)
144 return new wxPMClientImplDC( owner
);
145 #elif defined(__PALMOS__)
146 return new wxPalmClientImplDC( owner
);
150 wxImplDC
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
152 #if defined(__WXMSW__)
153 return new wxWindowsClientImplDC( owner
, window
);
154 #elif defined(__WXGTK20__)
155 return new wxGTKClientImplDC( owner
, window
);
156 #elif defined(__WXGTK__)
157 return new wxGTKClientImplDC( owner
, window
);
158 #elif defined(__WXMAC__)
159 return new wxMacClientImplDC( owner
, window
);
160 #elif defined(__WXCOCOA__)
161 return new wxCocoaClientImplDC( owner
, window
);
162 #elif defined(__WXMOTIF__)
163 return new wxMotifClientImplDC( owner
, window
);
164 #elif defined(__WXX11__)
165 return new wxX11ClientImplDC( owner
, window
);
166 #elif defined(__WXMGL__)
167 return new wxMGLClientImplDC( owner
, window
);
168 #elif defined(__WXDFB__)
169 return new wxDFBClientImplDC( owner
, window
);
170 #elif defined(__WXPM__)
171 return new wxPMClientImplDC( owner
, window
);
172 #elif defined(__PALMOS__)
173 return new wxPalmClientImplDC( owner
, window
);
177 wxImplDC
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
)
179 #if defined(__WXMSW__)
180 return new wxWindowsPaintImplDC( owner
);
181 #elif defined(__WXGTK20__)
182 return new wxGTKPaintImplDC( owner
);
183 #elif defined(__WXGTK__)
184 return new wxGTKPaintImplDC( owner
);
185 #elif defined(__WXMAC__)
186 return new wxMacPaintImplDC( owner
);
187 #elif defined(__WXCOCOA__)
188 return new wxCocoaPaintImplDC( owner
);
189 #elif defined(__WXMOTIF__)
190 return new wxMotifPaintImplDC( owner
);
191 #elif defined(__WXX11__)
192 return new wxX11PaintImplDC( owner
);
193 #elif defined(__WXMGL__)
194 return new wxMGLPaintImplDC( owner
);
195 #elif defined(__WXDFB__)
196 return new wxDFBPaintImplDC( owner
);
197 #elif defined(__WXPM__)
198 return new wxPMPaintImplDC( owner
);
199 #elif defined(__PALMOS__)
200 return new wxPalmPaintImplDC( owner
);
204 wxImplDC
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
206 #if defined(__WXMSW__)
207 return new wxWindowsPaintImplDC( owner
, window
);
208 #elif defined(__WXGTK20__)
209 return new wxGTKPaintImplDC( owner
, window
);
210 #elif defined(__WXGTK__)
211 return new wxGTKPaintImplDC( owner
, window
);
212 #elif defined(__WXMAC__)
213 return new wxMacPaintImplDC( owner
, window
);
214 #elif defined(__WXCOCOA__)
215 return new wxCocoaPaintImplDC( owner
, window
);
216 #elif defined(__WXMOTIF__)
217 return new wxMotifPaintImplDC( owner
, window
);
218 #elif defined(__WXX11__)
219 return new wxX11PaintImplDC( owner
, window
);
220 #elif defined(__WXMGL__)
221 return new wxMGLPaintImplDC( owner
, window
);
222 #elif defined(__WXDFB__)
223 return new wxDFBPaintImplDC( owner
, window
);
224 #elif defined(__WXPM__)
225 return new wxPMPaintImplDC( owner
, window
);
226 #elif defined(__PALMOS__)
227 return new wxPalmPaintImplDC( owner
, window
);
231 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
233 #if defined(__WXMSW__)
234 return new wxWindowsMemoryImplDC( owner
);
235 #elif defined(__WXGTK20__)
236 return new wxGTKMemoryImplDC( owner
);
237 #elif defined(__WXGTK__)
238 return new wxGTKMemoryImplDC( owner
);
239 #elif defined(__WXMAC__)
240 return new wxMacMemoryImplDC( owner
);
241 #elif defined(__WXCOCOA__)
242 return new wxCocoaMemoryImplDC( owner
);
243 #elif defined(__WXMOTIF__)
244 return new wxMotifMemoryImplDC( owner
);
245 #elif defined(__WXX11__)
246 return new wxX11MemoryImplDC( owner
);
247 #elif defined(__WXMGL__)
248 return new wxMGLMemoryImplDC( owner
);
249 #elif defined(__WXDFB__)
250 return new wxDFBMemoryImplDC( owner
);
251 #elif defined(__WXPM__)
252 return new wxPMMemoryImplDC( owner
);
253 #elif defined(__PALMOS__)
254 return new wxPalmMemoryImplDC( owner
);
258 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxBitmap
&bitmap
)
260 #if defined(__WXMSW__)
261 return new wxWindowsMemoryImplDC( owner
, bitmap
);
262 #elif defined(__WXGTK20__)
263 return new wxGTKMemoryImplDC( owner
, bitmap
);
264 #elif defined(__WXGTK__)
265 return new wxGTKMemoryImplDC( owner
, bitmap
);
266 #elif defined(__WXMAC__)
267 return new wxMacMemoryImplDC( owner
, bitmap
);
268 #elif defined(__WXCOCOA__)
269 return new wxCocoaMemoryImplDC( owner
, bitmap
);
270 #elif defined(__WXMOTIF__)
271 return new wxMotifMemoryImplDC( owner
, bitmap
);
272 #elif defined(__WXX11__)
273 return new wxX11MemoryImplDC( owner
, bitmap
);
274 #elif defined(__WXMGL__)
275 return new wxMGLMemoryImplDC( owner
, bitmap
);
276 #elif defined(__WXDFB__)
277 return new wxDFBMemoryImplDC( owner
, bitmap
);
278 #elif defined(__WXPM__)
279 return new wxPMMemoryImplDC( owner
, bitmap
);
280 #elif defined(__PALMOS__)
281 return new wxPalmMemoryImplDC( owner
, bitmap
);
285 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
287 #if defined(__WXMSW__)
288 return new wxWindowsMemoryImplDC( owner
, dc
);
289 #elif defined(__WXGTK20__)
290 return new wxGTKMemoryImplDC( owner
, dc
);
291 #elif defined(__WXGTK__)
292 return new wxGTKMemoryImplDC( owner
, dc
);
293 #elif defined(__WXMAC__)
294 return new wxMacMemoryImplDC( owner
, dc
);
295 #elif defined(__WXCOCOA__)
296 return new wxCocoaMemoryImplDC( owner
, dc
);
297 #elif defined(__WXMOTIF__)
298 return new wxMotifMemoryImplDC( owner
, dc
);
299 #elif defined(__WXX11__)
300 return new wxX11MemoryImplDC( owner
, dc
);
301 #elif defined(__WXMGL__)
302 return new wxMGLMemoryImplDC( owner
, dc
);
303 #elif defined(__WXDFB__)
304 return new wxDFBMemoryImplDC( owner
, dc
);
305 #elif defined(__WXPM__)
306 return new wxPMMemoryImplDC( owner
, dc
);
307 #elif defined(__PALMOS__)
308 return new wxPalmMemoryImplDC( owner
, dc
);
312 wxImplDC
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
314 #if defined(__WXMSW__)
315 return new wxWindowsScreenImplDC( owner
);
316 #elif defined(__WXGTK20__)
317 return new wxGTKScreenImplDC( owner
);
318 #elif defined(__WXGTK__)
319 return new wxGTKScreenImplDC( owner
);
320 #elif defined(__WXMAC__)
321 return new wxMacScreenImplDC( owner
);
322 #elif defined(__WXCOCOA__)
323 return new wxCocoaScreenImplDC( owner
);
324 #elif defined(__WXMOTIF__)
325 return new wxMotifScreenImplDC( owner
);
326 #elif defined(__WXX11__)
327 return new wxX11ScreenImplDC( owner
);
328 #elif defined(__WXMGL__)
329 return new wxMGLScreenImplDC( owner
);
330 #elif defined(__WXDFB__)
331 return new wxDFBScreenImplDC( owner
);
332 #elif defined(__WXPM__)
333 return new wxPMScreenImplDC( owner
);
334 #elif defined(__PALMOS__)
335 return new wxPalmScreenImplDC( owner
);
339 wxImplDC
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
341 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
342 return factory
->CreatePrinterImplDC( owner
, data
);
345 //-----------------------------------------------------------------------------
347 //-----------------------------------------------------------------------------
349 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
351 wxWindowDC::wxWindowDC()
353 wxDCFactory
*factory
= wxDCFactory::GetFactory();
354 m_pimpl
= factory
->CreateWindowDC( this );
357 wxWindowDC::wxWindowDC( wxWindow
*win
)
359 wxDCFactory
*factory
= wxDCFactory::GetFactory();
360 m_pimpl
= factory
->CreateWindowDC( this, win
);
363 //-----------------------------------------------------------------------------
365 //-----------------------------------------------------------------------------
367 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxDC
)
369 wxClientDC::wxClientDC()
371 wxDCFactory
*factory
= wxDCFactory::GetFactory();
372 m_pimpl
= factory
->CreateClientDC( this );
375 wxClientDC::wxClientDC( wxWindow
*win
)
377 wxDCFactory
*factory
= wxDCFactory::GetFactory();
378 m_pimpl
= factory
->CreateClientDC( this, win
);
381 //-----------------------------------------------------------------------------
383 //-----------------------------------------------------------------------------
385 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
387 wxMemoryDC::wxMemoryDC()
389 wxDCFactory
*factory
= wxDCFactory::GetFactory();
390 m_pimpl
= factory
->CreateMemoryDC( this );
393 wxMemoryDC::wxMemoryDC( wxBitmap
& bitmap
)
395 wxDCFactory
*factory
= wxDCFactory::GetFactory();
396 m_pimpl
= factory
->CreateMemoryDC( this, bitmap
);
399 wxMemoryDC::wxMemoryDC( wxDC
*dc
)
401 wxDCFactory
*factory
= wxDCFactory::GetFactory();
402 m_pimpl
= factory
->CreateMemoryDC( this, dc
);
405 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
407 // make sure that the given wxBitmap is not sharing its data with other
408 // wxBitmap instances as its contents will be modified by any drawing
409 // operation done on this DC
413 GetImpl()->DoSelect(bmp
);
416 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
418 GetImpl()->DoSelect(bmp
);
421 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
423 return GetImpl()->GetSelectedBitmap();
426 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
428 return GetImpl()->GetSelectedBitmap();
432 //-----------------------------------------------------------------------------
434 //-----------------------------------------------------------------------------
436 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxDC
)
438 wxPaintDC::wxPaintDC()
440 wxDCFactory
*factory
= wxDCFactory::GetFactory();
441 m_pimpl
= factory
->CreatePaintDC( this );
444 wxPaintDC::wxPaintDC( wxWindow
*win
)
446 wxDCFactory
*factory
= wxDCFactory::GetFactory();
447 m_pimpl
= factory
->CreatePaintDC( this, win
);
450 //-----------------------------------------------------------------------------
452 //-----------------------------------------------------------------------------
454 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
456 wxScreenDC::wxScreenDC()
458 wxDCFactory
*factory
= wxDCFactory::GetFactory();
459 m_pimpl
= factory
->CreateScreenDC( this );
462 //-----------------------------------------------------------------------------
464 //-----------------------------------------------------------------------------
466 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
468 wxPrinterDC::wxPrinterDC()
470 wxDCFactory
*factory
= wxDCFactory::GetFactory();
471 // m_pimpl = factory->CreatePrinterDC( this, data );
474 wxPrinterDC::wxPrinterDC( const wxPrintData
&data
)
476 wxDCFactory
*factory
= wxDCFactory::GetFactory();
477 m_pimpl
= factory
->CreatePrinterDC( this, data
);
480 //-----------------------------------------------------------------------------
482 //-----------------------------------------------------------------------------
484 IMPLEMENT_ABSTRACT_CLASS(wxImplDC
, wxObject
)
486 wxImplDC::wxImplDC( wxDC
*owner
)
487 : m_colour(wxColourDisplay())
491 , m_isBBoxValid(false)
492 , m_logicalOriginX(0), m_logicalOriginY(0)
493 , m_deviceOriginX(0), m_deviceOriginY(0)
494 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
495 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
496 , m_userScaleX(1.0), m_userScaleY(1.0)
497 , m_scaleX(1.0), m_scaleY(1.0)
498 , m_signX(1), m_signY(1)
499 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
500 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
501 , m_logicalFunction(wxCOPY
)
502 , m_backgroundMode(wxTRANSPARENT
)
503 , m_mappingMode(wxMM_TEXT
)
506 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
507 , m_textForegroundColour(*wxBLACK
)
508 , m_textBackgroundColour(*wxWHITE
)
512 , m_hasCustomPalette(false)
513 #endif // wxUSE_PALETTE
517 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
518 (double)wxGetDisplaySizeMM().GetWidth();
519 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
520 (double)wxGetDisplaySizeMM().GetHeight();
526 wxImplDC::~wxImplDC()
530 // ----------------------------------------------------------------------------
531 // coordinate conversions and transforms
532 // ----------------------------------------------------------------------------
534 wxCoord
wxImplDC::DeviceToLogicalX(wxCoord x
) const
536 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
539 wxCoord
wxImplDC::DeviceToLogicalY(wxCoord y
) const
541 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
544 wxCoord
wxImplDC::DeviceToLogicalXRel(wxCoord x
) const
546 return wxRound((double)(x
) / m_scaleX
);
549 wxCoord
wxImplDC::DeviceToLogicalYRel(wxCoord y
) const
551 return wxRound((double)(y
) / m_scaleY
);
554 wxCoord
wxImplDC::LogicalToDeviceX(wxCoord x
) const
556 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
559 wxCoord
wxImplDC::LogicalToDeviceY(wxCoord y
) const
561 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ m_deviceLocalOriginY
;
564 wxCoord
wxImplDC::LogicalToDeviceXRel(wxCoord x
) const
566 return wxRound((double)(x
) * m_scaleX
);
569 wxCoord
wxImplDC::LogicalToDeviceYRel(wxCoord y
) const
571 return wxRound((double)(y
) * m_scaleY
);
574 void wxImplDC::ComputeScaleAndOrigin()
576 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
577 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
580 void wxImplDC::SetMapMode( int mode
)
585 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
588 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
591 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
594 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
598 SetLogicalScale( 1.0, 1.0 );
601 m_mappingMode
= mode
;
604 void wxImplDC::SetUserScale( double x
, double y
)
606 // allow negative ? -> no
609 ComputeScaleAndOrigin();
612 void wxImplDC::SetLogicalScale( double x
, double y
)
617 ComputeScaleAndOrigin();
620 void wxImplDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
622 m_logicalOriginX
= x
* m_signX
;
623 m_logicalOriginY
= y
* m_signY
;
624 ComputeScaleAndOrigin();
627 void wxImplDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
631 ComputeScaleAndOrigin();
634 void wxImplDC::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
636 m_deviceLocalOriginX
= x
;
637 m_deviceLocalOriginY
= y
;
638 ComputeScaleAndOrigin();
641 void wxImplDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
643 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
644 // wxWidgets 2.9: no longer override it
645 m_signX
= (xLeftRight
? 1 : -1);
646 m_signY
= (yBottomUp
? -1 : 1);
647 ComputeScaleAndOrigin();
651 // Each element of the widths array will be the width of the string up to and
652 // including the corresponding character in text. This is the generic
653 // implementation, the port-specific classes should do this with native APIs
654 // if available and if faster. Note: pango_layout_index_to_pos is much slower
655 // than calling GetTextExtent!!
662 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
663 ~FontWidthCache() { delete []m_widths
; }
668 m_widths
= new int[FWC_SIZE
];
670 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
678 static FontWidthCache s_fontWidthCache
;
680 bool wxImplDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
684 const size_t len
= text
.length();
688 // reset the cache if font or horizontal scale have changed
689 if ( !s_fontWidthCache
.m_widths
||
690 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
691 (s_fontWidthCache
.m_font
!= GetFont()) )
693 s_fontWidthCache
.Reset();
694 s_fontWidthCache
.m_font
= GetFont();
695 s_fontWidthCache
.m_scaleX
= m_scaleX
;
698 // Calculate the position of each character based on the widths of
699 // the previous characters
701 for ( size_t i
= 0; i
< len
; i
++ )
703 const wxChar c
= text
[i
];
704 unsigned int c_int
= (unsigned int)c
;
706 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
708 w
= s_fontWidthCache
.m_widths
[c_int
];
712 DoGetTextExtent(c
, &w
, &h
);
713 if (c_int
< FWC_SIZE
)
714 s_fontWidthCache
.m_widths
[c_int
] = w
;
718 widths
[i
] = totalWidth
;
724 void wxImplDC::GetMultiLineTextExtent(const wxString
& text
,
728 const wxFont
*font
) const
730 wxCoord widthTextMax
= 0, widthLine
,
731 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
734 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
736 if ( pc
== text
.end() || *pc
== _T('\n') )
738 if ( curLine
.empty() )
740 // we can't use GetTextExtent - it will return 0 for both width
741 // and height and an empty line should count in height
744 // assume that this line has the same height as the previous
746 if ( !heightLineDefault
)
747 heightLineDefault
= heightLine
;
749 if ( !heightLineDefault
)
751 // but we don't know it yet - choose something reasonable
752 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
756 heightTextTotal
+= heightLineDefault
;
760 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
762 if ( widthLine
> widthTextMax
)
763 widthTextMax
= widthLine
;
764 heightTextTotal
+= heightLine
;
767 if ( pc
== text
.end() )
785 *y
= heightTextTotal
;
790 void wxImplDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
791 wxCoord width
, wxCoord height
)
793 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
795 wxCoord x2
= x1
+ width
,
798 // the pen width is calibrated to give 3 for width == height == 10
799 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
801 // we're drawing a scaled version of wx/generic/tick.xpm here
802 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
803 y3
= y1
+ height
/ 2; // y of the left tick branch
804 DoDrawLine(x1
, y3
, x3
, y2
);
805 DoDrawLine(x3
, y2
, x2
, y1
);
807 CalcBoundingBox(x1
, y1
);
808 CalcBoundingBox(x2
, y2
);
812 wxImplDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
813 wxCoord dstWidth
, wxCoord dstHeight
,
815 wxCoord xsrc
, wxCoord ysrc
,
816 wxCoord srcWidth
, wxCoord srcHeight
,
822 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
823 _T("invalid blit size") );
825 // emulate the stretching by modifying the DC scale
826 double xscale
= (double)srcWidth
/dstWidth
,
827 yscale
= (double)srcHeight
/dstHeight
;
829 double xscaleOld
, yscaleOld
;
830 GetUserScale(&xscaleOld
, &yscaleOld
);
831 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
833 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
834 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
836 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
838 SetUserScale(xscaleOld
, yscaleOld
);
843 void wxImplDC::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
845 int n
= list
->GetCount();
846 wxPoint
*points
= new wxPoint
[n
];
849 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
851 wxPoint
*point
= node
->GetData();
852 points
[i
].x
= point
->x
;
853 points
[i
].y
= point
->y
;
856 DoDrawLines(n
, points
, xoffset
, yoffset
);
861 void wxImplDC::DrawPolygon(const wxPointList
*list
,
862 wxCoord xoffset
, wxCoord yoffset
,
865 int n
= list
->GetCount();
866 wxPoint
*points
= new wxPoint
[n
];
869 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
871 wxPoint
*point
= node
->GetData();
872 points
[i
].x
= point
->x
;
873 points
[i
].y
= point
->y
;
876 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
882 wxImplDC::DoDrawPolyPolygon(int n
,
885 wxCoord xoffset
, wxCoord yoffset
,
890 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
898 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
903 pts
= new wxPoint
[j
+n
-1];
904 for (i
= 0; i
< j
; i
++)
906 for (i
= 2; i
<= n
; i
++)
908 lastOfs
-= count
[n
-i
];
909 pts
[j
++] = pts
[lastOfs
];
913 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
914 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
916 for (i
= j
= 0; i
< n
; i
++)
918 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
926 void wxImplDC::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
928 wxPointList point_list
;
930 wxPoint
*point1
= new wxPoint
;
931 point1
->x
= x1
; point1
->y
= y1
;
932 point_list
.Append( point1
);
934 wxPoint
*point2
= new wxPoint
;
935 point2
->x
= x2
; point2
->y
= y2
;
936 point_list
.Append( point2
);
938 wxPoint
*point3
= new wxPoint
;
939 point3
->x
= x3
; point3
->y
= y3
;
940 point_list
.Append( point3
);
942 DoDrawSpline(&point_list
);
944 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
946 wxPoint
*p
= node
->GetData();
951 void wxImplDC::DoDrawSpline(int n
, wxPoint points
[])
954 for (int i
=0; i
< n
; i
++)
955 list
.Append( &points
[i
] );
960 // ----------------------------------- spline code ----------------------------------------
962 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
963 double a3
, double b3
, double a4
, double b4
);
964 void wx_clear_stack();
965 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
966 double *y3
, double *x4
, double *y4
);
967 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
968 double x4
, double y4
);
969 static bool wx_spline_add_point(double x
, double y
);
970 static void wx_spline_draw_point_array(wxDC
*dc
);
972 wxPointList wx_spline_point_list
;
974 #define half(z1, z2) ((z1+z2)/2.0)
977 /* iterative version */
979 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
982 register double xmid
, ymid
;
983 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
986 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
988 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
989 xmid
= (double)half(x2
, x3
);
990 ymid
= (double)half(y2
, y3
);
991 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
992 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
993 wx_spline_add_point( x1
, y1
);
994 wx_spline_add_point( xmid
, ymid
);
996 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
997 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
998 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
999 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1004 /* utilities used by spline drawing routines */
1006 typedef struct wx_spline_stack_struct
{
1007 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1010 #define SPLINE_STACK_DEPTH 20
1011 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1012 static Stack
*wx_stack_top
;
1013 static int wx_stack_count
;
1015 void wx_clear_stack()
1017 wx_stack_top
= wx_spline_stack
;
1021 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1023 wx_stack_top
->x1
= x1
;
1024 wx_stack_top
->y1
= y1
;
1025 wx_stack_top
->x2
= x2
;
1026 wx_stack_top
->y2
= y2
;
1027 wx_stack_top
->x3
= x3
;
1028 wx_stack_top
->y3
= y3
;
1029 wx_stack_top
->x4
= x4
;
1030 wx_stack_top
->y4
= y4
;
1035 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1036 double *x3
, double *y3
, double *x4
, double *y4
)
1038 if (wx_stack_count
== 0)
1042 *x1
= wx_stack_top
->x1
;
1043 *y1
= wx_stack_top
->y1
;
1044 *x2
= wx_stack_top
->x2
;
1045 *y2
= wx_stack_top
->y2
;
1046 *x3
= wx_stack_top
->x3
;
1047 *y3
= wx_stack_top
->y3
;
1048 *x4
= wx_stack_top
->x4
;
1049 *y4
= wx_stack_top
->y4
;
1053 static bool wx_spline_add_point(double x
, double y
)
1055 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
1056 wx_spline_point_list
.Append(point
);
1060 static void wx_spline_draw_point_array(wxDC
*dc
)
1062 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1063 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1066 wxPoint
*point
= node
->GetData();
1068 wx_spline_point_list
.Erase(node
);
1069 node
= wx_spline_point_list
.GetFirst();
1073 void wxImplDC::DoDrawSpline( const wxPointList
*points
)
1075 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
1078 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1079 double x1
, y1
, x2
, y2
;
1081 wxPointList::compatibility_iterator node
= points
->GetFirst();
1086 p
= (wxPoint
*)node
->GetData();
1091 node
= node
->GetNext();
1092 p
= node
->GetData();
1096 cx1
= (double)((x1
+ x2
) / 2);
1097 cy1
= (double)((y1
+ y2
) / 2);
1098 cx2
= (double)((cx1
+ x2
) / 2);
1099 cy2
= (double)((cy1
+ y2
) / 2);
1101 wx_spline_add_point(x1
, y1
);
1103 while ((node
= node
->GetNext())
1106 #endif // !wxUSE_STL
1109 p
= node
->GetData();
1114 cx4
= (double)(x1
+ x2
) / 2;
1115 cy4
= (double)(y1
+ y2
) / 2;
1116 cx3
= (double)(x1
+ cx4
) / 2;
1117 cy3
= (double)(y1
+ cy4
) / 2;
1119 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1123 cx2
= (double)(cx1
+ x2
) / 2;
1124 cy2
= (double)(cy1
+ y2
) / 2;
1127 wx_spline_add_point( cx1
, cy1
);
1128 wx_spline_add_point( x2
, y2
);
1130 wx_spline_draw_point_array( m_owner
);
1133 #endif // wxUSE_SPLINES
1137 void wxImplDC::DoGradientFillLinear(const wxRect
& rect
,
1138 const wxColour
& initialColour
,
1139 const wxColour
& destColour
,
1140 wxDirection nDirection
)
1143 wxPen oldPen
= m_pen
;
1144 wxBrush oldBrush
= m_brush
;
1146 wxUint8 nR1
= initialColour
.Red();
1147 wxUint8 nG1
= initialColour
.Green();
1148 wxUint8 nB1
= initialColour
.Blue();
1149 wxUint8 nR2
= destColour
.Red();
1150 wxUint8 nG2
= destColour
.Green();
1151 wxUint8 nB2
= destColour
.Blue();
1154 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
1156 wxInt32 x
= rect
.GetWidth();
1157 wxInt32 w
= x
; // width of area to shade
1158 wxInt32 xDelta
= w
/256; // height of one shade bend
1166 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1168 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1171 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1173 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1176 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1178 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1180 wxColour
colour(nR
,nG
,nB
);
1181 SetPen(wxPen(colour
, 1, wxSOLID
));
1182 SetBrush(wxBrush(colour
));
1183 if(nDirection
== wxEAST
)
1184 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1185 xDelta
, rect
.GetHeight());
1186 else //nDirection == wxWEST
1187 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1188 xDelta
, rect
.GetHeight());
1191 else // nDirection == wxNORTH || nDirection == wxSOUTH
1193 wxInt32 y
= rect
.GetHeight();
1194 wxInt32 w
= y
; // height of area to shade
1195 wxInt32 yDelta
= w
/255; // height of one shade bend
1203 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1205 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1208 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1210 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1213 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1215 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1217 wxColour
colour(nR
,nG
,nB
);
1218 SetPen(wxPen(colour
, 1, wxSOLID
));
1219 SetBrush(wxBrush(colour
));
1220 if(nDirection
== wxNORTH
)
1221 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1222 rect
.GetWidth(), yDelta
);
1223 else //nDirection == wxSOUTH
1224 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1225 rect
.GetWidth(), yDelta
);
1233 void wxImplDC::DoGradientFillConcentric(const wxRect
& rect
,
1234 const wxColour
& initialColour
,
1235 const wxColour
& destColour
,
1236 const wxPoint
& circleCenter
)
1238 //save the old pen color
1239 wxColour oldPenColour
= m_pen
.GetColour();
1241 wxUint8 nR1
= destColour
.Red();
1242 wxUint8 nG1
= destColour
.Green();
1243 wxUint8 nB1
= destColour
.Blue();
1244 wxUint8 nR2
= initialColour
.Red();
1245 wxUint8 nG2
= initialColour
.Green();
1246 wxUint8 nB2
= initialColour
.Blue();
1251 wxInt32 cx
= rect
.GetWidth() / 2;
1252 wxInt32 cy
= rect
.GetHeight() / 2;
1260 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1261 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1263 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1265 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1267 //get color difference
1268 wxInt32 nGradient
= ((nRadius
-
1270 pow((double)(x
- cx
- nCircleOffX
), 2) +
1271 pow((double)(y
- cy
- nCircleOffY
), 2)
1272 )) * 100) / nRadius
;
1274 //normalize Gradient
1279 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1280 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1281 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1284 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1285 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1288 //return old pen color
1289 m_pen
.SetColour(oldPenColour
);
1292 //-----------------------------------------------------------------------------
1294 //-----------------------------------------------------------------------------
1296 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1298 void wxDC::DrawLabel(const wxString
& text
,
1299 const wxBitmap
& bitmap
,
1303 wxRect
*rectBounding
)
1305 // find the text position
1306 wxCoord widthText
, heightText
, heightLine
;
1307 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1309 wxCoord width
, height
;
1312 width
= widthText
+ bitmap
.GetWidth();
1313 height
= bitmap
.GetHeight();
1318 height
= heightText
;
1322 if ( alignment
& wxALIGN_RIGHT
)
1324 x
= rect
.GetRight() - width
;
1326 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1328 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1330 else // alignment & wxALIGN_LEFT
1335 if ( alignment
& wxALIGN_BOTTOM
)
1337 y
= rect
.GetBottom() - height
;
1339 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1341 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1343 else // alignment & wxALIGN_TOP
1348 // draw the bitmap first
1354 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1356 wxCoord offset
= bitmap
.GetWidth() + 4;
1360 y
+= (height
- heightText
) / 2;
1363 // we will draw the underscore under the accel char later
1364 wxCoord startUnderscore
= 0,
1368 // split the string into lines and draw each of them separately
1370 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1372 if ( *pc
== _T('\n') || pc
== text
.end() )
1374 int xRealStart
= x
; // init it here to avoid compielr warnings
1376 if ( !curLine
.empty() )
1378 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1379 // wxALIGN_LEFT is 0
1380 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1383 GetTextExtent(curLine
, &widthLine
, NULL
);
1385 if ( alignment
& wxALIGN_RIGHT
)
1387 xRealStart
+= width
- widthLine
;
1389 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1391 xRealStart
+= (width
- widthLine
) / 2;
1394 //else: left aligned, nothing to do
1396 DrawText(curLine
, xRealStart
, y
);
1401 // do we have underscore in this line? we can check yUnderscore
1402 // because it is set below to just y + heightLine if we do
1403 if ( y
== yUnderscore
)
1405 // adjust the horz positions to account for the shift
1406 startUnderscore
+= xRealStart
;
1407 endUnderscore
+= xRealStart
;
1410 if ( pc
== text
.end() )
1415 else // not end of line
1417 if ( pc
- text
.begin() == indexAccel
)
1419 // remeber to draw underscore here
1420 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1422 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1424 yUnderscore
= y
+ heightLine
;
1433 // draw the underscore if found
1434 if ( startUnderscore
!= endUnderscore
)
1436 // it should be of the same colour as text
1437 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1441 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1444 // return bounding rect if requested
1447 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1450 CalcBoundingBox(x0
, y0
);
1451 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1454 #if WXWIN_COMPATIBILITY_2_8
1455 // for compatibility with the old code when wxCoord was long everywhere
1456 void wxDC::GetTextExtent(const wxString
& string
,
1459 long *externalLeading
,
1460 const wxFont
*theFont
) const
1462 wxCoord x2
, y2
, descent2
, externalLeading2
;
1463 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1464 &descent2
, &externalLeading2
,
1471 *descent
= descent2
;
1472 if ( externalLeading
)
1473 *externalLeading
= externalLeading2
;
1476 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1479 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1486 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1489 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1496 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1498 wxCoord xx
,yy
,ww
,hh
;
1499 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1506 #endif // WXWIN_COMPATIBILITY_2_8
1509 #else // wxUSE_NEW_DC
1512 // bool wxDCBase::sm_cacheing = false;
1514 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1516 // ============================================================================
1518 // ============================================================================
1520 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1521 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1523 wxDCBase::wxDCBase()
1524 : m_colour(wxColourDisplay())
1527 , m_isInteractive(0)
1528 , m_isBBoxValid(false)
1529 , m_logicalOriginX(0), m_logicalOriginY(0)
1530 , m_deviceOriginX(0), m_deviceOriginY(0)
1531 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1532 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1533 , m_userScaleX(1.0), m_userScaleY(1.0)
1534 , m_scaleX(1.0), m_scaleY(1.0)
1535 , m_signX(1), m_signY(1)
1536 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1537 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1538 , m_logicalFunction(wxCOPY
)
1539 , m_backgroundMode(wxTRANSPARENT
)
1540 , m_mappingMode(wxMM_TEXT
)
1543 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1544 , m_textForegroundColour(*wxBLACK
)
1545 , m_textBackgroundColour(*wxWHITE
)
1549 , m_hasCustomPalette(false)
1550 #endif // wxUSE_PALETTE
1552 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1553 (double)wxGetDisplaySizeMM().GetWidth();
1554 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1555 (double)wxGetDisplaySizeMM().GetHeight();
1561 wxDCBase::~wxDCBase()
1565 #if WXWIN_COMPATIBILITY_2_6
1566 void wxDCBase::BeginDrawing()
1570 void wxDCBase::EndDrawing()
1573 #endif // WXWIN_COMPATIBILITY_2_6
1575 #if WXWIN_COMPATIBILITY_2_8
1576 // for compatibility with the old code when wxCoord was long everywhere
1577 void wxDCBase::GetTextExtent(const wxString
& string
,
1580 long *externalLeading
,
1581 const wxFont
*theFont
) const
1583 wxCoord x2
, y2
, descent2
, externalLeading2
;
1584 DoGetTextExtent(string
, &x2
, &y2
,
1585 &descent2
, &externalLeading2
,
1592 *descent
= descent2
;
1593 if ( externalLeading
)
1594 *externalLeading
= externalLeading2
;
1597 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1600 DoGetLogicalOrigin(&x2
, &y2
);
1607 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1610 DoGetDeviceOrigin(&x2
, &y2
);
1617 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1619 wxCoord xx
,yy
,ww
,hh
;
1620 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1626 #endif // WXWIN_COMPATIBILITY_2_8
1630 // ----------------------------------------------------------------------------
1631 // coordinate conversions and transforms
1632 // ----------------------------------------------------------------------------
1634 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1636 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1639 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1641 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1644 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1646 return wxRound((double)(x
) / m_scaleX
);
1649 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1651 return wxRound((double)(y
) / m_scaleY
);
1654 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1656 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1659 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1661 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1664 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1666 return wxRound((double)(x
) * m_scaleX
);
1669 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1671 return wxRound((double)(y
) * m_scaleY
);
1674 void wxDCBase::ComputeScaleAndOrigin()
1676 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1677 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1680 void wxDCBase::SetMapMode( int mode
)
1685 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1688 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1691 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1694 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1698 SetLogicalScale( 1.0, 1.0 );
1701 m_mappingMode
= mode
;
1704 void wxDCBase::SetUserScale( double x
, double y
)
1706 // allow negative ? -> no
1709 ComputeScaleAndOrigin();
1712 void wxDCBase::SetLogicalScale( double x
, double y
)
1715 m_logicalScaleX
= x
;
1716 m_logicalScaleY
= y
;
1717 ComputeScaleAndOrigin();
1720 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1722 m_logicalOriginX
= x
* m_signX
;
1723 m_logicalOriginY
= y
* m_signY
;
1724 ComputeScaleAndOrigin();
1727 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1729 m_deviceOriginX
= x
;
1730 m_deviceOriginY
= y
;
1731 ComputeScaleAndOrigin();
1734 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1736 m_deviceLocalOriginX
= x
;
1737 m_deviceLocalOriginY
= y
;
1738 ComputeScaleAndOrigin();
1741 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1743 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1744 // wxWidgets 2.9: no longer override it
1745 m_signX
= (xLeftRight
? 1 : -1);
1746 m_signY
= (yBottomUp
? -1 : 1);
1747 ComputeScaleAndOrigin();
1750 // ----------------------------------------------------------------------------
1752 // ----------------------------------------------------------------------------
1754 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1755 wxCoord width
, wxCoord height
)
1757 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1759 wxCoord x2
= x1
+ width
,
1762 // the pen width is calibrated to give 3 for width == height == 10
1763 wxDCPenChanger
pen((wxDC
&)*this,
1764 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1766 // we're drawing a scaled version of wx/generic/tick.xpm here
1767 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1768 y3
= y1
+ height
/ 2; // y of the left tick branch
1769 DoDrawLine(x1
, y3
, x3
, y2
);
1770 DoDrawLine(x3
, y2
, x2
, y1
);
1772 CalcBoundingBox(x1
, y1
);
1773 CalcBoundingBox(x2
, y2
);
1776 // ----------------------------------------------------------------------------
1777 // stubs for functions not implemented in all ports
1778 // ----------------------------------------------------------------------------
1781 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1782 wxCoord dstWidth
, wxCoord dstHeight
,
1784 wxCoord xsrc
, wxCoord ysrc
,
1785 wxCoord srcWidth
, wxCoord srcHeight
,
1791 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1792 _T("invalid blit size") );
1794 // emulate the stretching by modifying the DC scale
1795 double xscale
= (double)srcWidth
/dstWidth
,
1796 yscale
= (double)srcHeight
/dstHeight
;
1798 double xscaleOld
, yscaleOld
;
1799 GetUserScale(&xscaleOld
, &yscaleOld
);
1800 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1802 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1803 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1805 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1807 SetUserScale(xscaleOld
, yscaleOld
);
1812 // ----------------------------------------------------------------------------
1814 // ----------------------------------------------------------------------------
1816 void wxDCBase::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1818 unsigned int n
= list
->GetCount();
1819 wxPoint
*points
= new wxPoint
[n
];
1822 wxPointList::compatibility_iterator node
;
1823 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1825 wxPoint
*point
= node
->GetData();
1826 points
[i
].x
= point
->x
;
1827 points
[i
].y
= point
->y
;
1830 DoDrawLines(n
, points
, xoffset
, yoffset
);
1835 #if WXWIN_COMPATIBILITY_2_8
1836 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1838 unsigned int n
= list
->GetCount();
1839 wxPoint
*points
= new wxPoint
[n
];
1842 wxObjectList::compatibility_iterator node
;
1843 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1845 wxPoint
*point
= (wxPoint
*) node
->GetData();
1846 points
[i
].x
= point
->x
;
1847 points
[i
].y
= point
->y
;
1850 DoDrawLines(n
, points
, xoffset
, yoffset
);
1854 #endif // WXWIN_COMPATIBILITY_2_8
1857 void wxDCBase::DrawPolygon(const wxPointList
*list
,
1858 wxCoord xoffset
, wxCoord yoffset
,
1861 unsigned int n
= list
->GetCount();
1862 wxPoint
*points
= new wxPoint
[n
];
1865 wxPointList::compatibility_iterator node
;
1866 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1868 wxPoint
*point
= node
->GetData();
1869 points
[i
].x
= point
->x
;
1870 points
[i
].y
= point
->y
;
1873 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1879 #if WXWIN_COMPATIBILITY_2_8
1880 void wxDCBase::DrawPolygon(const wxList
*list
,
1881 wxCoord xoffset
, wxCoord yoffset
,
1884 unsigned int n
= list
->GetCount();
1885 wxPoint
*points
= new wxPoint
[n
];
1888 wxObjectList::compatibility_iterator node
;
1889 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1891 wxPoint
*point
= (wxPoint
*) node
->GetData();
1892 points
[i
].x
= point
->x
;
1893 points
[i
].y
= point
->y
;
1896 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1900 #endif // WXWIN_COMPATIBILITY_2_8
1903 wxDCBase::DoDrawPolyPolygon(int n
,
1906 wxCoord xoffset
, wxCoord yoffset
,
1911 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1919 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1924 pts
= new wxPoint
[j
+n
-1];
1925 for (i
= 0; i
< j
; i
++)
1927 for (i
= 2; i
<= n
; i
++)
1929 lastOfs
-= count
[n
-i
];
1930 pts
[j
++] = pts
[lastOfs
];
1934 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1935 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1937 for (i
= j
= 0; i
< n
; i
++)
1939 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1945 // ----------------------------------------------------------------------------
1947 // ----------------------------------------------------------------------------
1951 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1953 wxPointList point_list
;
1955 wxPoint
*point1
= new wxPoint
;
1956 point1
->x
= x1
; point1
->y
= y1
;
1957 point_list
.Append( point1
);
1959 wxPoint
*point2
= new wxPoint
;
1960 point2
->x
= x2
; point2
->y
= y2
;
1961 point_list
.Append( point2
);
1963 wxPoint
*point3
= new wxPoint
;
1964 point3
->x
= x3
; point3
->y
= y3
;
1965 point_list
.Append( point3
);
1967 DrawSpline(&point_list
);
1969 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
1971 wxPoint
*p
= node
->GetData();
1976 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
1979 for (int i
=0; i
< n
; i
++)
1980 list
.Append( &points
[i
] );
1985 // ----------------------------------- spline code ----------------------------------------
1987 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1988 double a3
, double b3
, double a4
, double b4
);
1989 void wx_clear_stack();
1990 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1991 double *y3
, double *x4
, double *y4
);
1992 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1993 double x4
, double y4
);
1994 static bool wx_spline_add_point(double x
, double y
);
1995 static void wx_spline_draw_point_array(wxDCBase
*dc
);
1997 wxPointList wx_spline_point_list
;
1999 #define half(z1, z2) ((z1+z2)/2.0)
2002 /* iterative version */
2004 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
2007 register double xmid
, ymid
;
2008 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2011 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
2013 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
2014 xmid
= (double)half(x2
, x3
);
2015 ymid
= (double)half(y2
, y3
);
2016 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
2017 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
2018 wx_spline_add_point( x1
, y1
);
2019 wx_spline_add_point( xmid
, ymid
);
2021 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
2022 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
2023 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
2024 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
2029 /* utilities used by spline drawing routines */
2031 typedef struct wx_spline_stack_struct
{
2032 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2035 #define SPLINE_STACK_DEPTH 20
2036 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2037 static Stack
*wx_stack_top
;
2038 static int wx_stack_count
;
2040 void wx_clear_stack()
2042 wx_stack_top
= wx_spline_stack
;
2046 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2048 wx_stack_top
->x1
= x1
;
2049 wx_stack_top
->y1
= y1
;
2050 wx_stack_top
->x2
= x2
;
2051 wx_stack_top
->y2
= y2
;
2052 wx_stack_top
->x3
= x3
;
2053 wx_stack_top
->y3
= y3
;
2054 wx_stack_top
->x4
= x4
;
2055 wx_stack_top
->y4
= y4
;
2060 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2061 double *x3
, double *y3
, double *x4
, double *y4
)
2063 if (wx_stack_count
== 0)
2067 *x1
= wx_stack_top
->x1
;
2068 *y1
= wx_stack_top
->y1
;
2069 *x2
= wx_stack_top
->x2
;
2070 *y2
= wx_stack_top
->y2
;
2071 *x3
= wx_stack_top
->x3
;
2072 *y3
= wx_stack_top
->y3
;
2073 *x4
= wx_stack_top
->x4
;
2074 *y4
= wx_stack_top
->y4
;
2078 static bool wx_spline_add_point(double x
, double y
)
2080 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
2081 wx_spline_point_list
.Append( point
);
2085 static void wx_spline_draw_point_array(wxDCBase
*dc
)
2087 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2088 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
2091 wxPoint
*point
= node
->GetData();
2093 wx_spline_point_list
.Erase(node
);
2094 node
= wx_spline_point_list
.GetFirst();
2098 #if WXWIN_COMPATIBILITY_2_8
2099 void wxDCBase::DrawSpline(const wxList
*points
)
2102 wxObjectList::compatibility_iterator node
= points
->GetFirst();
2105 list
.Append( (wxPoint
*) node
->GetData() );
2106 node
= node
->GetNext();
2108 DoDrawSpline( &list
);
2110 #endif // WXWIN_COMPATIBILITY_2_8
2112 void wxDCBase::DoDrawSpline( const wxPointList
*points
)
2114 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2117 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2118 double x1
, y1
, x2
, y2
;
2120 wxPointList::compatibility_iterator node
= points
->GetFirst();
2125 p
= node
->GetData();
2130 node
= node
->GetNext();
2131 p
= node
->GetData();
2135 cx1
= (double)((x1
+ x2
) / 2);
2136 cy1
= (double)((y1
+ y2
) / 2);
2137 cx2
= (double)((cx1
+ x2
) / 2);
2138 cy2
= (double)((cy1
+ y2
) / 2);
2140 wx_spline_add_point(x1
, y1
);
2142 while ((node
= node
->GetNext())
2145 #endif // !wxUSE_STL
2148 p
= node
->GetData();
2153 cx4
= (double)(x1
+ x2
) / 2;
2154 cy4
= (double)(y1
+ y2
) / 2;
2155 cx3
= (double)(x1
+ cx4
) / 2;
2156 cy3
= (double)(y1
+ cy4
) / 2;
2158 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2162 cx2
= (double)(cx1
+ x2
) / 2;
2163 cy2
= (double)(cy1
+ y2
) / 2;
2166 wx_spline_add_point( cx1
, cy1
);
2167 wx_spline_add_point( x2
, y2
);
2169 wx_spline_draw_point_array( this );
2172 #endif // wxUSE_SPLINES
2174 // ----------------------------------------------------------------------------
2175 // Partial Text Extents
2176 // ----------------------------------------------------------------------------
2179 // Each element of the widths array will be the width of the string up to and
2180 // including the corresponding character in text. This is the generic
2181 // implementation, the port-specific classes should do this with native APIs
2182 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2183 // than calling GetTextExtent!!
2185 #define FWC_SIZE 256
2187 class FontWidthCache
2190 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
2191 ~FontWidthCache() { delete []m_widths
; }
2196 m_widths
= new int[FWC_SIZE
];
2198 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2206 static FontWidthCache s_fontWidthCache
;
2208 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2212 const size_t len
= text
.length();
2216 // reset the cache if font or horizontal scale have changed
2217 if ( !s_fontWidthCache
.m_widths
||
2218 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2219 (s_fontWidthCache
.m_font
!= GetFont()) )
2221 s_fontWidthCache
.Reset();
2222 s_fontWidthCache
.m_font
= GetFont();
2223 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2226 // Calculate the position of each character based on the widths of
2227 // the previous characters
2229 for ( size_t i
= 0; i
< len
; i
++ )
2231 const wxChar c
= text
[i
];
2232 unsigned int c_int
= (unsigned int)c
;
2234 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2236 w
= s_fontWidthCache
.m_widths
[c_int
];
2240 GetTextExtent(c
, &w
, &h
);
2241 if (c_int
< FWC_SIZE
)
2242 s_fontWidthCache
.m_widths
[c_int
] = w
;
2246 widths
[i
] = totalWidth
;
2253 // ----------------------------------------------------------------------------
2254 // enhanced text drawing
2255 // ----------------------------------------------------------------------------
2257 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2261 const wxFont
*font
) const
2263 wxCoord widthTextMax
= 0, widthLine
,
2264 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2267 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2269 if ( pc
== text
.end() || *pc
== _T('\n') )
2271 if ( curLine
.empty() )
2273 // we can't use GetTextExtent - it will return 0 for both width
2274 // and height and an empty line should count in height
2277 // assume that this line has the same height as the previous
2279 if ( !heightLineDefault
)
2280 heightLineDefault
= heightLine
;
2282 if ( !heightLineDefault
)
2284 // but we don't know it yet - choose something reasonable
2285 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2289 heightTextTotal
+= heightLineDefault
;
2293 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2295 if ( widthLine
> widthTextMax
)
2296 widthTextMax
= widthLine
;
2297 heightTextTotal
+= heightLine
;
2300 if ( pc
== text
.end() )
2318 *y
= heightTextTotal
;
2323 void wxDCBase::DrawLabel(const wxString
& text
,
2324 const wxBitmap
& bitmap
,
2328 wxRect
*rectBounding
)
2330 // find the text position
2331 wxCoord widthText
, heightText
, heightLine
;
2332 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2334 wxCoord width
, height
;
2337 width
= widthText
+ bitmap
.GetWidth();
2338 height
= bitmap
.GetHeight();
2343 height
= heightText
;
2347 if ( alignment
& wxALIGN_RIGHT
)
2349 x
= rect
.GetRight() - width
;
2351 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2353 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2355 else // alignment & wxALIGN_LEFT
2360 if ( alignment
& wxALIGN_BOTTOM
)
2362 y
= rect
.GetBottom() - height
;
2364 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2366 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2368 else // alignment & wxALIGN_TOP
2373 // draw the bitmap first
2379 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2381 wxCoord offset
= bitmap
.GetWidth() + 4;
2385 y
+= (height
- heightText
) / 2;
2388 // we will draw the underscore under the accel char later
2389 wxCoord startUnderscore
= 0,
2393 // split the string into lines and draw each of them separately
2395 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2397 if ( pc
== text
.end() || *pc
== _T('\n') )
2399 int xRealStart
= x
; // init it here to avoid compielr warnings
2401 if ( !curLine
.empty() )
2403 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2404 // wxALIGN_LEFT is 0
2405 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2408 GetTextExtent(curLine
, &widthLine
, NULL
);
2410 if ( alignment
& wxALIGN_RIGHT
)
2412 xRealStart
+= width
- widthLine
;
2414 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2416 xRealStart
+= (width
- widthLine
) / 2;
2419 //else: left aligned, nothing to do
2421 DrawText(curLine
, xRealStart
, y
);
2426 // do we have underscore in this line? we can check yUnderscore
2427 // because it is set below to just y + heightLine if we do
2428 if ( y
== yUnderscore
)
2430 // adjust the horz positions to account for the shift
2431 startUnderscore
+= xRealStart
;
2432 endUnderscore
+= xRealStart
;
2435 if ( pc
== text
.end() )
2440 else // not end of line
2442 if ( pc
- text
.begin() == indexAccel
)
2444 // remeber to draw underscore here
2445 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2447 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2449 yUnderscore
= y
+ heightLine
;
2458 // draw the underscore if found
2459 if ( startUnderscore
!= endUnderscore
)
2461 // it should be of the same colour as text
2462 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2466 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2469 // return bounding rect if requested
2472 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2475 CalcBoundingBox(x0
, y0
);
2476 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2480 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2481 const wxColour
& initialColour
,
2482 const wxColour
& destColour
,
2483 wxDirection nDirection
)
2486 wxPen oldPen
= m_pen
;
2487 wxBrush oldBrush
= m_brush
;
2489 wxUint8 nR1
= initialColour
.Red();
2490 wxUint8 nG1
= initialColour
.Green();
2491 wxUint8 nB1
= initialColour
.Blue();
2492 wxUint8 nR2
= destColour
.Red();
2493 wxUint8 nG2
= destColour
.Green();
2494 wxUint8 nB2
= destColour
.Blue();
2497 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2499 wxInt32 x
= rect
.GetWidth();
2500 wxInt32 w
= x
; // width of area to shade
2501 wxInt32 xDelta
= w
/256; // height of one shade bend
2509 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2511 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2514 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2516 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2519 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2521 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2523 wxColour
colour(nR
,nG
,nB
);
2524 SetPen(wxPen(colour
, 1, wxSOLID
));
2525 SetBrush(wxBrush(colour
));
2526 if(nDirection
== wxEAST
)
2527 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
2528 xDelta
, rect
.GetHeight());
2529 else //nDirection == wxWEST
2530 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2531 xDelta
, rect
.GetHeight());
2534 else // nDirection == wxNORTH || nDirection == wxSOUTH
2536 wxInt32 y
= rect
.GetHeight();
2537 wxInt32 w
= y
; // height of area to shade
2538 wxInt32 yDelta
= w
/255; // height of one shade bend
2546 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2548 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2551 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2553 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2556 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2558 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2560 wxColour
colour(nR
,nG
,nB
);
2561 SetPen(wxPen(colour
, 1, wxSOLID
));
2562 SetBrush(wxBrush(colour
));
2563 if(nDirection
== wxNORTH
)
2564 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2565 rect
.GetWidth(), yDelta
);
2566 else //nDirection == wxSOUTH
2567 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
2568 rect
.GetWidth(), yDelta
);
2576 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2577 const wxColour
& initialColour
,
2578 const wxColour
& destColour
,
2579 const wxPoint
& circleCenter
)
2581 //save the old pen color
2582 wxColour oldPenColour
= m_pen
.GetColour();
2584 wxUint8 nR1
= destColour
.Red();
2585 wxUint8 nG1
= destColour
.Green();
2586 wxUint8 nB1
= destColour
.Blue();
2587 wxUint8 nR2
= initialColour
.Red();
2588 wxUint8 nG2
= initialColour
.Green();
2589 wxUint8 nB2
= initialColour
.Blue();
2594 wxInt32 cx
= rect
.GetWidth() / 2;
2595 wxInt32 cy
= rect
.GetHeight() / 2;
2603 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2604 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2606 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2608 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2610 //get color difference
2611 wxInt32 nGradient
= ((nRadius
-
2613 pow((double)(x
- cx
- nCircleOffX
), 2) +
2614 pow((double)(y
- cy
- nCircleOffY
), 2)
2615 )) * 100) / nRadius
;
2617 //normalize Gradient
2622 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2623 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2624 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2627 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2628 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2631 //return old pen color
2632 m_pen
.SetColour(oldPenColour
);
2636 Notes for wxWidgets DrawEllipticArcRot(...)
2638 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2639 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2642 All methods are generic, so they can be implemented in wxDCBase.
2643 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2644 methods like (WinCE) wxDC::DoDrawArc(...).
2646 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2647 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2648 parts) or every column (in steep parts) only one pixel is calculated.
2649 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2650 starting angle is not equal to the ending angle. The calculation of the
2651 pixels is done using simple arithmetic only and should perform not too
2652 bad even on devices without floating point processor. I didn't test this yet.
2654 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2655 For instance: an ellipse rotated 180 degrees is drawn
2656 slightly different from the original.
2658 The points are then moved to an array and used to draw a polyline and/or polygon
2659 (with center added, the pie).
2660 The result looks quite similar to the native ellipse, only e few pixels differ.
2662 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2663 slower as DrawEllipse(...), which calls the native API.
2664 An rotated ellipse outside the clipping region takes nearly the same time,
2665 while an native ellipse outside takes nearly no time to draw.
2667 If you draw an arc with this new method, you will see the starting and ending angles
2668 are calculated properly.
2669 If you use DrawEllipticArc(...), you will see they are only correct for circles
2670 and not properly calculated for ellipses.
2673 p.lenhard@t-online.de
2677 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2678 wxCoord w
, wxCoord h
,
2679 double sa
, double ea
, double angle
)
2683 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2684 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2686 // Add center (for polygon/pie)
2687 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
2689 // copy list into array and delete list elements
2690 int n
= list
.GetCount();
2691 wxPoint
*points
= new wxPoint
[n
];
2693 wxPointList::compatibility_iterator node
;
2694 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2696 wxPoint
*point
= node
->GetData();
2697 points
[i
].x
= point
->x
;
2698 points
[i
].y
= point
->y
;
2702 // first draw the pie without pen, if necessary
2703 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2705 wxPen
tempPen( GetPen() );
2706 SetPen( *wxTRANSPARENT_PEN
);
2707 DoDrawPolygon( n
, points
, 0, 0 );
2711 // then draw the arc without brush, if necessary
2712 if( GetPen() != *wxTRANSPARENT_PEN
)
2715 DoDrawLines( n
-1, points
, 0, 0 );
2720 } // DrawEllipticArcRot
2722 void wxDCBase::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
2727 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2728 double dCosA
= cos(angle
*2.0*pi
/360.0);
2729 wxPointList::compatibility_iterator node
;
2730 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2732 wxPoint
* point
= node
->GetData();
2734 // transform coordinates, if necessary
2735 if( center
.x
) point
->x
-= center
.x
;
2736 if( center
.y
) point
->y
-= center
.y
;
2738 // calculate rotation, rounding simply by implicit cast to integer
2739 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2740 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2743 // back transform coordinates, if necessary
2744 if( center
.x
) point
->x
+= center
.x
;
2745 if( center
.y
) point
->y
+= center
.y
;
2750 void wxDCBase::CalculateEllipticPoints( wxPointList
* points
,
2751 wxCoord xStart
, wxCoord yStart
,
2752 wxCoord w
, wxCoord h
,
2753 double sa
, double ea
)
2764 bool bUseAngles
= false;
2770 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2772 if( 2*a
== w
) decrX
= 1;
2774 if( 2*b
== h
) decrY
= 1;
2776 wxCoord xCenter
= xStart
+ a
;
2777 wxCoord yCenter
= yStart
+ b
;
2778 // calculate data for start and end, if necessary
2782 // normalisation of angles
2783 while( sa
<0 ) sa
+= 360;
2784 while( ea
<0 ) ea
+= 360;
2785 while( sa
>=360 ) sa
-= 360;
2786 while( ea
>=360 ) ea
-= 360;
2787 // calculate quadrant numbers
2788 if( sa
> 270 ) sq
= 3;
2789 else if( sa
> 180 ) sq
= 2;
2790 else if( sa
> 90 ) sq
= 1;
2791 if( ea
> 270 ) eq
= 3;
2792 else if( ea
> 180 ) eq
= 2;
2793 else if( ea
> 90 ) eq
= 1;
2794 sar
= sa
* pi
/ 180.0;
2795 ear
= ea
* pi
/ 180.0;
2796 // correct angle circle -> ellipse
2797 sar
= atan( -a
/(double)b
* tan( sar
) );
2798 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2799 ear
= atan( -a
/(double)b
* tan( ear
) );
2800 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2801 // coordinates of points
2802 xsa
= xCenter
+ a
* cos( sar
);
2803 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2804 ysa
= yCenter
+ b
* sin( sar
);
2805 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2806 xea
= xCenter
+ a
* cos( ear
);
2807 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2808 yea
= yCenter
+ b
* sin( ear
);
2809 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2811 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2813 double c2
= 2.0 / w
;
2822 // Lists for quadrant 1 to 4
2823 wxPointList pointsarray
[4];
2824 // Calculate points for first quadrant and set in all quadrants
2825 for( x
= 0; x
<= a
; ++x
)
2830 bool bNewPoint
= false;
2831 while( y2
> c1
- c2
* x2
&& y
> 0 )
2837 // old y now to big: set point with old y, old x
2838 if( bNewPoint
&& x
>1)
2841 // remove points on the same line
2842 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2843 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2844 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2845 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2847 } // calculate point
2849 // Starting and/or ending points for the quadrants, first quadrant gets both.
2850 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2851 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
2852 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
2853 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2854 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2856 // copy quadrants in original list
2859 // Copy the right part of the points in the lists
2860 // and delete the wxPoints, because they do not leave this method.
2861 points
->Append( new wxPoint( xsa
, ysa
) );
2863 bool bStarted
= false;
2864 bool bReady
= false;
2865 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2868 wxPointList::compatibility_iterator node
;
2869 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2871 // once: go to starting point in start quadrant
2874 node
->GetData()->x
< xsa
+1 && q
<= 1
2876 node
->GetData()->x
> xsa
-1 && q
>= 2
2883 // copy point, if not at ending point
2886 if( q
!= eq
|| bForceTurn
2888 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2890 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2894 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
2895 points
->Append( pPoint
);
2897 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
2907 } // while not bReady
2908 points
->Append( new wxPoint( xea
, yea
) );
2911 for( q
= 0; q
< 4; ++q
)
2913 wxPointList::compatibility_iterator node
;
2914 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2916 wxPoint
*p
= node
->GetData();
2923 wxPointList::compatibility_iterator node
;
2924 // copy whole ellipse, wxPoints will be deleted outside
2925 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2927 wxPoint
*p
= node
->GetData();
2928 points
->Append( p
);
2930 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2932 wxPoint
*p
= node
->GetData();
2933 points
->Append( p
);
2935 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2937 wxPoint
*p
= node
->GetData();
2938 points
->Append( p
);
2940 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2942 wxPoint
*p
= node
->GetData();
2943 points
->Append( p
);
2946 } // CalculateEllipticPoints
2948 #endif // __WXWINCE__
2950 #endif // wxUSE_NEW_DC