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 wxPrinterDC::~wxPrinterDC()
484 wxRect
wxPrinterDC::GetPaperRect()
486 return GetImpl()->GetPaperRect();
489 int wxPrinterDC::GetResolution()
491 return GetImpl()->GetResolution();
495 //-----------------------------------------------------------------------------
497 //-----------------------------------------------------------------------------
499 IMPLEMENT_ABSTRACT_CLASS(wxImplDC
, wxObject
)
501 wxImplDC::wxImplDC( wxDC
*owner
)
502 : m_colour(wxColourDisplay())
506 , m_isBBoxValid(false)
507 , m_logicalOriginX(0), m_logicalOriginY(0)
508 , m_deviceOriginX(0), m_deviceOriginY(0)
509 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
510 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
511 , m_userScaleX(1.0), m_userScaleY(1.0)
512 , m_scaleX(1.0), m_scaleY(1.0)
513 , m_signX(1), m_signY(1)
514 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
515 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
516 , m_logicalFunction(wxCOPY
)
517 , m_backgroundMode(wxTRANSPARENT
)
518 , m_mappingMode(wxMM_TEXT
)
521 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
522 , m_textForegroundColour(*wxBLACK
)
523 , m_textBackgroundColour(*wxWHITE
)
527 , m_hasCustomPalette(false)
528 #endif // wxUSE_PALETTE
532 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
533 (double)wxGetDisplaySizeMM().GetWidth();
534 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
535 (double)wxGetDisplaySizeMM().GetHeight();
541 wxImplDC::~wxImplDC()
545 // ----------------------------------------------------------------------------
546 // coordinate conversions and transforms
547 // ----------------------------------------------------------------------------
549 wxCoord
wxImplDC::DeviceToLogicalX(wxCoord x
) const
551 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
554 wxCoord
wxImplDC::DeviceToLogicalY(wxCoord y
) const
556 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
559 wxCoord
wxImplDC::DeviceToLogicalXRel(wxCoord x
) const
561 return wxRound((double)(x
) / m_scaleX
);
564 wxCoord
wxImplDC::DeviceToLogicalYRel(wxCoord y
) const
566 return wxRound((double)(y
) / m_scaleY
);
569 wxCoord
wxImplDC::LogicalToDeviceX(wxCoord x
) const
571 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
574 wxCoord
wxImplDC::LogicalToDeviceY(wxCoord y
) const
576 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ m_deviceLocalOriginY
;
579 wxCoord
wxImplDC::LogicalToDeviceXRel(wxCoord x
) const
581 return wxRound((double)(x
) * m_scaleX
);
584 wxCoord
wxImplDC::LogicalToDeviceYRel(wxCoord y
) const
586 return wxRound((double)(y
) * m_scaleY
);
589 void wxImplDC::ComputeScaleAndOrigin()
591 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
592 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
595 void wxImplDC::SetMapMode( int mode
)
600 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
603 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
606 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
609 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
613 SetLogicalScale( 1.0, 1.0 );
616 m_mappingMode
= mode
;
619 void wxImplDC::SetUserScale( double x
, double y
)
621 // allow negative ? -> no
624 ComputeScaleAndOrigin();
627 void wxImplDC::SetLogicalScale( double x
, double y
)
632 ComputeScaleAndOrigin();
635 void wxImplDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
637 m_logicalOriginX
= x
* m_signX
;
638 m_logicalOriginY
= y
* m_signY
;
639 ComputeScaleAndOrigin();
642 void wxImplDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
646 ComputeScaleAndOrigin();
649 void wxImplDC::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
651 m_deviceLocalOriginX
= x
;
652 m_deviceLocalOriginY
= y
;
653 ComputeScaleAndOrigin();
656 void wxImplDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
658 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
659 // wxWidgets 2.9: no longer override it
660 m_signX
= (xLeftRight
? 1 : -1);
661 m_signY
= (yBottomUp
? -1 : 1);
662 ComputeScaleAndOrigin();
666 // Each element of the widths array will be the width of the string up to and
667 // including the corresponding character in text. This is the generic
668 // implementation, the port-specific classes should do this with native APIs
669 // if available and if faster. Note: pango_layout_index_to_pos is much slower
670 // than calling GetTextExtent!!
677 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
678 ~FontWidthCache() { delete []m_widths
; }
683 m_widths
= new int[FWC_SIZE
];
685 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
693 static FontWidthCache s_fontWidthCache
;
695 bool wxImplDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
699 const size_t len
= text
.length();
703 // reset the cache if font or horizontal scale have changed
704 if ( !s_fontWidthCache
.m_widths
||
705 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
706 (s_fontWidthCache
.m_font
!= GetFont()) )
708 s_fontWidthCache
.Reset();
709 s_fontWidthCache
.m_font
= GetFont();
710 s_fontWidthCache
.m_scaleX
= m_scaleX
;
713 // Calculate the position of each character based on the widths of
714 // the previous characters
716 for ( size_t i
= 0; i
< len
; i
++ )
718 const wxChar c
= text
[i
];
719 unsigned int c_int
= (unsigned int)c
;
721 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
723 w
= s_fontWidthCache
.m_widths
[c_int
];
727 DoGetTextExtent(c
, &w
, &h
);
728 if (c_int
< FWC_SIZE
)
729 s_fontWidthCache
.m_widths
[c_int
] = w
;
733 widths
[i
] = totalWidth
;
739 void wxImplDC::GetMultiLineTextExtent(const wxString
& text
,
743 const wxFont
*font
) const
745 wxCoord widthTextMax
= 0, widthLine
,
746 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
749 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
751 if ( pc
== text
.end() || *pc
== _T('\n') )
753 if ( curLine
.empty() )
755 // we can't use GetTextExtent - it will return 0 for both width
756 // and height and an empty line should count in height
759 // assume that this line has the same height as the previous
761 if ( !heightLineDefault
)
762 heightLineDefault
= heightLine
;
764 if ( !heightLineDefault
)
766 // but we don't know it yet - choose something reasonable
767 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
771 heightTextTotal
+= heightLineDefault
;
775 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
777 if ( widthLine
> widthTextMax
)
778 widthTextMax
= widthLine
;
779 heightTextTotal
+= heightLine
;
782 if ( pc
== text
.end() )
800 *y
= heightTextTotal
;
805 void wxImplDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
806 wxCoord width
, wxCoord height
)
808 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
810 wxCoord x2
= x1
+ width
,
813 // the pen width is calibrated to give 3 for width == height == 10
814 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
816 // we're drawing a scaled version of wx/generic/tick.xpm here
817 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
818 y3
= y1
+ height
/ 2; // y of the left tick branch
819 DoDrawLine(x1
, y3
, x3
, y2
);
820 DoDrawLine(x3
, y2
, x2
, y1
);
822 CalcBoundingBox(x1
, y1
);
823 CalcBoundingBox(x2
, y2
);
827 wxImplDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
828 wxCoord dstWidth
, wxCoord dstHeight
,
830 wxCoord xsrc
, wxCoord ysrc
,
831 wxCoord srcWidth
, wxCoord srcHeight
,
837 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
838 _T("invalid blit size") );
840 // emulate the stretching by modifying the DC scale
841 double xscale
= (double)srcWidth
/dstWidth
,
842 yscale
= (double)srcHeight
/dstHeight
;
844 double xscaleOld
, yscaleOld
;
845 GetUserScale(&xscaleOld
, &yscaleOld
);
846 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
848 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
849 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
851 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
853 SetUserScale(xscaleOld
, yscaleOld
);
858 void wxImplDC::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
860 int n
= list
->GetCount();
861 wxPoint
*points
= new wxPoint
[n
];
864 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
866 wxPoint
*point
= node
->GetData();
867 points
[i
].x
= point
->x
;
868 points
[i
].y
= point
->y
;
871 DoDrawLines(n
, points
, xoffset
, yoffset
);
876 void wxImplDC::DrawPolygon(const wxPointList
*list
,
877 wxCoord xoffset
, wxCoord yoffset
,
880 int n
= list
->GetCount();
881 wxPoint
*points
= new wxPoint
[n
];
884 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
886 wxPoint
*point
= node
->GetData();
887 points
[i
].x
= point
->x
;
888 points
[i
].y
= point
->y
;
891 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
897 wxImplDC::DoDrawPolyPolygon(int n
,
900 wxCoord xoffset
, wxCoord yoffset
,
905 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
913 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
918 pts
= new wxPoint
[j
+n
-1];
919 for (i
= 0; i
< j
; i
++)
921 for (i
= 2; i
<= n
; i
++)
923 lastOfs
-= count
[n
-i
];
924 pts
[j
++] = pts
[lastOfs
];
928 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
929 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
931 for (i
= j
= 0; i
< n
; i
++)
933 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
941 void wxImplDC::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
943 wxPointList point_list
;
945 wxPoint
*point1
= new wxPoint
;
946 point1
->x
= x1
; point1
->y
= y1
;
947 point_list
.Append( point1
);
949 wxPoint
*point2
= new wxPoint
;
950 point2
->x
= x2
; point2
->y
= y2
;
951 point_list
.Append( point2
);
953 wxPoint
*point3
= new wxPoint
;
954 point3
->x
= x3
; point3
->y
= y3
;
955 point_list
.Append( point3
);
957 DoDrawSpline(&point_list
);
959 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
961 wxPoint
*p
= node
->GetData();
966 void wxImplDC::DoDrawSpline(int n
, wxPoint points
[])
969 for (int i
=0; i
< n
; i
++)
970 list
.Append( &points
[i
] );
975 // ----------------------------------- spline code ----------------------------------------
977 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
978 double a3
, double b3
, double a4
, double b4
);
979 void wx_clear_stack();
980 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
981 double *y3
, double *x4
, double *y4
);
982 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
983 double x4
, double y4
);
984 static bool wx_spline_add_point(double x
, double y
);
985 static void wx_spline_draw_point_array(wxDC
*dc
);
987 wxPointList wx_spline_point_list
;
989 #define half(z1, z2) ((z1+z2)/2.0)
992 /* iterative version */
994 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
997 register double xmid
, ymid
;
998 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1001 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1003 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1004 xmid
= (double)half(x2
, x3
);
1005 ymid
= (double)half(y2
, y3
);
1006 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1007 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1008 wx_spline_add_point( x1
, y1
);
1009 wx_spline_add_point( xmid
, ymid
);
1011 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1012 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1013 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1014 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1019 /* utilities used by spline drawing routines */
1021 typedef struct wx_spline_stack_struct
{
1022 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1025 #define SPLINE_STACK_DEPTH 20
1026 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1027 static Stack
*wx_stack_top
;
1028 static int wx_stack_count
;
1030 void wx_clear_stack()
1032 wx_stack_top
= wx_spline_stack
;
1036 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1038 wx_stack_top
->x1
= x1
;
1039 wx_stack_top
->y1
= y1
;
1040 wx_stack_top
->x2
= x2
;
1041 wx_stack_top
->y2
= y2
;
1042 wx_stack_top
->x3
= x3
;
1043 wx_stack_top
->y3
= y3
;
1044 wx_stack_top
->x4
= x4
;
1045 wx_stack_top
->y4
= y4
;
1050 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1051 double *x3
, double *y3
, double *x4
, double *y4
)
1053 if (wx_stack_count
== 0)
1057 *x1
= wx_stack_top
->x1
;
1058 *y1
= wx_stack_top
->y1
;
1059 *x2
= wx_stack_top
->x2
;
1060 *y2
= wx_stack_top
->y2
;
1061 *x3
= wx_stack_top
->x3
;
1062 *y3
= wx_stack_top
->y3
;
1063 *x4
= wx_stack_top
->x4
;
1064 *y4
= wx_stack_top
->y4
;
1068 static bool wx_spline_add_point(double x
, double y
)
1070 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
1071 wx_spline_point_list
.Append(point
);
1075 static void wx_spline_draw_point_array(wxDC
*dc
)
1077 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1078 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1081 wxPoint
*point
= node
->GetData();
1083 wx_spline_point_list
.Erase(node
);
1084 node
= wx_spline_point_list
.GetFirst();
1088 void wxImplDC::DoDrawSpline( const wxPointList
*points
)
1090 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
1093 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1094 double x1
, y1
, x2
, y2
;
1096 wxPointList::compatibility_iterator node
= points
->GetFirst();
1101 p
= (wxPoint
*)node
->GetData();
1106 node
= node
->GetNext();
1107 p
= node
->GetData();
1111 cx1
= (double)((x1
+ x2
) / 2);
1112 cy1
= (double)((y1
+ y2
) / 2);
1113 cx2
= (double)((cx1
+ x2
) / 2);
1114 cy2
= (double)((cy1
+ y2
) / 2);
1116 wx_spline_add_point(x1
, y1
);
1118 while ((node
= node
->GetNext())
1121 #endif // !wxUSE_STL
1124 p
= node
->GetData();
1129 cx4
= (double)(x1
+ x2
) / 2;
1130 cy4
= (double)(y1
+ y2
) / 2;
1131 cx3
= (double)(x1
+ cx4
) / 2;
1132 cy3
= (double)(y1
+ cy4
) / 2;
1134 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1138 cx2
= (double)(cx1
+ x2
) / 2;
1139 cy2
= (double)(cy1
+ y2
) / 2;
1142 wx_spline_add_point( cx1
, cy1
);
1143 wx_spline_add_point( x2
, y2
);
1145 wx_spline_draw_point_array( m_owner
);
1148 #endif // wxUSE_SPLINES
1152 void wxImplDC::DoGradientFillLinear(const wxRect
& rect
,
1153 const wxColour
& initialColour
,
1154 const wxColour
& destColour
,
1155 wxDirection nDirection
)
1158 wxPen oldPen
= m_pen
;
1159 wxBrush oldBrush
= m_brush
;
1161 wxUint8 nR1
= initialColour
.Red();
1162 wxUint8 nG1
= initialColour
.Green();
1163 wxUint8 nB1
= initialColour
.Blue();
1164 wxUint8 nR2
= destColour
.Red();
1165 wxUint8 nG2
= destColour
.Green();
1166 wxUint8 nB2
= destColour
.Blue();
1169 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
1171 wxInt32 x
= rect
.GetWidth();
1172 wxInt32 w
= x
; // width of area to shade
1173 wxInt32 xDelta
= w
/256; // height of one shade bend
1181 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1183 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1186 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1188 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1191 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1193 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1195 wxColour
colour(nR
,nG
,nB
);
1196 SetPen(wxPen(colour
, 1, wxSOLID
));
1197 SetBrush(wxBrush(colour
));
1198 if(nDirection
== wxEAST
)
1199 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1200 xDelta
, rect
.GetHeight());
1201 else //nDirection == wxWEST
1202 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1203 xDelta
, rect
.GetHeight());
1206 else // nDirection == wxNORTH || nDirection == wxSOUTH
1208 wxInt32 y
= rect
.GetHeight();
1209 wxInt32 w
= y
; // height of area to shade
1210 wxInt32 yDelta
= w
/255; // height of one shade bend
1218 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1220 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1223 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1225 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1228 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1230 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1232 wxColour
colour(nR
,nG
,nB
);
1233 SetPen(wxPen(colour
, 1, wxSOLID
));
1234 SetBrush(wxBrush(colour
));
1235 if(nDirection
== wxNORTH
)
1236 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1237 rect
.GetWidth(), yDelta
);
1238 else //nDirection == wxSOUTH
1239 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1240 rect
.GetWidth(), yDelta
);
1248 void wxImplDC::DoGradientFillConcentric(const wxRect
& rect
,
1249 const wxColour
& initialColour
,
1250 const wxColour
& destColour
,
1251 const wxPoint
& circleCenter
)
1253 //save the old pen color
1254 wxColour oldPenColour
= m_pen
.GetColour();
1256 wxUint8 nR1
= destColour
.Red();
1257 wxUint8 nG1
= destColour
.Green();
1258 wxUint8 nB1
= destColour
.Blue();
1259 wxUint8 nR2
= initialColour
.Red();
1260 wxUint8 nG2
= initialColour
.Green();
1261 wxUint8 nB2
= initialColour
.Blue();
1266 wxInt32 cx
= rect
.GetWidth() / 2;
1267 wxInt32 cy
= rect
.GetHeight() / 2;
1275 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1276 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1278 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1280 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1282 //get color difference
1283 wxInt32 nGradient
= ((nRadius
-
1285 pow((double)(x
- cx
- nCircleOffX
), 2) +
1286 pow((double)(y
- cy
- nCircleOffY
), 2)
1287 )) * 100) / nRadius
;
1289 //normalize Gradient
1294 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1295 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1296 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1299 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1300 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1303 //return old pen color
1304 m_pen
.SetColour(oldPenColour
);
1307 //-----------------------------------------------------------------------------
1309 //-----------------------------------------------------------------------------
1311 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1313 void wxDC::DrawLabel(const wxString
& text
,
1314 const wxBitmap
& bitmap
,
1318 wxRect
*rectBounding
)
1320 // find the text position
1321 wxCoord widthText
, heightText
, heightLine
;
1322 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1324 wxCoord width
, height
;
1327 width
= widthText
+ bitmap
.GetWidth();
1328 height
= bitmap
.GetHeight();
1333 height
= heightText
;
1337 if ( alignment
& wxALIGN_RIGHT
)
1339 x
= rect
.GetRight() - width
;
1341 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1343 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1345 else // alignment & wxALIGN_LEFT
1350 if ( alignment
& wxALIGN_BOTTOM
)
1352 y
= rect
.GetBottom() - height
;
1354 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1356 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1358 else // alignment & wxALIGN_TOP
1363 // draw the bitmap first
1369 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1371 wxCoord offset
= bitmap
.GetWidth() + 4;
1375 y
+= (height
- heightText
) / 2;
1378 // we will draw the underscore under the accel char later
1379 wxCoord startUnderscore
= 0,
1383 // split the string into lines and draw each of them separately
1385 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1387 if ( *pc
== _T('\n') || pc
== text
.end() )
1389 int xRealStart
= x
; // init it here to avoid compielr warnings
1391 if ( !curLine
.empty() )
1393 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1394 // wxALIGN_LEFT is 0
1395 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1398 GetTextExtent(curLine
, &widthLine
, NULL
);
1400 if ( alignment
& wxALIGN_RIGHT
)
1402 xRealStart
+= width
- widthLine
;
1404 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1406 xRealStart
+= (width
- widthLine
) / 2;
1409 //else: left aligned, nothing to do
1411 DrawText(curLine
, xRealStart
, y
);
1416 // do we have underscore in this line? we can check yUnderscore
1417 // because it is set below to just y + heightLine if we do
1418 if ( y
== yUnderscore
)
1420 // adjust the horz positions to account for the shift
1421 startUnderscore
+= xRealStart
;
1422 endUnderscore
+= xRealStart
;
1425 if ( pc
== text
.end() )
1430 else // not end of line
1432 if ( pc
- text
.begin() == indexAccel
)
1434 // remeber to draw underscore here
1435 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1437 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1439 yUnderscore
= y
+ heightLine
;
1448 // draw the underscore if found
1449 if ( startUnderscore
!= endUnderscore
)
1451 // it should be of the same colour as text
1452 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1456 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1459 // return bounding rect if requested
1462 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1465 CalcBoundingBox(x0
, y0
);
1466 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1469 #if WXWIN_COMPATIBILITY_2_8
1470 // for compatibility with the old code when wxCoord was long everywhere
1471 void wxDC::GetTextExtent(const wxString
& string
,
1474 long *externalLeading
,
1475 const wxFont
*theFont
) const
1477 wxCoord x2
, y2
, descent2
, externalLeading2
;
1478 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1479 &descent2
, &externalLeading2
,
1486 *descent
= descent2
;
1487 if ( externalLeading
)
1488 *externalLeading
= externalLeading2
;
1491 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1494 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1501 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1504 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1511 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1513 wxCoord xx
,yy
,ww
,hh
;
1514 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1521 #endif // WXWIN_COMPATIBILITY_2_8
1524 #else // wxUSE_NEW_DC
1527 // bool wxDCBase::sm_cacheing = false;
1529 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1531 // ============================================================================
1533 // ============================================================================
1535 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1536 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1538 wxDCBase::wxDCBase()
1539 : m_colour(wxColourDisplay())
1542 , m_isInteractive(0)
1543 , m_isBBoxValid(false)
1544 , m_logicalOriginX(0), m_logicalOriginY(0)
1545 , m_deviceOriginX(0), m_deviceOriginY(0)
1546 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1547 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1548 , m_userScaleX(1.0), m_userScaleY(1.0)
1549 , m_scaleX(1.0), m_scaleY(1.0)
1550 , m_signX(1), m_signY(1)
1551 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1552 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1553 , m_logicalFunction(wxCOPY
)
1554 , m_backgroundMode(wxTRANSPARENT
)
1555 , m_mappingMode(wxMM_TEXT
)
1558 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1559 , m_textForegroundColour(*wxBLACK
)
1560 , m_textBackgroundColour(*wxWHITE
)
1564 , m_hasCustomPalette(false)
1565 #endif // wxUSE_PALETTE
1567 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1568 (double)wxGetDisplaySizeMM().GetWidth();
1569 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1570 (double)wxGetDisplaySizeMM().GetHeight();
1576 wxDCBase::~wxDCBase()
1580 #if WXWIN_COMPATIBILITY_2_6
1581 void wxDCBase::BeginDrawing()
1585 void wxDCBase::EndDrawing()
1588 #endif // WXWIN_COMPATIBILITY_2_6
1590 #if WXWIN_COMPATIBILITY_2_8
1591 // for compatibility with the old code when wxCoord was long everywhere
1592 void wxDCBase::GetTextExtent(const wxString
& string
,
1595 long *externalLeading
,
1596 const wxFont
*theFont
) const
1598 wxCoord x2
, y2
, descent2
, externalLeading2
;
1599 DoGetTextExtent(string
, &x2
, &y2
,
1600 &descent2
, &externalLeading2
,
1607 *descent
= descent2
;
1608 if ( externalLeading
)
1609 *externalLeading
= externalLeading2
;
1612 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1615 DoGetLogicalOrigin(&x2
, &y2
);
1622 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1625 DoGetDeviceOrigin(&x2
, &y2
);
1632 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1634 wxCoord xx
,yy
,ww
,hh
;
1635 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1641 #endif // WXWIN_COMPATIBILITY_2_8
1645 // ----------------------------------------------------------------------------
1646 // coordinate conversions and transforms
1647 // ----------------------------------------------------------------------------
1649 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1651 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1654 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1656 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1659 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1661 return wxRound((double)(x
) / m_scaleX
);
1664 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1666 return wxRound((double)(y
) / m_scaleY
);
1669 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1671 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1674 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1676 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1679 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1681 return wxRound((double)(x
) * m_scaleX
);
1684 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1686 return wxRound((double)(y
) * m_scaleY
);
1689 void wxDCBase::ComputeScaleAndOrigin()
1691 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1692 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1695 void wxDCBase::SetMapMode( int mode
)
1700 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1703 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1706 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1709 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1713 SetLogicalScale( 1.0, 1.0 );
1716 m_mappingMode
= mode
;
1719 void wxDCBase::SetUserScale( double x
, double y
)
1721 // allow negative ? -> no
1724 ComputeScaleAndOrigin();
1727 void wxDCBase::SetLogicalScale( double x
, double y
)
1730 m_logicalScaleX
= x
;
1731 m_logicalScaleY
= y
;
1732 ComputeScaleAndOrigin();
1735 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1737 m_logicalOriginX
= x
* m_signX
;
1738 m_logicalOriginY
= y
* m_signY
;
1739 ComputeScaleAndOrigin();
1742 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1744 m_deviceOriginX
= x
;
1745 m_deviceOriginY
= y
;
1746 ComputeScaleAndOrigin();
1749 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1751 m_deviceLocalOriginX
= x
;
1752 m_deviceLocalOriginY
= y
;
1753 ComputeScaleAndOrigin();
1756 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1758 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1759 // wxWidgets 2.9: no longer override it
1760 m_signX
= (xLeftRight
? 1 : -1);
1761 m_signY
= (yBottomUp
? -1 : 1);
1762 ComputeScaleAndOrigin();
1765 // ----------------------------------------------------------------------------
1767 // ----------------------------------------------------------------------------
1769 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1770 wxCoord width
, wxCoord height
)
1772 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1774 wxCoord x2
= x1
+ width
,
1777 // the pen width is calibrated to give 3 for width == height == 10
1778 wxDCPenChanger
pen((wxDC
&)*this,
1779 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1781 // we're drawing a scaled version of wx/generic/tick.xpm here
1782 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1783 y3
= y1
+ height
/ 2; // y of the left tick branch
1784 DoDrawLine(x1
, y3
, x3
, y2
);
1785 DoDrawLine(x3
, y2
, x2
, y1
);
1787 CalcBoundingBox(x1
, y1
);
1788 CalcBoundingBox(x2
, y2
);
1791 // ----------------------------------------------------------------------------
1792 // stubs for functions not implemented in all ports
1793 // ----------------------------------------------------------------------------
1796 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1797 wxCoord dstWidth
, wxCoord dstHeight
,
1799 wxCoord xsrc
, wxCoord ysrc
,
1800 wxCoord srcWidth
, wxCoord srcHeight
,
1806 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1807 _T("invalid blit size") );
1809 // emulate the stretching by modifying the DC scale
1810 double xscale
= (double)srcWidth
/dstWidth
,
1811 yscale
= (double)srcHeight
/dstHeight
;
1813 double xscaleOld
, yscaleOld
;
1814 GetUserScale(&xscaleOld
, &yscaleOld
);
1815 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1817 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1818 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1820 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1822 SetUserScale(xscaleOld
, yscaleOld
);
1827 // ----------------------------------------------------------------------------
1829 // ----------------------------------------------------------------------------
1831 void wxDCBase::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1833 unsigned int n
= list
->GetCount();
1834 wxPoint
*points
= new wxPoint
[n
];
1837 wxPointList::compatibility_iterator node
;
1838 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1840 wxPoint
*point
= node
->GetData();
1841 points
[i
].x
= point
->x
;
1842 points
[i
].y
= point
->y
;
1845 DoDrawLines(n
, points
, xoffset
, yoffset
);
1850 #if WXWIN_COMPATIBILITY_2_8
1851 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1853 unsigned int n
= list
->GetCount();
1854 wxPoint
*points
= new wxPoint
[n
];
1857 wxObjectList::compatibility_iterator node
;
1858 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1860 wxPoint
*point
= (wxPoint
*) node
->GetData();
1861 points
[i
].x
= point
->x
;
1862 points
[i
].y
= point
->y
;
1865 DoDrawLines(n
, points
, xoffset
, yoffset
);
1869 #endif // WXWIN_COMPATIBILITY_2_8
1872 void wxDCBase::DrawPolygon(const wxPointList
*list
,
1873 wxCoord xoffset
, wxCoord yoffset
,
1876 unsigned int n
= list
->GetCount();
1877 wxPoint
*points
= new wxPoint
[n
];
1880 wxPointList::compatibility_iterator node
;
1881 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1883 wxPoint
*point
= node
->GetData();
1884 points
[i
].x
= point
->x
;
1885 points
[i
].y
= point
->y
;
1888 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1894 #if WXWIN_COMPATIBILITY_2_8
1895 void wxDCBase::DrawPolygon(const wxList
*list
,
1896 wxCoord xoffset
, wxCoord yoffset
,
1899 unsigned int n
= list
->GetCount();
1900 wxPoint
*points
= new wxPoint
[n
];
1903 wxObjectList::compatibility_iterator node
;
1904 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1906 wxPoint
*point
= (wxPoint
*) node
->GetData();
1907 points
[i
].x
= point
->x
;
1908 points
[i
].y
= point
->y
;
1911 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1915 #endif // WXWIN_COMPATIBILITY_2_8
1918 wxDCBase::DoDrawPolyPolygon(int n
,
1921 wxCoord xoffset
, wxCoord yoffset
,
1926 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1934 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1939 pts
= new wxPoint
[j
+n
-1];
1940 for (i
= 0; i
< j
; i
++)
1942 for (i
= 2; i
<= n
; i
++)
1944 lastOfs
-= count
[n
-i
];
1945 pts
[j
++] = pts
[lastOfs
];
1949 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1950 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1952 for (i
= j
= 0; i
< n
; i
++)
1954 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1960 // ----------------------------------------------------------------------------
1962 // ----------------------------------------------------------------------------
1966 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1968 wxPointList point_list
;
1970 wxPoint
*point1
= new wxPoint
;
1971 point1
->x
= x1
; point1
->y
= y1
;
1972 point_list
.Append( point1
);
1974 wxPoint
*point2
= new wxPoint
;
1975 point2
->x
= x2
; point2
->y
= y2
;
1976 point_list
.Append( point2
);
1978 wxPoint
*point3
= new wxPoint
;
1979 point3
->x
= x3
; point3
->y
= y3
;
1980 point_list
.Append( point3
);
1982 DrawSpline(&point_list
);
1984 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
1986 wxPoint
*p
= node
->GetData();
1991 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
1994 for (int i
=0; i
< n
; i
++)
1995 list
.Append( &points
[i
] );
2000 // ----------------------------------- spline code ----------------------------------------
2002 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
2003 double a3
, double b3
, double a4
, double b4
);
2004 void wx_clear_stack();
2005 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
2006 double *y3
, double *x4
, double *y4
);
2007 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
2008 double x4
, double y4
);
2009 static bool wx_spline_add_point(double x
, double y
);
2010 static void wx_spline_draw_point_array(wxDCBase
*dc
);
2012 wxPointList wx_spline_point_list
;
2014 #define half(z1, z2) ((z1+z2)/2.0)
2017 /* iterative version */
2019 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
2022 register double xmid
, ymid
;
2023 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2026 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
2028 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
2029 xmid
= (double)half(x2
, x3
);
2030 ymid
= (double)half(y2
, y3
);
2031 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
2032 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
2033 wx_spline_add_point( x1
, y1
);
2034 wx_spline_add_point( xmid
, ymid
);
2036 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
2037 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
2038 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
2039 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
2044 /* utilities used by spline drawing routines */
2046 typedef struct wx_spline_stack_struct
{
2047 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2050 #define SPLINE_STACK_DEPTH 20
2051 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2052 static Stack
*wx_stack_top
;
2053 static int wx_stack_count
;
2055 void wx_clear_stack()
2057 wx_stack_top
= wx_spline_stack
;
2061 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2063 wx_stack_top
->x1
= x1
;
2064 wx_stack_top
->y1
= y1
;
2065 wx_stack_top
->x2
= x2
;
2066 wx_stack_top
->y2
= y2
;
2067 wx_stack_top
->x3
= x3
;
2068 wx_stack_top
->y3
= y3
;
2069 wx_stack_top
->x4
= x4
;
2070 wx_stack_top
->y4
= y4
;
2075 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2076 double *x3
, double *y3
, double *x4
, double *y4
)
2078 if (wx_stack_count
== 0)
2082 *x1
= wx_stack_top
->x1
;
2083 *y1
= wx_stack_top
->y1
;
2084 *x2
= wx_stack_top
->x2
;
2085 *y2
= wx_stack_top
->y2
;
2086 *x3
= wx_stack_top
->x3
;
2087 *y3
= wx_stack_top
->y3
;
2088 *x4
= wx_stack_top
->x4
;
2089 *y4
= wx_stack_top
->y4
;
2093 static bool wx_spline_add_point(double x
, double y
)
2095 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
2096 wx_spline_point_list
.Append( point
);
2100 static void wx_spline_draw_point_array(wxDCBase
*dc
)
2102 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2103 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
2106 wxPoint
*point
= node
->GetData();
2108 wx_spline_point_list
.Erase(node
);
2109 node
= wx_spline_point_list
.GetFirst();
2113 #if WXWIN_COMPATIBILITY_2_8
2114 void wxDCBase::DrawSpline(const wxList
*points
)
2117 wxObjectList::compatibility_iterator node
= points
->GetFirst();
2120 list
.Append( (wxPoint
*) node
->GetData() );
2121 node
= node
->GetNext();
2123 DoDrawSpline( &list
);
2125 #endif // WXWIN_COMPATIBILITY_2_8
2127 void wxDCBase::DoDrawSpline( const wxPointList
*points
)
2129 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2132 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2133 double x1
, y1
, x2
, y2
;
2135 wxPointList::compatibility_iterator node
= points
->GetFirst();
2140 p
= node
->GetData();
2145 node
= node
->GetNext();
2146 p
= node
->GetData();
2150 cx1
= (double)((x1
+ x2
) / 2);
2151 cy1
= (double)((y1
+ y2
) / 2);
2152 cx2
= (double)((cx1
+ x2
) / 2);
2153 cy2
= (double)((cy1
+ y2
) / 2);
2155 wx_spline_add_point(x1
, y1
);
2157 while ((node
= node
->GetNext())
2160 #endif // !wxUSE_STL
2163 p
= node
->GetData();
2168 cx4
= (double)(x1
+ x2
) / 2;
2169 cy4
= (double)(y1
+ y2
) / 2;
2170 cx3
= (double)(x1
+ cx4
) / 2;
2171 cy3
= (double)(y1
+ cy4
) / 2;
2173 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2177 cx2
= (double)(cx1
+ x2
) / 2;
2178 cy2
= (double)(cy1
+ y2
) / 2;
2181 wx_spline_add_point( cx1
, cy1
);
2182 wx_spline_add_point( x2
, y2
);
2184 wx_spline_draw_point_array( this );
2187 #endif // wxUSE_SPLINES
2189 // ----------------------------------------------------------------------------
2190 // Partial Text Extents
2191 // ----------------------------------------------------------------------------
2194 // Each element of the widths array will be the width of the string up to and
2195 // including the corresponding character in text. This is the generic
2196 // implementation, the port-specific classes should do this with native APIs
2197 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2198 // than calling GetTextExtent!!
2200 #define FWC_SIZE 256
2202 class FontWidthCache
2205 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
2206 ~FontWidthCache() { delete []m_widths
; }
2211 m_widths
= new int[FWC_SIZE
];
2213 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2221 static FontWidthCache s_fontWidthCache
;
2223 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2227 const size_t len
= text
.length();
2231 // reset the cache if font or horizontal scale have changed
2232 if ( !s_fontWidthCache
.m_widths
||
2233 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2234 (s_fontWidthCache
.m_font
!= GetFont()) )
2236 s_fontWidthCache
.Reset();
2237 s_fontWidthCache
.m_font
= GetFont();
2238 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2241 // Calculate the position of each character based on the widths of
2242 // the previous characters
2244 for ( size_t i
= 0; i
< len
; i
++ )
2246 const wxChar c
= text
[i
];
2247 unsigned int c_int
= (unsigned int)c
;
2249 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2251 w
= s_fontWidthCache
.m_widths
[c_int
];
2255 GetTextExtent(c
, &w
, &h
);
2256 if (c_int
< FWC_SIZE
)
2257 s_fontWidthCache
.m_widths
[c_int
] = w
;
2261 widths
[i
] = totalWidth
;
2268 // ----------------------------------------------------------------------------
2269 // enhanced text drawing
2270 // ----------------------------------------------------------------------------
2272 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2276 const wxFont
*font
) const
2278 wxCoord widthTextMax
= 0, widthLine
,
2279 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2282 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2284 if ( pc
== text
.end() || *pc
== _T('\n') )
2286 if ( curLine
.empty() )
2288 // we can't use GetTextExtent - it will return 0 for both width
2289 // and height and an empty line should count in height
2292 // assume that this line has the same height as the previous
2294 if ( !heightLineDefault
)
2295 heightLineDefault
= heightLine
;
2297 if ( !heightLineDefault
)
2299 // but we don't know it yet - choose something reasonable
2300 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2304 heightTextTotal
+= heightLineDefault
;
2308 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2310 if ( widthLine
> widthTextMax
)
2311 widthTextMax
= widthLine
;
2312 heightTextTotal
+= heightLine
;
2315 if ( pc
== text
.end() )
2333 *y
= heightTextTotal
;
2338 void wxDCBase::DrawLabel(const wxString
& text
,
2339 const wxBitmap
& bitmap
,
2343 wxRect
*rectBounding
)
2345 // find the text position
2346 wxCoord widthText
, heightText
, heightLine
;
2347 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2349 wxCoord width
, height
;
2352 width
= widthText
+ bitmap
.GetWidth();
2353 height
= bitmap
.GetHeight();
2358 height
= heightText
;
2362 if ( alignment
& wxALIGN_RIGHT
)
2364 x
= rect
.GetRight() - width
;
2366 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2368 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2370 else // alignment & wxALIGN_LEFT
2375 if ( alignment
& wxALIGN_BOTTOM
)
2377 y
= rect
.GetBottom() - height
;
2379 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2381 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2383 else // alignment & wxALIGN_TOP
2388 // draw the bitmap first
2394 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2396 wxCoord offset
= bitmap
.GetWidth() + 4;
2400 y
+= (height
- heightText
) / 2;
2403 // we will draw the underscore under the accel char later
2404 wxCoord startUnderscore
= 0,
2408 // split the string into lines and draw each of them separately
2410 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2412 if ( pc
== text
.end() || *pc
== _T('\n') )
2414 int xRealStart
= x
; // init it here to avoid compielr warnings
2416 if ( !curLine
.empty() )
2418 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2419 // wxALIGN_LEFT is 0
2420 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2423 GetTextExtent(curLine
, &widthLine
, NULL
);
2425 if ( alignment
& wxALIGN_RIGHT
)
2427 xRealStart
+= width
- widthLine
;
2429 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2431 xRealStart
+= (width
- widthLine
) / 2;
2434 //else: left aligned, nothing to do
2436 DrawText(curLine
, xRealStart
, y
);
2441 // do we have underscore in this line? we can check yUnderscore
2442 // because it is set below to just y + heightLine if we do
2443 if ( y
== yUnderscore
)
2445 // adjust the horz positions to account for the shift
2446 startUnderscore
+= xRealStart
;
2447 endUnderscore
+= xRealStart
;
2450 if ( pc
== text
.end() )
2455 else // not end of line
2457 if ( pc
- text
.begin() == indexAccel
)
2459 // remeber to draw underscore here
2460 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2462 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2464 yUnderscore
= y
+ heightLine
;
2473 // draw the underscore if found
2474 if ( startUnderscore
!= endUnderscore
)
2476 // it should be of the same colour as text
2477 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2481 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2484 // return bounding rect if requested
2487 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2490 CalcBoundingBox(x0
, y0
);
2491 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2495 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2496 const wxColour
& initialColour
,
2497 const wxColour
& destColour
,
2498 wxDirection nDirection
)
2501 wxPen oldPen
= m_pen
;
2502 wxBrush oldBrush
= m_brush
;
2504 wxUint8 nR1
= initialColour
.Red();
2505 wxUint8 nG1
= initialColour
.Green();
2506 wxUint8 nB1
= initialColour
.Blue();
2507 wxUint8 nR2
= destColour
.Red();
2508 wxUint8 nG2
= destColour
.Green();
2509 wxUint8 nB2
= destColour
.Blue();
2512 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2514 wxInt32 x
= rect
.GetWidth();
2515 wxInt32 w
= x
; // width of area to shade
2516 wxInt32 xDelta
= w
/256; // height of one shade bend
2524 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2526 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2529 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2531 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2534 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2536 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2538 wxColour
colour(nR
,nG
,nB
);
2539 SetPen(wxPen(colour
, 1, wxSOLID
));
2540 SetBrush(wxBrush(colour
));
2541 if(nDirection
== wxEAST
)
2542 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
2543 xDelta
, rect
.GetHeight());
2544 else //nDirection == wxWEST
2545 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2546 xDelta
, rect
.GetHeight());
2549 else // nDirection == wxNORTH || nDirection == wxSOUTH
2551 wxInt32 y
= rect
.GetHeight();
2552 wxInt32 w
= y
; // height of area to shade
2553 wxInt32 yDelta
= w
/255; // height of one shade bend
2561 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2563 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2566 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2568 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2571 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2573 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2575 wxColour
colour(nR
,nG
,nB
);
2576 SetPen(wxPen(colour
, 1, wxSOLID
));
2577 SetBrush(wxBrush(colour
));
2578 if(nDirection
== wxNORTH
)
2579 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2580 rect
.GetWidth(), yDelta
);
2581 else //nDirection == wxSOUTH
2582 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
2583 rect
.GetWidth(), yDelta
);
2591 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2592 const wxColour
& initialColour
,
2593 const wxColour
& destColour
,
2594 const wxPoint
& circleCenter
)
2596 //save the old pen color
2597 wxColour oldPenColour
= m_pen
.GetColour();
2599 wxUint8 nR1
= destColour
.Red();
2600 wxUint8 nG1
= destColour
.Green();
2601 wxUint8 nB1
= destColour
.Blue();
2602 wxUint8 nR2
= initialColour
.Red();
2603 wxUint8 nG2
= initialColour
.Green();
2604 wxUint8 nB2
= initialColour
.Blue();
2609 wxInt32 cx
= rect
.GetWidth() / 2;
2610 wxInt32 cy
= rect
.GetHeight() / 2;
2618 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2619 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2621 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2623 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2625 //get color difference
2626 wxInt32 nGradient
= ((nRadius
-
2628 pow((double)(x
- cx
- nCircleOffX
), 2) +
2629 pow((double)(y
- cy
- nCircleOffY
), 2)
2630 )) * 100) / nRadius
;
2632 //normalize Gradient
2637 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2638 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2639 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2642 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2643 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2646 //return old pen color
2647 m_pen
.SetColour(oldPenColour
);
2651 Notes for wxWidgets DrawEllipticArcRot(...)
2653 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2654 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2657 All methods are generic, so they can be implemented in wxDCBase.
2658 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2659 methods like (WinCE) wxDC::DoDrawArc(...).
2661 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2662 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2663 parts) or every column (in steep parts) only one pixel is calculated.
2664 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2665 starting angle is not equal to the ending angle. The calculation of the
2666 pixels is done using simple arithmetic only and should perform not too
2667 bad even on devices without floating point processor. I didn't test this yet.
2669 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2670 For instance: an ellipse rotated 180 degrees is drawn
2671 slightly different from the original.
2673 The points are then moved to an array and used to draw a polyline and/or polygon
2674 (with center added, the pie).
2675 The result looks quite similar to the native ellipse, only e few pixels differ.
2677 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2678 slower as DrawEllipse(...), which calls the native API.
2679 An rotated ellipse outside the clipping region takes nearly the same time,
2680 while an native ellipse outside takes nearly no time to draw.
2682 If you draw an arc with this new method, you will see the starting and ending angles
2683 are calculated properly.
2684 If you use DrawEllipticArc(...), you will see they are only correct for circles
2685 and not properly calculated for ellipses.
2688 p.lenhard@t-online.de
2692 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2693 wxCoord w
, wxCoord h
,
2694 double sa
, double ea
, double angle
)
2698 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2699 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2701 // Add center (for polygon/pie)
2702 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
2704 // copy list into array and delete list elements
2705 int n
= list
.GetCount();
2706 wxPoint
*points
= new wxPoint
[n
];
2708 wxPointList::compatibility_iterator node
;
2709 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2711 wxPoint
*point
= node
->GetData();
2712 points
[i
].x
= point
->x
;
2713 points
[i
].y
= point
->y
;
2717 // first draw the pie without pen, if necessary
2718 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2720 wxPen
tempPen( GetPen() );
2721 SetPen( *wxTRANSPARENT_PEN
);
2722 DoDrawPolygon( n
, points
, 0, 0 );
2726 // then draw the arc without brush, if necessary
2727 if( GetPen() != *wxTRANSPARENT_PEN
)
2730 DoDrawLines( n
-1, points
, 0, 0 );
2735 } // DrawEllipticArcRot
2737 void wxDCBase::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
2742 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2743 double dCosA
= cos(angle
*2.0*pi
/360.0);
2744 wxPointList::compatibility_iterator node
;
2745 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2747 wxPoint
* point
= node
->GetData();
2749 // transform coordinates, if necessary
2750 if( center
.x
) point
->x
-= center
.x
;
2751 if( center
.y
) point
->y
-= center
.y
;
2753 // calculate rotation, rounding simply by implicit cast to integer
2754 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2755 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2758 // back transform coordinates, if necessary
2759 if( center
.x
) point
->x
+= center
.x
;
2760 if( center
.y
) point
->y
+= center
.y
;
2765 void wxDCBase::CalculateEllipticPoints( wxPointList
* points
,
2766 wxCoord xStart
, wxCoord yStart
,
2767 wxCoord w
, wxCoord h
,
2768 double sa
, double ea
)
2779 bool bUseAngles
= false;
2785 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2787 if( 2*a
== w
) decrX
= 1;
2789 if( 2*b
== h
) decrY
= 1;
2791 wxCoord xCenter
= xStart
+ a
;
2792 wxCoord yCenter
= yStart
+ b
;
2793 // calculate data for start and end, if necessary
2797 // normalisation of angles
2798 while( sa
<0 ) sa
+= 360;
2799 while( ea
<0 ) ea
+= 360;
2800 while( sa
>=360 ) sa
-= 360;
2801 while( ea
>=360 ) ea
-= 360;
2802 // calculate quadrant numbers
2803 if( sa
> 270 ) sq
= 3;
2804 else if( sa
> 180 ) sq
= 2;
2805 else if( sa
> 90 ) sq
= 1;
2806 if( ea
> 270 ) eq
= 3;
2807 else if( ea
> 180 ) eq
= 2;
2808 else if( ea
> 90 ) eq
= 1;
2809 sar
= sa
* pi
/ 180.0;
2810 ear
= ea
* pi
/ 180.0;
2811 // correct angle circle -> ellipse
2812 sar
= atan( -a
/(double)b
* tan( sar
) );
2813 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2814 ear
= atan( -a
/(double)b
* tan( ear
) );
2815 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2816 // coordinates of points
2817 xsa
= xCenter
+ a
* cos( sar
);
2818 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2819 ysa
= yCenter
+ b
* sin( sar
);
2820 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2821 xea
= xCenter
+ a
* cos( ear
);
2822 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2823 yea
= yCenter
+ b
* sin( ear
);
2824 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2826 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2828 double c2
= 2.0 / w
;
2837 // Lists for quadrant 1 to 4
2838 wxPointList pointsarray
[4];
2839 // Calculate points for first quadrant and set in all quadrants
2840 for( x
= 0; x
<= a
; ++x
)
2845 bool bNewPoint
= false;
2846 while( y2
> c1
- c2
* x2
&& y
> 0 )
2852 // old y now to big: set point with old y, old x
2853 if( bNewPoint
&& x
>1)
2856 // remove points on the same line
2857 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2858 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2859 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2860 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2862 } // calculate point
2864 // Starting and/or ending points for the quadrants, first quadrant gets both.
2865 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2866 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
2867 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
2868 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2869 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2871 // copy quadrants in original list
2874 // Copy the right part of the points in the lists
2875 // and delete the wxPoints, because they do not leave this method.
2876 points
->Append( new wxPoint( xsa
, ysa
) );
2878 bool bStarted
= false;
2879 bool bReady
= false;
2880 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2883 wxPointList::compatibility_iterator node
;
2884 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2886 // once: go to starting point in start quadrant
2889 node
->GetData()->x
< xsa
+1 && q
<= 1
2891 node
->GetData()->x
> xsa
-1 && q
>= 2
2898 // copy point, if not at ending point
2901 if( q
!= eq
|| bForceTurn
2903 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2905 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2909 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
2910 points
->Append( pPoint
);
2912 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
2922 } // while not bReady
2923 points
->Append( new wxPoint( xea
, yea
) );
2926 for( q
= 0; q
< 4; ++q
)
2928 wxPointList::compatibility_iterator node
;
2929 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2931 wxPoint
*p
= node
->GetData();
2938 wxPointList::compatibility_iterator node
;
2939 // copy whole ellipse, wxPoints will be deleted outside
2940 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2942 wxPoint
*p
= node
->GetData();
2943 points
->Append( p
);
2945 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2947 wxPoint
*p
= node
->GetData();
2948 points
->Append( p
);
2950 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2952 wxPoint
*p
= node
->GetData();
2953 points
->Append( p
);
2955 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2957 wxPoint
*p
= node
->GetData();
2958 points
->Append( p
);
2961 } // CalculateEllipticPoints
2963 #endif // __WXWINCE__
2965 #endif // wxUSE_NEW_DC