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/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
41 //----------------------------------------------------------------------------
43 //----------------------------------------------------------------------------
45 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
47 void wxDCFactory::SetDCFactory( wxDCFactory
*factory
)
49 if (wxDCFactory::m_factory
)
50 delete wxDCFactory::m_factory
;
52 wxDCFactory::m_factory
= factory
;
55 wxDCFactory
*wxDCFactory::GetFactory()
57 if (!wxDCFactory::m_factory
)
58 wxDCFactory::m_factory
= new wxNativeDCFactory
;
60 return wxDCFactory::m_factory
;
63 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
67 wxImplDC
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
)
69 #if defined(__WXMSW__)
70 return new wxWindowsWindowImplDC( owner
);
71 #elif defined(__WXGTK20__)
72 return new wxGTKWindowImplDC( owner
);
73 #elif defined(__WXGTK__)
74 return new wxGTKWindowImplDC( owner
);
75 #elif defined(__WXMAC__)
76 return new wxMacWindowImplDC( owner
);
77 #elif defined(__WXCOCOA__)
78 return new wxCocoaWindowImplDC( owner
);
79 #elif defined(__WXMOTIF__)
80 return new wxMotifWindowImplDC( owner
);
81 #elif defined(__WXX11__)
82 return new wxX11WindowImplDC( owner
);
83 #elif defined(__WXMGL__)
84 return new wxMGLWindowImplDC( owner
);
85 #elif defined(__WXDFB__)
86 return new wxDFBWindowImplDC( owner
);
87 #elif defined(__WXPM__)
88 return new wxPMWindowImplDC( owner
);
89 #elif defined(__PALMOS__)
90 return new wxPalmWindowImplDC( owner
);
94 wxImplDC
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
96 #if defined(__WXMSW__)
97 return new wxWindowsWindowImplDC( owner
, window
);
98 #elif defined(__WXGTK20__)
99 return new wxGTKWindowImplDC( owner
, window
);
100 #elif defined(__WXGTK__)
101 return new wxGTKWindowImplDC( owner
, window
);
102 #elif defined(__WXMAC__)
103 return new wxMacWindowImplDC( owner
, window
);
104 #elif defined(__WXCOCOA__)
105 return new wxCocoaWindowImplDC( owner
, window
);
106 #elif defined(__WXMOTIF__)
107 return new wxMotifWindowImplDC( owner
, window
);
108 #elif defined(__WXX11__)
109 return new wxX11WindowImplDC( owner
, window
);
110 #elif defined(__WXMGL__)
111 return new wxMGLWindowImplDC( owner
, window
);
112 #elif defined(__WXDFB__)
113 return new wxDFBWindowImplDC( owner
, window
);
114 #elif defined(__WXPM__)
115 return new wxPMWindowImplDC( owner
, window
);
116 #elif defined(__PALMOS__)
117 return new wxPalmWindowImplDC( owner
, window
);
121 wxImplDC
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
)
123 #if defined(__WXMSW__)
124 return new wxWindowsClientImplDC( owner
);
125 #elif defined(__WXGTK20__)
126 return new wxGTKClientImplDC( owner
);
127 #elif defined(__WXGTK__)
128 return new wxGTKClientImplDC( owner
);
129 #elif defined(__WXMAC__)
130 return new wxMacClientImplDC( owner
);
131 #elif defined(__WXCOCOA__)
132 return new wxCocoaClientImplDC( owner
);
133 #elif defined(__WXMOTIF__)
134 return new wxMotifClientImplDC( owner
);
135 #elif defined(__WXX11__)
136 return new wxX11ClientImplDC( owner
);
137 #elif defined(__WXMGL__)
138 return new wxMGLClientImplDC( owner
);
139 #elif defined(__WXDFB__)
140 return new wxDFBClientImplDC( owner
);
141 #elif defined(__WXPM__)
142 return new wxPMClientImplDC( owner
);
143 #elif defined(__PALMOS__)
144 return new wxPalmClientImplDC( owner
);
148 wxImplDC
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
150 #if defined(__WXMSW__)
151 return new wxWindowsClientImplDC( owner
, window
);
152 #elif defined(__WXGTK20__)
153 return new wxGTKClientImplDC( owner
, window
);
154 #elif defined(__WXGTK__)
155 return new wxGTKClientImplDC( owner
, window
);
156 #elif defined(__WXMAC__)
157 return new wxMacClientImplDC( owner
, window
);
158 #elif defined(__WXCOCOA__)
159 return new wxCocoaClientImplDC( owner
, window
);
160 #elif defined(__WXMOTIF__)
161 return new wxMotifClientImplDC( owner
, window
);
162 #elif defined(__WXX11__)
163 return new wxX11ClientImplDC( owner
, window
);
164 #elif defined(__WXMGL__)
165 return new wxMGLClientImplDC( owner
, window
);
166 #elif defined(__WXDFB__)
167 return new wxDFBClientImplDC( owner
, window
);
168 #elif defined(__WXPM__)
169 return new wxPMClientImplDC( owner
, window
);
170 #elif defined(__PALMOS__)
171 return new wxPalmClientImplDC( owner
, window
);
175 wxImplDC
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
)
177 #if defined(__WXMSW__)
178 return new wxWindowsPaintImplDC( owner
);
179 #elif defined(__WXGTK20__)
180 return new wxGTKPaintImplDC( owner
);
181 #elif defined(__WXGTK__)
182 return new wxGTKPaintImplDC( owner
);
183 #elif defined(__WXMAC__)
184 return new wxMacPaintImplDC( owner
);
185 #elif defined(__WXCOCOA__)
186 return new wxCocoaPaintImplDC( owner
);
187 #elif defined(__WXMOTIF__)
188 return new wxMotifPaintImplDC( owner
);
189 #elif defined(__WXX11__)
190 return new wxX11PaintImplDC( owner
);
191 #elif defined(__WXMGL__)
192 return new wxMGLPaintImplDC( owner
);
193 #elif defined(__WXDFB__)
194 return new wxDFBPaintImplDC( owner
);
195 #elif defined(__WXPM__)
196 return new wxPMPaintImplDC( owner
);
197 #elif defined(__PALMOS__)
198 return new wxPalmPaintImplDC( owner
);
202 wxImplDC
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
204 #if defined(__WXMSW__)
205 return new wxWindowsPaintImplDC( owner
, window
);
206 #elif defined(__WXGTK20__)
207 return new wxGTKPaintImplDC( owner
, window
);
208 #elif defined(__WXGTK__)
209 return new wxGTKPaintImplDC( owner
, window
);
210 #elif defined(__WXMAC__)
211 return new wxMacPaintImplDC( owner
, window
);
212 #elif defined(__WXCOCOA__)
213 return new wxCocoaPaintImplDC( owner
, window
);
214 #elif defined(__WXMOTIF__)
215 return new wxMotifPaintImplDC( owner
, window
);
216 #elif defined(__WXX11__)
217 return new wxX11PaintImplDC( owner
, window
);
218 #elif defined(__WXMGL__)
219 return new wxMGLPaintImplDC( owner
, window
);
220 #elif defined(__WXDFB__)
221 return new wxDFBPaintImplDC( owner
, window
);
222 #elif defined(__WXPM__)
223 return new wxPMPaintImplDC( owner
, window
);
224 #elif defined(__PALMOS__)
225 return new wxPalmPaintImplDC( owner
, window
);
229 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
231 #if defined(__WXMSW__)
232 return new wxWindowsMemoryImplDC( owner
);
233 #elif defined(__WXGTK20__)
234 return new wxGTKMemoryImplDC( owner
);
235 #elif defined(__WXGTK__)
236 return new wxGTKMemoryImplDC( owner
);
237 #elif defined(__WXMAC__)
238 return new wxMacMemoryImplDC( owner
);
239 #elif defined(__WXCOCOA__)
240 return new wxCocoaMemoryImplDC( owner
);
241 #elif defined(__WXMOTIF__)
242 return new wxMotifMemoryImplDC( owner
);
243 #elif defined(__WXX11__)
244 return new wxX11MemoryImplDC( owner
);
245 #elif defined(__WXMGL__)
246 return new wxMGLMemoryImplDC( owner
);
247 #elif defined(__WXDFB__)
248 return new wxDFBMemoryImplDC( owner
);
249 #elif defined(__WXPM__)
250 return new wxPMMemoryImplDC( owner
);
251 #elif defined(__PALMOS__)
252 return new wxPalmMemoryImplDC( owner
);
256 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxBitmap
&bitmap
)
258 #if defined(__WXMSW__)
259 return new wxWindowsMemoryImplDC( owner
, bitmap
);
260 #elif defined(__WXGTK20__)
261 return new wxGTKMemoryImplDC( owner
, bitmap
);
262 #elif defined(__WXGTK__)
263 return new wxGTKMemoryImplDC( owner
, bitmap
);
264 #elif defined(__WXMAC__)
265 return new wxMacMemoryImplDC( owner
, bitmap
);
266 #elif defined(__WXCOCOA__)
267 return new wxCocoaMemoryImplDC( owner
, bitmap
);
268 #elif defined(__WXMOTIF__)
269 return new wxMotifMemoryImplDC( owner
, bitmap
);
270 #elif defined(__WXX11__)
271 return new wxX11MemoryImplDC( owner
, bitmap
);
272 #elif defined(__WXMGL__)
273 return new wxMGLMemoryImplDC( owner
, bitmap
);
274 #elif defined(__WXDFB__)
275 return new wxDFBMemoryImplDC( owner
, bitmap
);
276 #elif defined(__WXPM__)
277 return new wxPMMemoryImplDC( owner
, bitmap
);
278 #elif defined(__PALMOS__)
279 return new wxPalmMemoryImplDC( owner
, bitmap
);
283 wxImplDC
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
285 #if defined(__WXMSW__)
286 return new wxWindowsMemoryImplDC( owner
, dc
);
287 #elif defined(__WXGTK20__)
288 return new wxGTKMemoryImplDC( owner
, dc
);
289 #elif defined(__WXGTK__)
290 return new wxGTKMemoryImplDC( owner
, dc
);
291 #elif defined(__WXMAC__)
292 return new wxMacMemoryImplDC( owner
, dc
);
293 #elif defined(__WXCOCOA__)
294 return new wxCocoaMemoryImplDC( owner
, dc
);
295 #elif defined(__WXMOTIF__)
296 return new wxMotifMemoryImplDC( owner
, dc
);
297 #elif defined(__WXX11__)
298 return new wxX11MemoryImplDC( owner
, dc
);
299 #elif defined(__WXMGL__)
300 return new wxMGLMemoryImplDC( owner
, dc
);
301 #elif defined(__WXDFB__)
302 return new wxDFBMemoryImplDC( owner
, dc
);
303 #elif defined(__WXPM__)
304 return new wxPMMemoryImplDC( owner
, dc
);
305 #elif defined(__PALMOS__)
306 return new wxPalmMemoryImplDC( owner
, dc
);
310 wxImplDC
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
312 #if defined(__WXMSW__)
313 return new wxWindowsScreenImplDC( owner
);
314 #elif defined(__WXGTK20__)
315 return new wxGTKScreenImplDC( owner
);
316 #elif defined(__WXGTK__)
317 return new wxGTKScreenImplDC( owner
);
318 #elif defined(__WXMAC__)
319 return new wxMacScreenImplDC( owner
);
320 #elif defined(__WXCOCOA__)
321 return new wxCocoaScreenImplDC( owner
);
322 #elif defined(__WXMOTIF__)
323 return new wxMotifScreenImplDC( owner
);
324 #elif defined(__WXX11__)
325 return new wxX11ScreenImplDC( owner
);
326 #elif defined(__WXMGL__)
327 return new wxMGLScreenImplDC( owner
);
328 #elif defined(__WXDFB__)
329 return new wxDFBScreenImplDC( owner
);
330 #elif defined(__WXPM__)
331 return new wxPMScreenImplDC( owner
);
332 #elif defined(__PALMOS__)
333 return new wxPalmScreenImplDC( owner
);
337 wxImpleDC
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*ownder
, const wxPrintData
&data
)
339 #if defined(__WXMSW__)
340 return new wxWindowsPrinterImplDC( owner
);
341 #elif defined(__WXGTK20__)
342 return new wxGTKPrinterImplDC( owner
);
343 #elif defined(__WXGTK__)
344 return new wxGTKPrinterImplDC( owner
);
345 #elif defined(__WXMAC__)
346 return new wxMacPrinterImplDC( owner
);
347 #elif defined(__WXCOCOA__)
348 return new wxCocoaPrinterImplDC( owner
);
349 #elif defined(__WXMOTIF__)
350 return new wxMotifPrinterImplDC( owner
);
351 #elif defined(__WXX11__)
352 return new wxX11PrinterImplDC( owner
);
353 #elif defined(__WXMGL__)
354 return new wxMGLPrinterImplDC( owner
);
355 #elif defined(__WXDFB__)
356 return new wxDFBPrinterImplDC( owner
);
357 #elif defined(__WXPM__)
358 return new wxPMPrinterImplDC( owner
);
359 #elif defined(__PALMOS__)
360 return new wxPalmPrinterImplDC( owner
);
364 //-----------------------------------------------------------------------------
366 //-----------------------------------------------------------------------------
368 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
370 wxWindowDC::wxWindowDC()
372 wxDCFactory
*factory
= wxDCFactory::GetFactory();
373 m_pimpl
= factory
->CreateWindowDC( this );
376 wxWindowDC::wxWindowDC( wxWindow
*win
)
378 wxDCFactory
*factory
= wxDCFactory::GetFactory();
379 m_pimpl
= factory
->CreateWindowDC( this, win
);
382 //-----------------------------------------------------------------------------
384 //-----------------------------------------------------------------------------
386 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxDC
)
388 wxClientDC::wxClientDC()
390 wxDCFactory
*factory
= wxDCFactory::GetFactory();
391 m_pimpl
= factory
->CreateClientDC( this );
394 wxClientDC::wxClientDC( wxWindow
*win
)
396 wxDCFactory
*factory
= wxDCFactory::GetFactory();
397 m_pimpl
= factory
->CreateClientDC( this, win
);
400 //-----------------------------------------------------------------------------
402 //-----------------------------------------------------------------------------
404 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
406 wxMemoryDC::wxMemoryDC()
408 wxDCFactory
*factory
= wxDCFactory::GetFactory();
409 m_pimpl
= factory
->CreateMemoryDC( this );
412 wxMemoryDC::wxMemoryDC( wxBitmap
& bitmap
)
414 wxDCFactory
*factory
= wxDCFactory::GetFactory();
415 m_pimpl
= factory
->CreateMemoryDC( this, bitmap
);
418 wxMemoryDC::wxMemoryDC( wxDC
*dc
)
420 wxDCFactory
*factory
= wxDCFactory::GetFactory();
421 m_pimpl
= factory
->CreateMemoryDC( this, dc
);
424 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
426 // make sure that the given wxBitmap is not sharing its data with other
427 // wxBitmap instances as its contents will be modified by any drawing
428 // operation done on this DC
433 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
438 mem_pimpl
->DoSelect(bmp
);
441 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
444 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
448 mem_pimpl
->DoSelect(bmp
);
451 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
454 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
459 return mem_pimpl
->DoGetSelectedBitmap();
464 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
467 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
473 return mem_pimpl
->DoGetSelectedBitmap();
479 //-----------------------------------------------------------------------------
481 //-----------------------------------------------------------------------------
483 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxDC
)
485 wxPaintDC::wxPaintDC()
487 wxDCFactory
*factory
= wxDCFactory::GetFactory();
488 m_pimpl
= factory
->CreatePaintDC( this );
491 wxPaintDC::wxPaintDC( wxWindow
*win
)
493 wxDCFactory
*factory
= wxDCFactory::GetFactory();
494 m_pimpl
= factory
->CreatePaintDC( this, win
);
497 //-----------------------------------------------------------------------------
499 //-----------------------------------------------------------------------------
501 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
503 wxScreenDC::wxScreenDC()
505 wxDCFactory
*factory
= wxDCFactory::GetFactory();
506 m_pimpl
= factory
->CreateScreenDC( this );
509 //-----------------------------------------------------------------------------
511 //-----------------------------------------------------------------------------
513 IMPLEMENT_ABSTRACT_CLASS(wxImplDC
, wxObject
)
515 wxImplDC::wxImplDC( wxDC
*owner
)
516 : m_colour(wxColourDisplay())
520 , m_isBBoxValid(false)
521 , m_logicalOriginX(0), m_logicalOriginY(0)
522 , m_deviceOriginX(0), m_deviceOriginY(0)
523 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
524 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
525 , m_userScaleX(1.0), m_userScaleY(1.0)
526 , m_scaleX(1.0), m_scaleY(1.0)
527 , m_signX(1), m_signY(1)
528 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
529 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
530 , m_logicalFunction(wxCOPY
)
531 , m_backgroundMode(wxTRANSPARENT
)
532 , m_mappingMode(wxMM_TEXT
)
535 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
536 , m_textForegroundColour(*wxBLACK
)
537 , m_textBackgroundColour(*wxWHITE
)
541 , m_hasCustomPalette(false)
542 #endif // wxUSE_PALETTE
546 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
547 (double)wxGetDisplaySizeMM().GetWidth();
548 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
549 (double)wxGetDisplaySizeMM().GetHeight();
555 wxImplDC::~wxImplDC()
559 // ----------------------------------------------------------------------------
560 // coordinate conversions and transforms
561 // ----------------------------------------------------------------------------
563 wxCoord
wxImplDC::DeviceToLogicalX(wxCoord x
) const
565 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
568 wxCoord
wxImplDC::DeviceToLogicalY(wxCoord y
) const
570 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
573 wxCoord
wxImplDC::DeviceToLogicalXRel(wxCoord x
) const
575 return wxRound((double)(x
) / m_scaleX
);
578 wxCoord
wxImplDC::DeviceToLogicalYRel(wxCoord y
) const
580 return wxRound((double)(y
) / m_scaleY
);
583 wxCoord
wxImplDC::LogicalToDeviceX(wxCoord x
) const
585 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
588 wxCoord
wxImplDC::LogicalToDeviceY(wxCoord y
) const
590 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ m_deviceLocalOriginY
;
593 wxCoord
wxImplDC::LogicalToDeviceXRel(wxCoord x
) const
595 return wxRound((double)(x
) * m_scaleX
);
598 wxCoord
wxImplDC::LogicalToDeviceYRel(wxCoord y
) const
600 return wxRound((double)(y
) * m_scaleY
);
603 void wxImplDC::ComputeScaleAndOrigin()
605 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
606 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
609 void wxImplDC::SetMapMode( int mode
)
614 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
617 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
620 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
623 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
627 SetLogicalScale( 1.0, 1.0 );
630 m_mappingMode
= mode
;
633 void wxImplDC::SetUserScale( double x
, double y
)
635 // allow negative ? -> no
638 ComputeScaleAndOrigin();
641 void wxImplDC::SetLogicalScale( double x
, double y
)
646 ComputeScaleAndOrigin();
649 void wxImplDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
651 m_logicalOriginX
= x
* m_signX
;
652 m_logicalOriginY
= y
* m_signY
;
653 ComputeScaleAndOrigin();
656 void wxImplDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
660 ComputeScaleAndOrigin();
663 void wxImplDC::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
665 m_deviceLocalOriginX
= x
;
666 m_deviceLocalOriginY
= y
;
667 ComputeScaleAndOrigin();
670 void wxImplDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
672 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
673 // wxWidgets 2.9: no longer override it
674 m_signX
= (xLeftRight
? 1 : -1);
675 m_signY
= (yBottomUp
? -1 : 1);
676 ComputeScaleAndOrigin();
680 // Each element of the widths array will be the width of the string up to and
681 // including the corresponding character in text. This is the generic
682 // implementation, the port-specific classes should do this with native APIs
683 // if available and if faster. Note: pango_layout_index_to_pos is much slower
684 // than calling GetTextExtent!!
691 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
692 ~FontWidthCache() { delete []m_widths
; }
697 m_widths
= new int[FWC_SIZE
];
699 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
707 static FontWidthCache s_fontWidthCache
;
709 bool wxImplDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
713 const size_t len
= text
.length();
717 // reset the cache if font or horizontal scale have changed
718 if ( !s_fontWidthCache
.m_widths
||
719 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
720 (s_fontWidthCache
.m_font
!= GetFont()) )
722 s_fontWidthCache
.Reset();
723 s_fontWidthCache
.m_font
= GetFont();
724 s_fontWidthCache
.m_scaleX
= m_scaleX
;
727 // Calculate the position of each character based on the widths of
728 // the previous characters
730 for ( size_t i
= 0; i
< len
; i
++ )
732 const wxChar c
= text
[i
];
733 unsigned int c_int
= (unsigned int)c
;
735 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
737 w
= s_fontWidthCache
.m_widths
[c_int
];
741 DoGetTextExtent(c
, &w
, &h
);
742 if (c_int
< FWC_SIZE
)
743 s_fontWidthCache
.m_widths
[c_int
] = w
;
747 widths
[i
] = totalWidth
;
753 void wxImplDC::GetMultiLineTextExtent(const wxString
& text
,
757 const wxFont
*font
) const
759 wxCoord widthTextMax
= 0, widthLine
,
760 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
763 for ( const wxChar
*pc
= text
; ; pc
++ )
765 if ( *pc
== _T('\n') || *pc
== _T('\0') )
767 if ( curLine
.empty() )
769 // we can't use GetTextExtent - it will return 0 for both width
770 // and height and an empty line should count in height
773 // assume that this line has the same height as the previous
775 if ( !heightLineDefault
)
776 heightLineDefault
= heightLine
;
778 if ( !heightLineDefault
)
780 // but we don't know it yet - choose something reasonable
781 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
785 heightTextTotal
+= heightLineDefault
;
789 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
791 if ( widthLine
> widthTextMax
)
792 widthTextMax
= widthLine
;
793 heightTextTotal
+= heightLine
;
796 if ( *pc
== _T('\n') )
815 *y
= heightTextTotal
;
820 void wxImplDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
821 wxCoord width
, wxCoord height
)
823 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
825 wxCoord x2
= x1
+ width
,
828 // the pen width is calibrated to give 3 for width == height == 10
829 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
831 // we're drawing a scaled version of wx/generic/tick.xpm here
832 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
833 y3
= y1
+ height
/ 2; // y of the left tick branch
834 DoDrawLine(x1
, y3
, x3
, y2
);
835 DoDrawLine(x3
, y2
, x2
, y1
);
837 CalcBoundingBox(x1
, y1
);
838 CalcBoundingBox(x2
, y2
);
842 wxImplDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
843 wxCoord dstWidth
, wxCoord dstHeight
,
845 wxCoord xsrc
, wxCoord ysrc
,
846 wxCoord srcWidth
, wxCoord srcHeight
,
852 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
853 _T("invalid blit size") );
855 // emulate the stretching by modifying the DC scale
856 double xscale
= (double)srcWidth
/dstWidth
,
857 yscale
= (double)srcHeight
/dstHeight
;
859 double xscaleOld
, yscaleOld
;
860 GetUserScale(&xscaleOld
, &yscaleOld
);
861 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
863 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
864 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
866 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
868 SetUserScale(xscaleOld
, yscaleOld
);
873 void wxImplDC::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
875 int n
= list
->GetCount();
876 wxPoint
*points
= new wxPoint
[n
];
879 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
881 wxPoint
*point
= node
->GetData();
882 points
[i
].x
= point
->x
;
883 points
[i
].y
= point
->y
;
886 DoDrawLines(n
, points
, xoffset
, yoffset
);
891 void wxImplDC::DrawPolygon(const wxPointList
*list
,
892 wxCoord xoffset
, wxCoord yoffset
,
895 int n
= list
->GetCount();
896 wxPoint
*points
= new wxPoint
[n
];
899 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
901 wxPoint
*point
= node
->GetData();
902 points
[i
].x
= point
->x
;
903 points
[i
].y
= point
->y
;
906 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
912 wxImplDC::DoDrawPolyPolygon(int n
,
915 wxCoord xoffset
, wxCoord yoffset
,
920 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
928 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
933 pts
= new wxPoint
[j
+n
-1];
934 for (i
= 0; i
< j
; i
++)
936 for (i
= 2; i
<= n
; i
++)
938 lastOfs
-= count
[n
-i
];
939 pts
[j
++] = pts
[lastOfs
];
943 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
944 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
946 for (i
= j
= 0; i
< n
; i
++)
948 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
956 void wxImplDC::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
958 wxPointList point_list
;
960 wxPoint
*point1
= new wxPoint
;
961 point1
->x
= x1
; point1
->y
= y1
;
962 point_list
.Append( point1
);
964 wxPoint
*point2
= new wxPoint
;
965 point2
->x
= x2
; point2
->y
= y2
;
966 point_list
.Append( point2
);
968 wxPoint
*point3
= new wxPoint
;
969 point3
->x
= x3
; point3
->y
= y3
;
970 point_list
.Append( point3
);
972 DoDrawSpline(&point_list
);
974 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
976 wxPoint
*p
= node
->GetData();
981 void wxImplDC::DoDrawSpline(int n
, wxPoint points
[])
984 for (int i
=0; i
< n
; i
++)
985 list
.Append( &points
[i
] );
990 // ----------------------------------- spline code ----------------------------------------
992 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
993 double a3
, double b3
, double a4
, double b4
);
994 void wx_clear_stack();
995 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
996 double *y3
, double *x4
, double *y4
);
997 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
998 double x4
, double y4
);
999 static bool wx_spline_add_point(double x
, double y
);
1000 static void wx_spline_draw_point_array(wxDC
*dc
);
1002 wxPointList wx_spline_point_list
;
1004 #define half(z1, z2) ((z1+z2)/2.0)
1007 /* iterative version */
1009 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1012 register double xmid
, ymid
;
1013 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1016 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1018 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1019 xmid
= (double)half(x2
, x3
);
1020 ymid
= (double)half(y2
, y3
);
1021 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1022 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1023 wx_spline_add_point( x1
, y1
);
1024 wx_spline_add_point( xmid
, ymid
);
1026 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1027 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1028 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1029 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1034 /* utilities used by spline drawing routines */
1036 typedef struct wx_spline_stack_struct
{
1037 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1040 #define SPLINE_STACK_DEPTH 20
1041 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1042 static Stack
*wx_stack_top
;
1043 static int wx_stack_count
;
1045 void wx_clear_stack()
1047 wx_stack_top
= wx_spline_stack
;
1051 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1053 wx_stack_top
->x1
= x1
;
1054 wx_stack_top
->y1
= y1
;
1055 wx_stack_top
->x2
= x2
;
1056 wx_stack_top
->y2
= y2
;
1057 wx_stack_top
->x3
= x3
;
1058 wx_stack_top
->y3
= y3
;
1059 wx_stack_top
->x4
= x4
;
1060 wx_stack_top
->y4
= y4
;
1065 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1066 double *x3
, double *y3
, double *x4
, double *y4
)
1068 if (wx_stack_count
== 0)
1072 *x1
= wx_stack_top
->x1
;
1073 *y1
= wx_stack_top
->y1
;
1074 *x2
= wx_stack_top
->x2
;
1075 *y2
= wx_stack_top
->y2
;
1076 *x3
= wx_stack_top
->x3
;
1077 *y3
= wx_stack_top
->y3
;
1078 *x4
= wx_stack_top
->x4
;
1079 *y4
= wx_stack_top
->y4
;
1083 static bool wx_spline_add_point(double x
, double y
)
1085 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
1086 wx_spline_point_list
.Append(point
);
1090 static void wx_spline_draw_point_array(wxDC
*dc
)
1092 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1095 wxPoint
*point
= node
->GetData();
1097 wx_spline_point_list
.Erase(node
);
1098 node
= wx_spline_point_list
.GetFirst();
1102 void wxImplDC::DoDrawSpline( const wxPointList
*points
)
1104 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
1107 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1108 double x1
, y1
, x2
, y2
;
1110 wxPointList::compatibility_iterator node
= points
->GetFirst();
1115 p
= (wxPoint
*)node
->GetData();
1120 node
= node
->GetNext();
1121 p
= node
->GetData();
1125 cx1
= (double)((x1
+ x2
) / 2);
1126 cy1
= (double)((y1
+ y2
) / 2);
1127 cx2
= (double)((cx1
+ x2
) / 2);
1128 cy2
= (double)((cy1
+ y2
) / 2);
1130 wx_spline_add_point(x1
, y1
);
1132 while ((node
= node
->GetNext())
1135 #endif // !wxUSE_STL
1138 p
= node
->GetData();
1143 cx4
= (double)(x1
+ x2
) / 2;
1144 cy4
= (double)(y1
+ y2
) / 2;
1145 cx3
= (double)(x1
+ cx4
) / 2;
1146 cy3
= (double)(y1
+ cy4
) / 2;
1148 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1152 cx2
= (double)(cx1
+ x2
) / 2;
1153 cy2
= (double)(cy1
+ y2
) / 2;
1156 wx_spline_add_point( cx1
, cy1
);
1157 wx_spline_add_point( x2
, y2
);
1159 wx_spline_draw_point_array( m_owner
);
1162 #endif // wxUSE_SPLINES
1166 void wxImplDC::DoGradientFillLinear(const wxRect
& rect
,
1167 const wxColour
& initialColour
,
1168 const wxColour
& destColour
,
1169 wxDirection nDirection
)
1172 wxPen oldPen
= m_pen
;
1173 wxBrush oldBrush
= m_brush
;
1175 wxUint8 nR1
= initialColour
.Red();
1176 wxUint8 nG1
= initialColour
.Green();
1177 wxUint8 nB1
= initialColour
.Blue();
1178 wxUint8 nR2
= destColour
.Red();
1179 wxUint8 nG2
= destColour
.Green();
1180 wxUint8 nB2
= destColour
.Blue();
1183 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
1185 wxInt32 x
= rect
.GetWidth();
1186 wxInt32 w
= x
; // width of area to shade
1187 wxInt32 xDelta
= w
/256; // height of one shade bend
1195 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1197 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1200 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1202 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1205 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1207 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1209 wxColour
colour(nR
,nG
,nB
);
1210 SetPen(wxPen(colour
, 1, wxSOLID
));
1211 SetBrush(wxBrush(colour
));
1212 if(nDirection
== wxEAST
)
1213 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1214 xDelta
, rect
.GetHeight());
1215 else //nDirection == wxWEST
1216 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1217 xDelta
, rect
.GetHeight());
1220 else // nDirection == wxNORTH || nDirection == wxSOUTH
1222 wxInt32 y
= rect
.GetHeight();
1223 wxInt32 w
= y
; // height of area to shade
1224 wxInt32 yDelta
= w
/255; // height of one shade bend
1232 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1234 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1237 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1239 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1242 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1244 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1246 wxColour
colour(nR
,nG
,nB
);
1247 SetPen(wxPen(colour
, 1, wxSOLID
));
1248 SetBrush(wxBrush(colour
));
1249 if(nDirection
== wxNORTH
)
1250 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1251 rect
.GetWidth(), yDelta
);
1252 else //nDirection == wxSOUTH
1253 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1254 rect
.GetWidth(), yDelta
);
1262 void wxImplDC::DoGradientFillConcentric(const wxRect
& rect
,
1263 const wxColour
& initialColour
,
1264 const wxColour
& destColour
,
1265 const wxPoint
& circleCenter
)
1267 //save the old pen color
1268 wxColour oldPenColour
= m_pen
.GetColour();
1270 wxUint8 nR1
= destColour
.Red();
1271 wxUint8 nG1
= destColour
.Green();
1272 wxUint8 nB1
= destColour
.Blue();
1273 wxUint8 nR2
= initialColour
.Red();
1274 wxUint8 nG2
= initialColour
.Green();
1275 wxUint8 nB2
= initialColour
.Blue();
1280 wxInt32 cx
= rect
.GetWidth() / 2;
1281 wxInt32 cy
= rect
.GetHeight() / 2;
1289 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1290 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1292 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1294 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1296 //get color difference
1297 wxInt32 nGradient
= ((nRadius
-
1299 pow((double)(x
- cx
- nCircleOffX
), 2) +
1300 pow((double)(y
- cy
- nCircleOffY
), 2)
1301 )) * 100) / nRadius
;
1303 //normalize Gradient
1308 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1309 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1310 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1313 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1314 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1317 //return old pen color
1318 m_pen
.SetColour(oldPenColour
);
1321 //-----------------------------------------------------------------------------
1323 //-----------------------------------------------------------------------------
1325 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1327 void wxDC::DrawLabel(const wxString
& text
,
1328 const wxBitmap
& bitmap
,
1332 wxRect
*rectBounding
)
1334 // find the text position
1335 wxCoord widthText
, heightText
, heightLine
;
1336 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1338 wxCoord width
, height
;
1341 width
= widthText
+ bitmap
.GetWidth();
1342 height
= bitmap
.GetHeight();
1347 height
= heightText
;
1351 if ( alignment
& wxALIGN_RIGHT
)
1353 x
= rect
.GetRight() - width
;
1355 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1357 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1359 else // alignment & wxALIGN_LEFT
1364 if ( alignment
& wxALIGN_BOTTOM
)
1366 y
= rect
.GetBottom() - height
;
1368 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1370 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1372 else // alignment & wxALIGN_TOP
1377 // draw the bitmap first
1383 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1385 wxCoord offset
= bitmap
.GetWidth() + 4;
1389 y
+= (height
- heightText
) / 2;
1392 // we will draw the underscore under the accel char later
1393 wxCoord startUnderscore
= 0,
1397 // split the string into lines and draw each of them separately
1399 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1401 if ( *pc
== _T('\n') || pc
== text
.end() )
1403 int xRealStart
= x
; // init it here to avoid compielr warnings
1405 if ( !curLine
.empty() )
1407 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1408 // wxALIGN_LEFT is 0
1409 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1412 GetTextExtent(curLine
, &widthLine
, NULL
);
1414 if ( alignment
& wxALIGN_RIGHT
)
1416 xRealStart
+= width
- widthLine
;
1418 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1420 xRealStart
+= (width
- widthLine
) / 2;
1423 //else: left aligned, nothing to do
1425 DrawText(curLine
, xRealStart
, y
);
1430 // do we have underscore in this line? we can check yUnderscore
1431 // because it is set below to just y + heightLine if we do
1432 if ( y
== yUnderscore
)
1434 // adjust the horz positions to account for the shift
1435 startUnderscore
+= xRealStart
;
1436 endUnderscore
+= xRealStart
;
1439 if ( pc
== text
.end() )
1444 else // not end of line
1446 if ( pc
- text
.begin() == indexAccel
)
1448 // remeber to draw underscore here
1449 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1451 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1453 yUnderscore
= y
+ heightLine
;
1462 // draw the underscore if found
1463 if ( startUnderscore
!= endUnderscore
)
1465 // it should be of the same colour as text
1466 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1470 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1473 // return bounding rect if requested
1476 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1479 CalcBoundingBox(x0
, y0
);
1480 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1483 #if WXWIN_COMPATIBILITY_2_8
1484 // for compatibility with the old code when wxCoord was long everywhere
1485 void wxDC::GetTextExtent(const wxString
& string
,
1488 long *externalLeading
,
1489 const wxFont
*theFont
) const
1491 wxCoord x2
, y2
, descent2
, externalLeading2
;
1492 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1493 &descent2
, &externalLeading2
,
1500 *descent
= descent2
;
1501 if ( externalLeading
)
1502 *externalLeading
= externalLeading2
;
1505 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1508 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1515 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1518 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1525 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1527 wxCoord xx
,yy
,ww
,hh
;
1528 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1535 #endif // WXWIN_COMPATIBILITY_2_8
1538 #else // wxUSE_NEW_DC
1541 // bool wxDCBase::sm_cacheing = false;
1543 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1545 // ============================================================================
1547 // ============================================================================
1549 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1550 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1552 wxDCBase::wxDCBase()
1553 : m_colour(wxColourDisplay())
1556 , m_isInteractive(0)
1557 , m_isBBoxValid(false)
1558 , m_logicalOriginX(0), m_logicalOriginY(0)
1559 , m_deviceOriginX(0), m_deviceOriginY(0)
1560 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1561 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1562 , m_userScaleX(1.0), m_userScaleY(1.0)
1563 , m_scaleX(1.0), m_scaleY(1.0)
1564 , m_signX(1), m_signY(1)
1565 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1566 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1567 , m_logicalFunction(wxCOPY
)
1568 , m_backgroundMode(wxTRANSPARENT
)
1569 , m_mappingMode(wxMM_TEXT
)
1572 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1573 , m_textForegroundColour(*wxBLACK
)
1574 , m_textBackgroundColour(*wxWHITE
)
1578 , m_hasCustomPalette(false)
1579 #endif // wxUSE_PALETTE
1581 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1582 (double)wxGetDisplaySizeMM().GetWidth();
1583 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1584 (double)wxGetDisplaySizeMM().GetHeight();
1590 wxDCBase::~wxDCBase()
1594 #if WXWIN_COMPATIBILITY_2_6
1595 void wxDCBase::BeginDrawing()
1599 void wxDCBase::EndDrawing()
1602 #endif // WXWIN_COMPATIBILITY_2_6
1604 #if WXWIN_COMPATIBILITY_2_8
1605 // for compatibility with the old code when wxCoord was long everywhere
1606 void wxDCBase::GetTextExtent(const wxString
& string
,
1609 long *externalLeading
,
1610 const wxFont
*theFont
) const
1612 wxCoord x2
, y2
, descent2
, externalLeading2
;
1613 DoGetTextExtent(string
, &x2
, &y2
,
1614 &descent2
, &externalLeading2
,
1621 *descent
= descent2
;
1622 if ( externalLeading
)
1623 *externalLeading
= externalLeading2
;
1626 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1629 DoGetLogicalOrigin(&x2
, &y2
);
1636 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1639 DoGetDeviceOrigin(&x2
, &y2
);
1646 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1648 wxCoord xx
,yy
,ww
,hh
;
1649 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1655 #endif // WXWIN_COMPATIBILITY_2_8
1659 // ----------------------------------------------------------------------------
1660 // coordinate conversions and transforms
1661 // ----------------------------------------------------------------------------
1663 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1665 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1668 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1670 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1673 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1675 return wxRound((double)(x
) / m_scaleX
);
1678 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1680 return wxRound((double)(y
) / m_scaleY
);
1683 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1685 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1688 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1690 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1693 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1695 return wxRound((double)(x
) * m_scaleX
);
1698 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1700 return wxRound((double)(y
) * m_scaleY
);
1703 void wxDCBase::ComputeScaleAndOrigin()
1705 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1706 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1709 void wxDCBase::SetMapMode( int mode
)
1714 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1717 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1720 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1723 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1727 SetLogicalScale( 1.0, 1.0 );
1730 m_mappingMode
= mode
;
1733 void wxDCBase::SetUserScale( double x
, double y
)
1735 // allow negative ? -> no
1738 ComputeScaleAndOrigin();
1741 void wxDCBase::SetLogicalScale( double x
, double y
)
1744 m_logicalScaleX
= x
;
1745 m_logicalScaleY
= y
;
1746 ComputeScaleAndOrigin();
1749 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1751 m_logicalOriginX
= x
* m_signX
;
1752 m_logicalOriginY
= y
* m_signY
;
1753 ComputeScaleAndOrigin();
1756 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1758 m_deviceOriginX
= x
;
1759 m_deviceOriginY
= y
;
1760 ComputeScaleAndOrigin();
1763 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1765 m_deviceLocalOriginX
= x
;
1766 m_deviceLocalOriginY
= y
;
1767 ComputeScaleAndOrigin();
1770 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1772 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1773 // wxWidgets 2.9: no longer override it
1774 m_signX
= (xLeftRight
? 1 : -1);
1775 m_signY
= (yBottomUp
? -1 : 1);
1776 ComputeScaleAndOrigin();
1779 // ----------------------------------------------------------------------------
1781 // ----------------------------------------------------------------------------
1783 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1784 wxCoord width
, wxCoord height
)
1786 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1788 wxCoord x2
= x1
+ width
,
1791 // the pen width is calibrated to give 3 for width == height == 10
1792 wxDCPenChanger
pen((wxDC
&)*this,
1793 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1795 // we're drawing a scaled version of wx/generic/tick.xpm here
1796 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1797 y3
= y1
+ height
/ 2; // y of the left tick branch
1798 DoDrawLine(x1
, y3
, x3
, y2
);
1799 DoDrawLine(x3
, y2
, x2
, y1
);
1801 CalcBoundingBox(x1
, y1
);
1802 CalcBoundingBox(x2
, y2
);
1805 // ----------------------------------------------------------------------------
1806 // stubs for functions not implemented in all ports
1807 // ----------------------------------------------------------------------------
1810 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1811 wxCoord dstWidth
, wxCoord dstHeight
,
1813 wxCoord xsrc
, wxCoord ysrc
,
1814 wxCoord srcWidth
, wxCoord srcHeight
,
1820 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1821 _T("invalid blit size") );
1823 // emulate the stretching by modifying the DC scale
1824 double xscale
= (double)srcWidth
/dstWidth
,
1825 yscale
= (double)srcHeight
/dstHeight
;
1827 double xscaleOld
, yscaleOld
;
1828 GetUserScale(&xscaleOld
, &yscaleOld
);
1829 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1831 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1832 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1834 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1836 SetUserScale(xscaleOld
, yscaleOld
);
1841 // ----------------------------------------------------------------------------
1843 // ----------------------------------------------------------------------------
1845 void wxDCBase::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1847 unsigned int n
= list
->GetCount();
1848 wxPoint
*points
= new wxPoint
[n
];
1851 wxPointList::compatibility_iterator node
;
1852 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1854 wxPoint
*point
= node
->GetData();
1855 points
[i
].x
= point
->x
;
1856 points
[i
].y
= point
->y
;
1859 DoDrawLines(n
, points
, xoffset
, yoffset
);
1864 #if WXWIN_COMPATIBILITY_2_8
1865 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1867 unsigned int n
= list
->GetCount();
1868 wxPoint
*points
= new wxPoint
[n
];
1871 wxObjectList::compatibility_iterator node
;
1872 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1874 wxPoint
*point
= (wxPoint
*) node
->GetData();
1875 points
[i
].x
= point
->x
;
1876 points
[i
].y
= point
->y
;
1879 DoDrawLines(n
, points
, xoffset
, yoffset
);
1883 #endif // WXWIN_COMPATIBILITY_2_8
1886 void wxDCBase::DrawPolygon(const wxPointList
*list
,
1887 wxCoord xoffset
, wxCoord yoffset
,
1890 unsigned int n
= list
->GetCount();
1891 wxPoint
*points
= new wxPoint
[n
];
1894 wxPointList::compatibility_iterator node
;
1895 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1897 wxPoint
*point
= node
->GetData();
1898 points
[i
].x
= point
->x
;
1899 points
[i
].y
= point
->y
;
1902 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1908 #if WXWIN_COMPATIBILITY_2_8
1909 void wxDCBase::DrawPolygon(const wxList
*list
,
1910 wxCoord xoffset
, wxCoord yoffset
,
1913 unsigned int n
= list
->GetCount();
1914 wxPoint
*points
= new wxPoint
[n
];
1917 wxObjectList::compatibility_iterator node
;
1918 for ( node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1920 wxPoint
*point
= (wxPoint
*) node
->GetData();
1921 points
[i
].x
= point
->x
;
1922 points
[i
].y
= point
->y
;
1925 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1929 #endif // WXWIN_COMPATIBILITY_2_8
1932 wxDCBase::DoDrawPolyPolygon(int n
,
1935 wxCoord xoffset
, wxCoord yoffset
,
1940 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1948 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1953 pts
= new wxPoint
[j
+n
-1];
1954 for (i
= 0; i
< j
; i
++)
1956 for (i
= 2; i
<= n
; i
++)
1958 lastOfs
-= count
[n
-i
];
1959 pts
[j
++] = pts
[lastOfs
];
1963 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1964 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1966 for (i
= j
= 0; i
< n
; i
++)
1968 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1974 // ----------------------------------------------------------------------------
1976 // ----------------------------------------------------------------------------
1980 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1982 wxPointList point_list
;
1984 wxPoint
*point1
= new wxPoint
;
1985 point1
->x
= x1
; point1
->y
= y1
;
1986 point_list
.Append( point1
);
1988 wxPoint
*point2
= new wxPoint
;
1989 point2
->x
= x2
; point2
->y
= y2
;
1990 point_list
.Append( point2
);
1992 wxPoint
*point3
= new wxPoint
;
1993 point3
->x
= x3
; point3
->y
= y3
;
1994 point_list
.Append( point3
);
1996 DrawSpline(&point_list
);
1998 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
2000 wxPoint
*p
= node
->GetData();
2005 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
2008 for (int i
=0; i
< n
; i
++)
2009 list
.Append( &points
[i
] );
2014 // ----------------------------------- spline code ----------------------------------------
2016 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
2017 double a3
, double b3
, double a4
, double b4
);
2018 void wx_clear_stack();
2019 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
2020 double *y3
, double *x4
, double *y4
);
2021 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
2022 double x4
, double y4
);
2023 static bool wx_spline_add_point(double x
, double y
);
2024 static void wx_spline_draw_point_array(wxDCBase
*dc
);
2026 wxPointList wx_spline_point_list
;
2028 #define half(z1, z2) ((z1+z2)/2.0)
2031 /* iterative version */
2033 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
2036 register double xmid
, ymid
;
2037 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2040 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
2042 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
2043 xmid
= (double)half(x2
, x3
);
2044 ymid
= (double)half(y2
, y3
);
2045 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
2046 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
2047 wx_spline_add_point( x1
, y1
);
2048 wx_spline_add_point( xmid
, ymid
);
2050 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
2051 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
2052 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
2053 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
2058 /* utilities used by spline drawing routines */
2060 typedef struct wx_spline_stack_struct
{
2061 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2064 #define SPLINE_STACK_DEPTH 20
2065 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2066 static Stack
*wx_stack_top
;
2067 static int wx_stack_count
;
2069 void wx_clear_stack()
2071 wx_stack_top
= wx_spline_stack
;
2075 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2077 wx_stack_top
->x1
= x1
;
2078 wx_stack_top
->y1
= y1
;
2079 wx_stack_top
->x2
= x2
;
2080 wx_stack_top
->y2
= y2
;
2081 wx_stack_top
->x3
= x3
;
2082 wx_stack_top
->y3
= y3
;
2083 wx_stack_top
->x4
= x4
;
2084 wx_stack_top
->y4
= y4
;
2089 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2090 double *x3
, double *y3
, double *x4
, double *y4
)
2092 if (wx_stack_count
== 0)
2096 *x1
= wx_stack_top
->x1
;
2097 *y1
= wx_stack_top
->y1
;
2098 *x2
= wx_stack_top
->x2
;
2099 *y2
= wx_stack_top
->y2
;
2100 *x3
= wx_stack_top
->x3
;
2101 *y3
= wx_stack_top
->y3
;
2102 *x4
= wx_stack_top
->x4
;
2103 *y4
= wx_stack_top
->y4
;
2107 static bool wx_spline_add_point(double x
, double y
)
2109 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
2110 wx_spline_point_list
.Append( point
);
2114 static void wx_spline_draw_point_array(wxDCBase
*dc
)
2116 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2117 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
2120 wxPoint
*point
= node
->GetData();
2122 wx_spline_point_list
.Erase(node
);
2123 node
= wx_spline_point_list
.GetFirst();
2127 #if WXWIN_COMPATIBILITY_2_8
2128 void wxDCBase::DrawSpline(const wxList
*points
)
2131 wxObjectList::compatibility_iterator node
= points
->GetFirst();
2134 list
.Append( (wxPoint
*) node
->GetData() );
2135 node
= node
->GetNext();
2137 DoDrawSpline( &list
);
2139 #endif // WXWIN_COMPATIBILITY_2_8
2141 void wxDCBase::DoDrawSpline( const wxPointList
*points
)
2143 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2146 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2147 double x1
, y1
, x2
, y2
;
2149 wxPointList::compatibility_iterator node
= points
->GetFirst();
2154 p
= node
->GetData();
2159 node
= node
->GetNext();
2160 p
= node
->GetData();
2164 cx1
= (double)((x1
+ x2
) / 2);
2165 cy1
= (double)((y1
+ y2
) / 2);
2166 cx2
= (double)((cx1
+ x2
) / 2);
2167 cy2
= (double)((cy1
+ y2
) / 2);
2169 wx_spline_add_point(x1
, y1
);
2171 while ((node
= node
->GetNext())
2174 #endif // !wxUSE_STL
2177 p
= node
->GetData();
2182 cx4
= (double)(x1
+ x2
) / 2;
2183 cy4
= (double)(y1
+ y2
) / 2;
2184 cx3
= (double)(x1
+ cx4
) / 2;
2185 cy3
= (double)(y1
+ cy4
) / 2;
2187 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2191 cx2
= (double)(cx1
+ x2
) / 2;
2192 cy2
= (double)(cy1
+ y2
) / 2;
2195 wx_spline_add_point( cx1
, cy1
);
2196 wx_spline_add_point( x2
, y2
);
2198 wx_spline_draw_point_array( this );
2201 #endif // wxUSE_SPLINES
2203 // ----------------------------------------------------------------------------
2204 // Partial Text Extents
2205 // ----------------------------------------------------------------------------
2208 // Each element of the widths array will be the width of the string up to and
2209 // including the corresponding character in text. This is the generic
2210 // implementation, the port-specific classes should do this with native APIs
2211 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2212 // than calling GetTextExtent!!
2214 #define FWC_SIZE 256
2216 class FontWidthCache
2219 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
2220 ~FontWidthCache() { delete []m_widths
; }
2225 m_widths
= new int[FWC_SIZE
];
2227 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2235 static FontWidthCache s_fontWidthCache
;
2237 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2241 const size_t len
= text
.length();
2245 // reset the cache if font or horizontal scale have changed
2246 if ( !s_fontWidthCache
.m_widths
||
2247 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2248 (s_fontWidthCache
.m_font
!= GetFont()) )
2250 s_fontWidthCache
.Reset();
2251 s_fontWidthCache
.m_font
= GetFont();
2252 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2255 // Calculate the position of each character based on the widths of
2256 // the previous characters
2258 for ( size_t i
= 0; i
< len
; i
++ )
2260 const wxChar c
= text
[i
];
2261 unsigned int c_int
= (unsigned int)c
;
2263 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2265 w
= s_fontWidthCache
.m_widths
[c_int
];
2269 GetTextExtent(c
, &w
, &h
);
2270 if (c_int
< FWC_SIZE
)
2271 s_fontWidthCache
.m_widths
[c_int
] = w
;
2275 widths
[i
] = totalWidth
;
2282 // ----------------------------------------------------------------------------
2283 // enhanced text drawing
2284 // ----------------------------------------------------------------------------
2286 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2290 const wxFont
*font
) const
2292 wxCoord widthTextMax
= 0, widthLine
,
2293 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2296 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2298 if ( pc
== text
.end() || *pc
== _T('\n') )
2300 if ( curLine
.empty() )
2302 // we can't use GetTextExtent - it will return 0 for both width
2303 // and height and an empty line should count in height
2306 // assume that this line has the same height as the previous
2308 if ( !heightLineDefault
)
2309 heightLineDefault
= heightLine
;
2311 if ( !heightLineDefault
)
2313 // but we don't know it yet - choose something reasonable
2314 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2318 heightTextTotal
+= heightLineDefault
;
2322 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2324 if ( widthLine
> widthTextMax
)
2325 widthTextMax
= widthLine
;
2326 heightTextTotal
+= heightLine
;
2329 if ( pc
== text
.end() )
2347 *y
= heightTextTotal
;
2352 void wxDCBase::DrawLabel(const wxString
& text
,
2353 const wxBitmap
& bitmap
,
2357 wxRect
*rectBounding
)
2359 // find the text position
2360 wxCoord widthText
, heightText
, heightLine
;
2361 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2363 wxCoord width
, height
;
2366 width
= widthText
+ bitmap
.GetWidth();
2367 height
= bitmap
.GetHeight();
2372 height
= heightText
;
2376 if ( alignment
& wxALIGN_RIGHT
)
2378 x
= rect
.GetRight() - width
;
2380 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2382 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2384 else // alignment & wxALIGN_LEFT
2389 if ( alignment
& wxALIGN_BOTTOM
)
2391 y
= rect
.GetBottom() - height
;
2393 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2395 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2397 else // alignment & wxALIGN_TOP
2402 // draw the bitmap first
2408 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2410 wxCoord offset
= bitmap
.GetWidth() + 4;
2414 y
+= (height
- heightText
) / 2;
2417 // we will draw the underscore under the accel char later
2418 wxCoord startUnderscore
= 0,
2422 // split the string into lines and draw each of them separately
2424 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2426 if ( pc
== text
.end() || *pc
== _T('\n') )
2428 int xRealStart
= x
; // init it here to avoid compielr warnings
2430 if ( !curLine
.empty() )
2432 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2433 // wxALIGN_LEFT is 0
2434 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2437 GetTextExtent(curLine
, &widthLine
, NULL
);
2439 if ( alignment
& wxALIGN_RIGHT
)
2441 xRealStart
+= width
- widthLine
;
2443 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2445 xRealStart
+= (width
- widthLine
) / 2;
2448 //else: left aligned, nothing to do
2450 DrawText(curLine
, xRealStart
, y
);
2455 // do we have underscore in this line? we can check yUnderscore
2456 // because it is set below to just y + heightLine if we do
2457 if ( y
== yUnderscore
)
2459 // adjust the horz positions to account for the shift
2460 startUnderscore
+= xRealStart
;
2461 endUnderscore
+= xRealStart
;
2464 if ( pc
== text
.end() )
2469 else // not end of line
2471 if ( pc
- text
.begin() == indexAccel
)
2473 // remeber to draw underscore here
2474 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2476 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2478 yUnderscore
= y
+ heightLine
;
2487 // draw the underscore if found
2488 if ( startUnderscore
!= endUnderscore
)
2490 // it should be of the same colour as text
2491 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2495 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2498 // return bounding rect if requested
2501 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2504 CalcBoundingBox(x0
, y0
);
2505 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2509 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2510 const wxColour
& initialColour
,
2511 const wxColour
& destColour
,
2512 wxDirection nDirection
)
2515 wxPen oldPen
= m_pen
;
2516 wxBrush oldBrush
= m_brush
;
2518 wxUint8 nR1
= initialColour
.Red();
2519 wxUint8 nG1
= initialColour
.Green();
2520 wxUint8 nB1
= initialColour
.Blue();
2521 wxUint8 nR2
= destColour
.Red();
2522 wxUint8 nG2
= destColour
.Green();
2523 wxUint8 nB2
= destColour
.Blue();
2526 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2528 wxInt32 x
= rect
.GetWidth();
2529 wxInt32 w
= x
; // width of area to shade
2530 wxInt32 xDelta
= w
/256; // height of one shade bend
2538 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2540 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2543 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2545 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2548 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2550 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2552 wxColour
colour(nR
,nG
,nB
);
2553 SetPen(wxPen(colour
, 1, wxSOLID
));
2554 SetBrush(wxBrush(colour
));
2555 if(nDirection
== wxEAST
)
2556 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
2557 xDelta
, rect
.GetHeight());
2558 else //nDirection == wxWEST
2559 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2560 xDelta
, rect
.GetHeight());
2563 else // nDirection == wxNORTH || nDirection == wxSOUTH
2565 wxInt32 y
= rect
.GetHeight();
2566 wxInt32 w
= y
; // height of area to shade
2567 wxInt32 yDelta
= w
/255; // height of one shade bend
2575 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2577 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2580 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2582 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2585 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2587 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2589 wxColour
colour(nR
,nG
,nB
);
2590 SetPen(wxPen(colour
, 1, wxSOLID
));
2591 SetBrush(wxBrush(colour
));
2592 if(nDirection
== wxNORTH
)
2593 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2594 rect
.GetWidth(), yDelta
);
2595 else //nDirection == wxSOUTH
2596 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
2597 rect
.GetWidth(), yDelta
);
2605 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2606 const wxColour
& initialColour
,
2607 const wxColour
& destColour
,
2608 const wxPoint
& circleCenter
)
2610 //save the old pen color
2611 wxColour oldPenColour
= m_pen
.GetColour();
2613 wxUint8 nR1
= destColour
.Red();
2614 wxUint8 nG1
= destColour
.Green();
2615 wxUint8 nB1
= destColour
.Blue();
2616 wxUint8 nR2
= initialColour
.Red();
2617 wxUint8 nG2
= initialColour
.Green();
2618 wxUint8 nB2
= initialColour
.Blue();
2623 wxInt32 cx
= rect
.GetWidth() / 2;
2624 wxInt32 cy
= rect
.GetHeight() / 2;
2632 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2633 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2635 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2637 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2639 //get color difference
2640 wxInt32 nGradient
= ((nRadius
-
2642 pow((double)(x
- cx
- nCircleOffX
), 2) +
2643 pow((double)(y
- cy
- nCircleOffY
), 2)
2644 )) * 100) / nRadius
;
2646 //normalize Gradient
2651 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2652 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2653 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2656 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2657 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2660 //return old pen color
2661 m_pen
.SetColour(oldPenColour
);
2665 Notes for wxWidgets DrawEllipticArcRot(...)
2667 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2668 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2671 All methods are generic, so they can be implemented in wxDCBase.
2672 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2673 methods like (WinCE) wxDC::DoDrawArc(...).
2675 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2676 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2677 parts) or every column (in steep parts) only one pixel is calculated.
2678 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2679 starting angle is not equal to the ending angle. The calculation of the
2680 pixels is done using simple arithmetic only and should perform not too
2681 bad even on devices without floating point processor. I didn't test this yet.
2683 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2684 For instance: an ellipse rotated 180 degrees is drawn
2685 slightly different from the original.
2687 The points are then moved to an array and used to draw a polyline and/or polygon
2688 (with center added, the pie).
2689 The result looks quite similar to the native ellipse, only e few pixels differ.
2691 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2692 slower as DrawEllipse(...), which calls the native API.
2693 An rotated ellipse outside the clipping region takes nearly the same time,
2694 while an native ellipse outside takes nearly no time to draw.
2696 If you draw an arc with this new method, you will see the starting and ending angles
2697 are calculated properly.
2698 If you use DrawEllipticArc(...), you will see they are only correct for circles
2699 and not properly calculated for ellipses.
2702 p.lenhard@t-online.de
2706 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2707 wxCoord w
, wxCoord h
,
2708 double sa
, double ea
, double angle
)
2712 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2713 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2715 // Add center (for polygon/pie)
2716 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
2718 // copy list into array and delete list elements
2719 int n
= list
.GetCount();
2720 wxPoint
*points
= new wxPoint
[n
];
2722 wxPointList::compatibility_iterator node
;
2723 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2725 wxPoint
*point
= node
->GetData();
2726 points
[i
].x
= point
->x
;
2727 points
[i
].y
= point
->y
;
2731 // first draw the pie without pen, if necessary
2732 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2734 wxPen
tempPen( GetPen() );
2735 SetPen( *wxTRANSPARENT_PEN
);
2736 DoDrawPolygon( n
, points
, 0, 0 );
2740 // then draw the arc without brush, if necessary
2741 if( GetPen() != *wxTRANSPARENT_PEN
)
2744 DoDrawLines( n
-1, points
, 0, 0 );
2749 } // DrawEllipticArcRot
2751 void wxDCBase::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
2756 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2757 double dCosA
= cos(angle
*2.0*pi
/360.0);
2758 wxPointList::compatibility_iterator node
;
2759 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2761 wxPoint
* point
= node
->GetData();
2763 // transform coordinates, if necessary
2764 if( center
.x
) point
->x
-= center
.x
;
2765 if( center
.y
) point
->y
-= center
.y
;
2767 // calculate rotation, rounding simply by implicit cast to integer
2768 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2769 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2772 // back transform coordinates, if necessary
2773 if( center
.x
) point
->x
+= center
.x
;
2774 if( center
.y
) point
->y
+= center
.y
;
2779 void wxDCBase::CalculateEllipticPoints( wxPointList
* points
,
2780 wxCoord xStart
, wxCoord yStart
,
2781 wxCoord w
, wxCoord h
,
2782 double sa
, double ea
)
2793 bool bUseAngles
= false;
2799 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2801 if( 2*a
== w
) decrX
= 1;
2803 if( 2*b
== h
) decrY
= 1;
2805 wxCoord xCenter
= xStart
+ a
;
2806 wxCoord yCenter
= yStart
+ b
;
2807 // calculate data for start and end, if necessary
2811 // normalisation of angles
2812 while( sa
<0 ) sa
+= 360;
2813 while( ea
<0 ) ea
+= 360;
2814 while( sa
>=360 ) sa
-= 360;
2815 while( ea
>=360 ) ea
-= 360;
2816 // calculate quadrant numbers
2817 if( sa
> 270 ) sq
= 3;
2818 else if( sa
> 180 ) sq
= 2;
2819 else if( sa
> 90 ) sq
= 1;
2820 if( ea
> 270 ) eq
= 3;
2821 else if( ea
> 180 ) eq
= 2;
2822 else if( ea
> 90 ) eq
= 1;
2823 sar
= sa
* pi
/ 180.0;
2824 ear
= ea
* pi
/ 180.0;
2825 // correct angle circle -> ellipse
2826 sar
= atan( -a
/(double)b
* tan( sar
) );
2827 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2828 ear
= atan( -a
/(double)b
* tan( ear
) );
2829 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2830 // coordinates of points
2831 xsa
= xCenter
+ a
* cos( sar
);
2832 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2833 ysa
= yCenter
+ b
* sin( sar
);
2834 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2835 xea
= xCenter
+ a
* cos( ear
);
2836 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2837 yea
= yCenter
+ b
* sin( ear
);
2838 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2840 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2842 double c2
= 2.0 / w
;
2851 // Lists for quadrant 1 to 4
2852 wxPointList pointsarray
[4];
2853 // Calculate points for first quadrant and set in all quadrants
2854 for( x
= 0; x
<= a
; ++x
)
2859 bool bNewPoint
= false;
2860 while( y2
> c1
- c2
* x2
&& y
> 0 )
2866 // old y now to big: set point with old y, old x
2867 if( bNewPoint
&& x
>1)
2870 // remove points on the same line
2871 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2872 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2873 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2874 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2876 } // calculate point
2878 // Starting and/or ending points for the quadrants, first quadrant gets both.
2879 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2880 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
2881 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
2882 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2883 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2885 // copy quadrants in original list
2888 // Copy the right part of the points in the lists
2889 // and delete the wxPoints, because they do not leave this method.
2890 points
->Append( new wxPoint( xsa
, ysa
) );
2892 bool bStarted
= false;
2893 bool bReady
= false;
2894 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2897 wxPointList::compatibility_iterator node
;
2898 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2900 // once: go to starting point in start quadrant
2903 node
->GetData()->x
< xsa
+1 && q
<= 1
2905 node
->GetData()->x
> xsa
-1 && q
>= 2
2912 // copy point, if not at ending point
2915 if( q
!= eq
|| bForceTurn
2917 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2919 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2923 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
2924 points
->Append( pPoint
);
2926 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
2936 } // while not bReady
2937 points
->Append( new wxPoint( xea
, yea
) );
2940 for( q
= 0; q
< 4; ++q
)
2942 wxPointList::compatibility_iterator node
;
2943 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2945 wxPoint
*p
= node
->GetData();
2952 wxPointList::compatibility_iterator node
;
2953 // copy whole ellipse, wxPoints will be deleted outside
2954 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2956 wxPoint
*p
= node
->GetData();
2957 points
->Append( p
);
2959 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2961 wxPoint
*p
= node
->GetData();
2962 points
->Append( p
);
2964 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2966 wxPoint
*p
= node
->GetData();
2967 points
->Append( p
);
2969 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2971 wxPoint
*p
= node
->GetData();
2972 points
->Append( p
);
2975 } // CalculateEllipticPoints
2977 #endif // __WXWINCE__
2979 #endif // wxUSE_NEW_DC