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 //-----------------------------------------------------------------------------
339 //-----------------------------------------------------------------------------
341 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
343 wxWindowDC::wxWindowDC()
345 wxDCFactory
*factory
= wxDCFactory::GetFactory();
346 m_pimpl
= factory
->CreateWindowDC( this );
349 wxWindowDC::wxWindowDC( wxWindow
*win
)
351 wxDCFactory
*factory
= wxDCFactory::GetFactory();
352 m_pimpl
= factory
->CreateWindowDC( this, win
);
355 //-----------------------------------------------------------------------------
357 //-----------------------------------------------------------------------------
359 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxDC
)
361 wxClientDC::wxClientDC()
363 wxDCFactory
*factory
= wxDCFactory::GetFactory();
364 m_pimpl
= factory
->CreateClientDC( this );
367 wxClientDC::wxClientDC( wxWindow
*win
)
369 wxDCFactory
*factory
= wxDCFactory::GetFactory();
370 m_pimpl
= factory
->CreateClientDC( this, win
);
373 //-----------------------------------------------------------------------------
375 //-----------------------------------------------------------------------------
377 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
379 wxMemoryDC::wxMemoryDC()
381 wxDCFactory
*factory
= wxDCFactory::GetFactory();
382 m_pimpl
= factory
->CreateMemoryDC( this );
385 wxMemoryDC::wxMemoryDC( wxBitmap
& bitmap
)
387 wxDCFactory
*factory
= wxDCFactory::GetFactory();
388 m_pimpl
= factory
->CreateMemoryDC( this, bitmap
);
391 wxMemoryDC::wxMemoryDC( wxDC
*dc
)
393 wxDCFactory
*factory
= wxDCFactory::GetFactory();
394 m_pimpl
= factory
->CreateMemoryDC( this, dc
);
397 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
399 // make sure that the given wxBitmap is not sharing its data with other
400 // wxBitmap instances as its contents will be modified by any drawing
401 // operation done on this DC
406 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
411 mem_pimpl
->DoSelect(bmp
);
414 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
417 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
421 mem_pimpl
->DoSelect(bmp
);
424 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
427 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
432 return mem_pimpl
->DoGetSelectedBitmap();
437 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
440 wxGTKMemoryImplDC
*mem_pimpl
= wxDynamicCast( m_pimpl
, wxGTKMemoryImplDC
);
446 return mem_pimpl
->DoGetSelectedBitmap();
452 //-----------------------------------------------------------------------------
454 //-----------------------------------------------------------------------------
456 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxDC
)
458 wxPaintDC::wxPaintDC()
460 wxDCFactory
*factory
= wxDCFactory::GetFactory();
461 m_pimpl
= factory
->CreatePaintDC( this );
464 wxPaintDC::wxPaintDC( wxWindow
*win
)
466 wxDCFactory
*factory
= wxDCFactory::GetFactory();
467 m_pimpl
= factory
->CreatePaintDC( this, win
);
470 //-----------------------------------------------------------------------------
472 //-----------------------------------------------------------------------------
474 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
476 wxScreenDC::wxScreenDC()
478 wxDCFactory
*factory
= wxDCFactory::GetFactory();
479 m_pimpl
= factory
->CreateScreenDC( this );
482 //-----------------------------------------------------------------------------
484 //-----------------------------------------------------------------------------
486 IMPLEMENT_ABSTRACT_CLASS(wxImplDC
, wxObject
)
488 wxImplDC::wxImplDC( wxDC
*owner
)
489 : m_colour(wxColourDisplay())
493 , m_isBBoxValid(false)
494 , m_logicalOriginX(0), m_logicalOriginY(0)
495 , m_deviceOriginX(0), m_deviceOriginY(0)
496 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
497 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
498 , m_userScaleX(1.0), m_userScaleY(1.0)
499 , m_scaleX(1.0), m_scaleY(1.0)
500 , m_signX(1), m_signY(1)
501 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
502 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
503 , m_logicalFunction(wxCOPY
)
504 , m_backgroundMode(wxTRANSPARENT
)
505 , m_mappingMode(wxMM_TEXT
)
508 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
509 , m_textForegroundColour(*wxBLACK
)
510 , m_textBackgroundColour(*wxWHITE
)
514 , m_hasCustomPalette(false)
515 #endif // wxUSE_PALETTE
519 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
520 (double)wxGetDisplaySizeMM().GetWidth();
521 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
522 (double)wxGetDisplaySizeMM().GetHeight();
528 wxImplDC::~wxImplDC()
532 // ----------------------------------------------------------------------------
533 // coordinate conversions and transforms
534 // ----------------------------------------------------------------------------
536 wxCoord
wxImplDC::DeviceToLogicalX(wxCoord x
) const
538 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
541 wxCoord
wxImplDC::DeviceToLogicalY(wxCoord y
) const
543 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
546 wxCoord
wxImplDC::DeviceToLogicalXRel(wxCoord x
) const
548 return wxRound((double)(x
) / m_scaleX
);
551 wxCoord
wxImplDC::DeviceToLogicalYRel(wxCoord y
) const
553 return wxRound((double)(y
) / m_scaleY
);
556 wxCoord
wxImplDC::LogicalToDeviceX(wxCoord x
) const
558 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
561 wxCoord
wxImplDC::LogicalToDeviceY(wxCoord y
) const
563 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ m_deviceLocalOriginY
;
566 wxCoord
wxImplDC::LogicalToDeviceXRel(wxCoord x
) const
568 return wxRound((double)(x
) * m_scaleX
);
571 wxCoord
wxImplDC::LogicalToDeviceYRel(wxCoord y
) const
573 return wxRound((double)(y
) * m_scaleY
);
576 void wxImplDC::ComputeScaleAndOrigin()
578 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
579 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
582 void wxImplDC::SetMapMode( int mode
)
587 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
590 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
593 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
596 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
600 SetLogicalScale( 1.0, 1.0 );
603 m_mappingMode
= mode
;
606 void wxImplDC::SetUserScale( double x
, double y
)
608 // allow negative ? -> no
611 ComputeScaleAndOrigin();
614 void wxImplDC::SetLogicalScale( double x
, double y
)
619 ComputeScaleAndOrigin();
622 void wxImplDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
624 m_logicalOriginX
= x
* m_signX
;
625 m_logicalOriginY
= y
* m_signY
;
626 ComputeScaleAndOrigin();
629 void wxImplDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
633 ComputeScaleAndOrigin();
636 void wxImplDC::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
638 m_deviceLocalOriginX
= x
;
639 m_deviceLocalOriginY
= y
;
640 ComputeScaleAndOrigin();
643 void wxImplDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
645 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
646 // wxWidgets 2.9: no longer override it
647 m_signX
= (xLeftRight
? 1 : -1);
648 m_signY
= (yBottomUp
? -1 : 1);
649 ComputeScaleAndOrigin();
653 // Each element of the widths array will be the width of the string up to and
654 // including the corresponding character in text. This is the generic
655 // implementation, the port-specific classes should do this with native APIs
656 // if available and if faster. Note: pango_layout_index_to_pos is much slower
657 // than calling GetTextExtent!!
664 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
665 ~FontWidthCache() { delete []m_widths
; }
670 m_widths
= new int[FWC_SIZE
];
672 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
680 static FontWidthCache s_fontWidthCache
;
682 bool wxImplDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
686 const size_t len
= text
.length();
690 // reset the cache if font or horizontal scale have changed
691 if ( !s_fontWidthCache
.m_widths
||
692 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
693 (s_fontWidthCache
.m_font
!= GetFont()) )
695 s_fontWidthCache
.Reset();
696 s_fontWidthCache
.m_font
= GetFont();
697 s_fontWidthCache
.m_scaleX
= m_scaleX
;
700 // Calculate the position of each character based on the widths of
701 // the previous characters
703 for ( size_t i
= 0; i
< len
; i
++ )
705 const wxChar c
= text
[i
];
706 unsigned int c_int
= (unsigned int)c
;
708 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
710 w
= s_fontWidthCache
.m_widths
[c_int
];
714 DoGetTextExtent(c
, &w
, &h
);
715 if (c_int
< FWC_SIZE
)
716 s_fontWidthCache
.m_widths
[c_int
] = w
;
720 widths
[i
] = totalWidth
;
726 void wxImplDC::GetMultiLineTextExtent(const wxString
& text
,
730 const wxFont
*font
) const
732 wxCoord widthTextMax
= 0, widthLine
,
733 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
736 for ( const wxChar
*pc
= text
; ; pc
++ )
738 if ( *pc
== _T('\n') || *pc
== _T('\0') )
740 if ( curLine
.empty() )
742 // we can't use GetTextExtent - it will return 0 for both width
743 // and height and an empty line should count in height
746 // assume that this line has the same height as the previous
748 if ( !heightLineDefault
)
749 heightLineDefault
= heightLine
;
751 if ( !heightLineDefault
)
753 // but we don't know it yet - choose something reasonable
754 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
758 heightTextTotal
+= heightLineDefault
;
762 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
764 if ( widthLine
> widthTextMax
)
765 widthTextMax
= widthLine
;
766 heightTextTotal
+= heightLine
;
769 if ( *pc
== _T('\n') )
788 *y
= heightTextTotal
;
793 void wxImplDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
794 wxCoord width
, wxCoord height
)
796 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
798 wxCoord x2
= x1
+ width
,
801 // the pen width is calibrated to give 3 for width == height == 10
802 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
804 // we're drawing a scaled version of wx/generic/tick.xpm here
805 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
806 y3
= y1
+ height
/ 2; // y of the left tick branch
807 DoDrawLine(x1
, y3
, x3
, y2
);
808 DoDrawLine(x3
, y2
, x2
, y1
);
810 CalcBoundingBox(x1
, y1
);
811 CalcBoundingBox(x2
, y2
);
815 wxImplDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
816 wxCoord dstWidth
, wxCoord dstHeight
,
818 wxCoord xsrc
, wxCoord ysrc
,
819 wxCoord srcWidth
, wxCoord srcHeight
,
825 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
826 _T("invalid blit size") );
828 // emulate the stretching by modifying the DC scale
829 double xscale
= (double)srcWidth
/dstWidth
,
830 yscale
= (double)srcHeight
/dstHeight
;
832 double xscaleOld
, yscaleOld
;
833 GetUserScale(&xscaleOld
, &yscaleOld
);
834 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
836 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
837 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
839 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
841 SetUserScale(xscaleOld
, yscaleOld
);
847 void wxImplDC::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
849 int n
= list
->GetCount();
850 wxPoint
*points
= new wxPoint
[n
];
853 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
855 wxPoint
*point
= (wxPoint
*)node
->GetData();
856 points
[i
].x
= point
->x
;
857 points
[i
].y
= point
->y
;
860 DoDrawLines(n
, points
, xoffset
, yoffset
);
865 void wxImplDC::DrawPolygon(const wxList
*list
,
866 wxCoord xoffset
, wxCoord yoffset
,
869 int n
= list
->GetCount();
870 wxPoint
*points
= new wxPoint
[n
];
873 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
875 wxPoint
*point
= (wxPoint
*)node
->GetData();
876 points
[i
].x
= point
->x
;
877 points
[i
].y
= point
->y
;
880 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
887 wxImplDC::DoDrawPolyPolygon(int n
,
890 wxCoord xoffset
, wxCoord yoffset
,
895 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
903 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
908 pts
= new wxPoint
[j
+n
-1];
909 for (i
= 0; i
< j
; i
++)
911 for (i
= 2; i
<= n
; i
++)
913 lastOfs
-= count
[n
-i
];
914 pts
[j
++] = pts
[lastOfs
];
918 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
919 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
921 for (i
= j
= 0; i
< n
; i
++)
923 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
931 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
932 void wxImplDC::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
936 wxPoint
*point1
= new wxPoint
;
937 point1
->x
= x1
; point1
->y
= y1
;
938 point_list
.Append((wxObject
*)point1
);
940 wxPoint
*point2
= new wxPoint
;
941 point2
->x
= x2
; point2
->y
= y2
;
942 point_list
.Append((wxObject
*)point2
);
944 wxPoint
*point3
= new wxPoint
;
945 point3
->x
= x3
; point3
->y
= y3
;
946 point_list
.Append((wxObject
*)point3
);
948 DoDrawSpline(&point_list
);
950 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
952 wxPoint
*p
= (wxPoint
*)node
->GetData();
957 void wxImplDC::DoDrawSpline(int n
, wxPoint points
[])
960 for (int i
=0; i
< n
; i
++)
962 list
.Append((wxObject
*)&points
[i
]);
968 // ----------------------------------- spline code ----------------------------------------
970 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
971 double a3
, double b3
, double a4
, double b4
);
972 void wx_clear_stack();
973 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
974 double *y3
, double *x4
, double *y4
);
975 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
976 double x4
, double y4
);
977 static bool wx_spline_add_point(double x
, double y
);
978 static void wx_spline_draw_point_array(wxDC
*dc
);
980 wxList wx_spline_point_list
;
982 #define half(z1, z2) ((z1+z2)/2.0)
985 /* iterative version */
987 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
990 register double xmid
, ymid
;
991 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
994 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
996 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
997 xmid
= (double)half(x2
, x3
);
998 ymid
= (double)half(y2
, y3
);
999 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1000 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1001 wx_spline_add_point( x1
, y1
);
1002 wx_spline_add_point( xmid
, ymid
);
1004 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1005 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1006 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1007 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1012 /* utilities used by spline drawing routines */
1014 typedef struct wx_spline_stack_struct
{
1015 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1018 #define SPLINE_STACK_DEPTH 20
1019 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1020 static Stack
*wx_stack_top
;
1021 static int wx_stack_count
;
1023 void wx_clear_stack()
1025 wx_stack_top
= wx_spline_stack
;
1029 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1031 wx_stack_top
->x1
= x1
;
1032 wx_stack_top
->y1
= y1
;
1033 wx_stack_top
->x2
= x2
;
1034 wx_stack_top
->y2
= y2
;
1035 wx_stack_top
->x3
= x3
;
1036 wx_stack_top
->y3
= y3
;
1037 wx_stack_top
->x4
= x4
;
1038 wx_stack_top
->y4
= y4
;
1043 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1044 double *x3
, double *y3
, double *x4
, double *y4
)
1046 if (wx_stack_count
== 0)
1050 *x1
= wx_stack_top
->x1
;
1051 *y1
= wx_stack_top
->y1
;
1052 *x2
= wx_stack_top
->x2
;
1053 *y2
= wx_stack_top
->y2
;
1054 *x3
= wx_stack_top
->x3
;
1055 *y3
= wx_stack_top
->y3
;
1056 *x4
= wx_stack_top
->x4
;
1057 *y4
= wx_stack_top
->y4
;
1061 static bool wx_spline_add_point(double x
, double y
)
1063 wxPoint
*point
= new wxPoint
;
1066 wx_spline_point_list
.Append((wxObject
*)point
);
1070 static void wx_spline_draw_point_array(wxDC
*dc
)
1072 // dc->DrawLines(&wx_spline_point_list, 0, 0 ); wxList
1073 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
1076 wxPoint
*point
= (wxPoint
*)node
->GetData();
1078 wx_spline_point_list
.Erase(node
);
1079 node
= wx_spline_point_list
.GetFirst();
1083 void wxImplDC::DoDrawSpline( wxList
*points
)
1085 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
1088 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1089 double x1
, y1
, x2
, y2
;
1091 wxList::compatibility_iterator node
= points
->GetFirst();
1096 p
= (wxPoint
*)node
->GetData();
1101 node
= node
->GetNext();
1102 p
= (wxPoint
*)node
->GetData();
1106 cx1
= (double)((x1
+ x2
) / 2);
1107 cy1
= (double)((y1
+ y2
) / 2);
1108 cx2
= (double)((cx1
+ x2
) / 2);
1109 cy2
= (double)((cy1
+ y2
) / 2);
1111 wx_spline_add_point(x1
, y1
);
1113 while ((node
= node
->GetNext())
1116 #endif // !wxUSE_STL
1119 p
= (wxPoint
*)node
->GetData();
1124 cx4
= (double)(x1
+ x2
) / 2;
1125 cy4
= (double)(y1
+ y2
) / 2;
1126 cx3
= (double)(x1
+ cx4
) / 2;
1127 cy3
= (double)(y1
+ cy4
) / 2;
1129 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1133 cx2
= (double)(cx1
+ x2
) / 2;
1134 cy2
= (double)(cy1
+ y2
) / 2;
1137 wx_spline_add_point( cx1
, cy1
);
1138 wx_spline_add_point( x2
, y2
);
1140 wx_spline_draw_point_array( m_owner
);
1143 #endif // wxUSE_SPLINES
1147 void wxImplDC::DoGradientFillLinear(const wxRect
& rect
,
1148 const wxColour
& initialColour
,
1149 const wxColour
& destColour
,
1150 wxDirection nDirection
)
1153 wxPen oldPen
= m_pen
;
1154 wxBrush oldBrush
= m_brush
;
1156 wxUint8 nR1
= initialColour
.Red();
1157 wxUint8 nG1
= initialColour
.Green();
1158 wxUint8 nB1
= initialColour
.Blue();
1159 wxUint8 nR2
= destColour
.Red();
1160 wxUint8 nG2
= destColour
.Green();
1161 wxUint8 nB2
= destColour
.Blue();
1164 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
1166 wxInt32 x
= rect
.GetWidth();
1167 wxInt32 w
= x
; // width of area to shade
1168 wxInt32 xDelta
= w
/256; // height of one shade bend
1176 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1178 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1181 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1183 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1186 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1188 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
1190 wxColour
colour(nR
,nG
,nB
);
1191 SetPen(wxPen(colour
, 1, wxSOLID
));
1192 SetBrush(wxBrush(colour
));
1193 if(nDirection
== wxEAST
)
1194 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1195 xDelta
, rect
.GetHeight());
1196 else //nDirection == wxWEST
1197 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1198 xDelta
, rect
.GetHeight());
1201 else // nDirection == wxNORTH || nDirection == wxSOUTH
1203 wxInt32 y
= rect
.GetHeight();
1204 wxInt32 w
= y
; // height of area to shade
1205 wxInt32 yDelta
= w
/255; // height of one shade bend
1213 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1215 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1218 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1220 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1223 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1225 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1227 wxColour
colour(nR
,nG
,nB
);
1228 SetPen(wxPen(colour
, 1, wxSOLID
));
1229 SetBrush(wxBrush(colour
));
1230 if(nDirection
== wxNORTH
)
1231 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1232 rect
.GetWidth(), yDelta
);
1233 else //nDirection == wxSOUTH
1234 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1235 rect
.GetWidth(), yDelta
);
1243 void wxImplDC::DoGradientFillConcentric(const wxRect
& rect
,
1244 const wxColour
& initialColour
,
1245 const wxColour
& destColour
,
1246 const wxPoint
& circleCenter
)
1248 //save the old pen color
1249 wxColour oldPenColour
= m_pen
.GetColour();
1251 wxUint8 nR1
= destColour
.Red();
1252 wxUint8 nG1
= destColour
.Green();
1253 wxUint8 nB1
= destColour
.Blue();
1254 wxUint8 nR2
= initialColour
.Red();
1255 wxUint8 nG2
= initialColour
.Green();
1256 wxUint8 nB2
= initialColour
.Blue();
1261 wxInt32 cx
= rect
.GetWidth() / 2;
1262 wxInt32 cy
= rect
.GetHeight() / 2;
1270 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1271 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1273 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1275 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1277 //get color difference
1278 wxInt32 nGradient
= ((nRadius
-
1280 pow((double)(x
- cx
- nCircleOffX
), 2) +
1281 pow((double)(y
- cy
- nCircleOffY
), 2)
1282 )) * 100) / nRadius
;
1284 //normalize Gradient
1289 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1290 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1291 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1294 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1295 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1298 //return old pen color
1299 m_pen
.SetColour(oldPenColour
);
1302 //-----------------------------------------------------------------------------
1304 //-----------------------------------------------------------------------------
1306 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1308 void wxDC::DrawLabel(const wxString
& text
,
1309 const wxBitmap
& bitmap
,
1313 wxRect
*rectBounding
)
1315 // find the text position
1316 wxCoord widthText
, heightText
, heightLine
;
1317 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1319 wxCoord width
, height
;
1322 width
= widthText
+ bitmap
.GetWidth();
1323 height
= bitmap
.GetHeight();
1328 height
= heightText
;
1332 if ( alignment
& wxALIGN_RIGHT
)
1334 x
= rect
.GetRight() - width
;
1336 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1338 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1340 else // alignment & wxALIGN_LEFT
1345 if ( alignment
& wxALIGN_BOTTOM
)
1347 y
= rect
.GetBottom() - height
;
1349 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1351 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1353 else // alignment & wxALIGN_TOP
1358 // draw the bitmap first
1364 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1366 wxCoord offset
= bitmap
.GetWidth() + 4;
1370 y
+= (height
- heightText
) / 2;
1373 // we will draw the underscore under the accel char later
1374 wxCoord startUnderscore
= 0,
1378 // split the string into lines and draw each of them separately
1380 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1382 if ( *pc
== _T('\n') || pc
== text
.end() )
1384 int xRealStart
= x
; // init it here to avoid compielr warnings
1386 if ( !curLine
.empty() )
1388 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1389 // wxALIGN_LEFT is 0
1390 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1393 GetTextExtent(curLine
, &widthLine
, NULL
);
1395 if ( alignment
& wxALIGN_RIGHT
)
1397 xRealStart
+= width
- widthLine
;
1399 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1401 xRealStart
+= (width
- widthLine
) / 2;
1404 //else: left aligned, nothing to do
1406 DrawText(curLine
, xRealStart
, y
);
1411 // do we have underscore in this line? we can check yUnderscore
1412 // because it is set below to just y + heightLine if we do
1413 if ( y
== yUnderscore
)
1415 // adjust the horz positions to account for the shift
1416 startUnderscore
+= xRealStart
;
1417 endUnderscore
+= xRealStart
;
1420 if ( pc
== text
.end() )
1425 else // not end of line
1427 if ( pc
- text
.begin() == indexAccel
)
1429 // remeber to draw underscore here
1430 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1432 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1434 yUnderscore
= y
+ heightLine
;
1443 // draw the underscore if found
1444 if ( startUnderscore
!= endUnderscore
)
1446 // it should be of the same colour as text
1447 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1451 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1454 // return bounding rect if requested
1457 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1460 CalcBoundingBox(x0
, y0
);
1461 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1464 #if WXWIN_COMPATIBILITY_2_8
1465 // for compatibility with the old code when wxCoord was long everywhere
1466 void wxDC::GetTextExtent(const wxString
& string
,
1469 long *externalLeading
,
1470 const wxFont
*theFont
) const
1472 wxCoord x2
, y2
, descent2
, externalLeading2
;
1473 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1474 &descent2
, &externalLeading2
,
1481 *descent
= descent2
;
1482 if ( externalLeading
)
1483 *externalLeading
= externalLeading2
;
1486 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1489 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1496 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1499 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1506 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1508 wxCoord xx
,yy
,ww
,hh
;
1509 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1516 #endif // WXWIN_COMPATIBILITY_2_8
1519 #else // wxUSE_NEW_DC
1522 // bool wxDCBase::sm_cacheing = false;
1524 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
1526 // ============================================================================
1528 // ============================================================================
1530 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
1531 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
1533 wxDCBase::wxDCBase()
1534 : m_colour(wxColourDisplay())
1537 , m_isInteractive(0)
1538 , m_isBBoxValid(false)
1539 , m_logicalOriginX(0), m_logicalOriginY(0)
1540 , m_deviceOriginX(0), m_deviceOriginY(0)
1541 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1542 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1543 , m_userScaleX(1.0), m_userScaleY(1.0)
1544 , m_scaleX(1.0), m_scaleY(1.0)
1545 , m_signX(1), m_signY(1)
1546 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1547 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1548 , m_logicalFunction(wxCOPY
)
1549 , m_backgroundMode(wxTRANSPARENT
)
1550 , m_mappingMode(wxMM_TEXT
)
1553 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
1554 , m_textForegroundColour(*wxBLACK
)
1555 , m_textBackgroundColour(*wxWHITE
)
1559 , m_hasCustomPalette(false)
1560 #endif // wxUSE_PALETTE
1562 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
1563 (double)wxGetDisplaySizeMM().GetWidth();
1564 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
1565 (double)wxGetDisplaySizeMM().GetHeight();
1571 wxDCBase::~wxDCBase()
1575 #if WXWIN_COMPATIBILITY_2_6
1576 void wxDCBase::BeginDrawing()
1580 void wxDCBase::EndDrawing()
1583 #endif // WXWIN_COMPATIBILITY_2_6
1585 #if WXWIN_COMPATIBILITY_2_8
1586 // for compatibility with the old code when wxCoord was long everywhere
1587 void wxDCBase::GetTextExtent(const wxString
& string
,
1590 long *externalLeading
,
1591 const wxFont
*theFont
) const
1593 wxCoord x2
, y2
, descent2
, externalLeading2
;
1594 DoGetTextExtent(string
, &x2
, &y2
,
1595 &descent2
, &externalLeading2
,
1602 *descent
= descent2
;
1603 if ( externalLeading
)
1604 *externalLeading
= externalLeading2
;
1607 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
1610 DoGetLogicalOrigin(&x2
, &y2
);
1617 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
1620 DoGetDeviceOrigin(&x2
, &y2
);
1627 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1629 wxCoord xx
,yy
,ww
,hh
;
1630 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1636 #endif // WXWIN_COMPATIBILITY_2_8
1640 // ----------------------------------------------------------------------------
1641 // coordinate conversions and transforms
1642 // ----------------------------------------------------------------------------
1644 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1646 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
1649 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1651 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
1654 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1656 return wxRound((double)(x
) / m_scaleX
);
1659 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1661 return wxRound((double)(y
) / m_scaleY
);
1664 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1666 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
1669 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1671 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
1674 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1676 return wxRound((double)(x
) * m_scaleX
);
1679 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1681 return wxRound((double)(y
) * m_scaleY
);
1684 void wxDCBase::ComputeScaleAndOrigin()
1686 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
1687 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
1690 void wxDCBase::SetMapMode( int mode
)
1695 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
1698 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
1701 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
1704 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
1708 SetLogicalScale( 1.0, 1.0 );
1711 m_mappingMode
= mode
;
1714 void wxDCBase::SetUserScale( double x
, double y
)
1716 // allow negative ? -> no
1719 ComputeScaleAndOrigin();
1722 void wxDCBase::SetLogicalScale( double x
, double y
)
1725 m_logicalScaleX
= x
;
1726 m_logicalScaleY
= y
;
1727 ComputeScaleAndOrigin();
1730 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
1732 m_logicalOriginX
= x
* m_signX
;
1733 m_logicalOriginY
= y
* m_signY
;
1734 ComputeScaleAndOrigin();
1737 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
1739 m_deviceOriginX
= x
;
1740 m_deviceOriginY
= y
;
1741 ComputeScaleAndOrigin();
1744 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
1746 m_deviceLocalOriginX
= x
;
1747 m_deviceLocalOriginY
= y
;
1748 ComputeScaleAndOrigin();
1751 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
1753 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1754 // wxWidgets 2.9: no longer override it
1755 m_signX
= (xLeftRight
? 1 : -1);
1756 m_signY
= (yBottomUp
? -1 : 1);
1757 ComputeScaleAndOrigin();
1760 // ----------------------------------------------------------------------------
1762 // ----------------------------------------------------------------------------
1764 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
1765 wxCoord width
, wxCoord height
)
1767 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1769 wxCoord x2
= x1
+ width
,
1772 // the pen width is calibrated to give 3 for width == height == 10
1773 wxDCPenChanger
pen((wxDC
&)*this,
1774 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
1776 // we're drawing a scaled version of wx/generic/tick.xpm here
1777 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
1778 y3
= y1
+ height
/ 2; // y of the left tick branch
1779 DoDrawLine(x1
, y3
, x3
, y2
);
1780 DoDrawLine(x3
, y2
, x2
, y1
);
1782 CalcBoundingBox(x1
, y1
);
1783 CalcBoundingBox(x2
, y2
);
1786 // ----------------------------------------------------------------------------
1787 // stubs for functions not implemented in all ports
1788 // ----------------------------------------------------------------------------
1791 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1792 wxCoord dstWidth
, wxCoord dstHeight
,
1794 wxCoord xsrc
, wxCoord ysrc
,
1795 wxCoord srcWidth
, wxCoord srcHeight
,
1801 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
1802 _T("invalid blit size") );
1804 // emulate the stretching by modifying the DC scale
1805 double xscale
= (double)srcWidth
/dstWidth
,
1806 yscale
= (double)srcHeight
/dstHeight
;
1808 double xscaleOld
, yscaleOld
;
1809 GetUserScale(&xscaleOld
, &yscaleOld
);
1810 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
1812 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
1813 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
1815 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
1817 SetUserScale(xscaleOld
, yscaleOld
);
1822 // ----------------------------------------------------------------------------
1824 // ----------------------------------------------------------------------------
1826 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
1828 int n
= list
->GetCount();
1829 wxPoint
*points
= new wxPoint
[n
];
1832 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1834 wxPoint
*point
= (wxPoint
*)node
->GetData();
1835 points
[i
].x
= point
->x
;
1836 points
[i
].y
= point
->y
;
1839 DoDrawLines(n
, points
, xoffset
, yoffset
);
1845 void wxDCBase::DrawPolygon(const wxList
*list
,
1846 wxCoord xoffset
, wxCoord yoffset
,
1849 int n
= list
->GetCount();
1850 wxPoint
*points
= new wxPoint
[n
];
1853 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
1855 wxPoint
*point
= (wxPoint
*)node
->GetData();
1856 points
[i
].x
= point
->x
;
1857 points
[i
].y
= point
->y
;
1860 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
1866 wxDCBase::DoDrawPolyPolygon(int n
,
1869 wxCoord xoffset
, wxCoord yoffset
,
1874 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
1882 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
1887 pts
= new wxPoint
[j
+n
-1];
1888 for (i
= 0; i
< j
; i
++)
1890 for (i
= 2; i
<= n
; i
++)
1892 lastOfs
-= count
[n
-i
];
1893 pts
[j
++] = pts
[lastOfs
];
1897 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
1898 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
1900 for (i
= j
= 0; i
< n
; i
++)
1902 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
1908 // ----------------------------------------------------------------------------
1910 // ----------------------------------------------------------------------------
1914 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
1915 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
1919 wxPoint
*point1
= new wxPoint
;
1920 point1
->x
= x1
; point1
->y
= y1
;
1921 point_list
.Append((wxObject
*)point1
);
1923 wxPoint
*point2
= new wxPoint
;
1924 point2
->x
= x2
; point2
->y
= y2
;
1925 point_list
.Append((wxObject
*)point2
);
1927 wxPoint
*point3
= new wxPoint
;
1928 point3
->x
= x3
; point3
->y
= y3
;
1929 point_list
.Append((wxObject
*)point3
);
1931 DrawSpline(&point_list
);
1933 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
1935 wxPoint
*p
= (wxPoint
*)node
->GetData();
1940 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
1943 for (int i
=0; i
< n
; i
++)
1945 list
.Append((wxObject
*)&points
[i
]);
1951 // ----------------------------------- spline code ----------------------------------------
1953 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1954 double a3
, double b3
, double a4
, double b4
);
1955 void wx_clear_stack();
1956 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1957 double *y3
, double *x4
, double *y4
);
1958 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1959 double x4
, double y4
);
1960 static bool wx_spline_add_point(double x
, double y
);
1961 static void wx_spline_draw_point_array(wxDCBase
*dc
);
1963 wxList wx_spline_point_list
;
1965 #define half(z1, z2) ((z1+z2)/2.0)
1968 /* iterative version */
1970 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1973 register double xmid
, ymid
;
1974 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1977 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1979 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1980 xmid
= (double)half(x2
, x3
);
1981 ymid
= (double)half(y2
, y3
);
1982 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1983 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1984 wx_spline_add_point( x1
, y1
);
1985 wx_spline_add_point( xmid
, ymid
);
1987 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1988 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1989 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1990 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1995 /* utilities used by spline drawing routines */
1997 typedef struct wx_spline_stack_struct
{
1998 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2001 #define SPLINE_STACK_DEPTH 20
2002 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2003 static Stack
*wx_stack_top
;
2004 static int wx_stack_count
;
2006 void wx_clear_stack()
2008 wx_stack_top
= wx_spline_stack
;
2012 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2014 wx_stack_top
->x1
= x1
;
2015 wx_stack_top
->y1
= y1
;
2016 wx_stack_top
->x2
= x2
;
2017 wx_stack_top
->y2
= y2
;
2018 wx_stack_top
->x3
= x3
;
2019 wx_stack_top
->y3
= y3
;
2020 wx_stack_top
->x4
= x4
;
2021 wx_stack_top
->y4
= y4
;
2026 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2027 double *x3
, double *y3
, double *x4
, double *y4
)
2029 if (wx_stack_count
== 0)
2033 *x1
= wx_stack_top
->x1
;
2034 *y1
= wx_stack_top
->y1
;
2035 *x2
= wx_stack_top
->x2
;
2036 *y2
= wx_stack_top
->y2
;
2037 *x3
= wx_stack_top
->x3
;
2038 *y3
= wx_stack_top
->y3
;
2039 *x4
= wx_stack_top
->x4
;
2040 *y4
= wx_stack_top
->y4
;
2044 static bool wx_spline_add_point(double x
, double y
)
2046 wxPoint
*point
= new wxPoint
;
2049 wx_spline_point_list
.Append((wxObject
*)point
);
2053 static void wx_spline_draw_point_array(wxDCBase
*dc
)
2055 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2056 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
2059 wxPoint
*point
= (wxPoint
*)node
->GetData();
2061 wx_spline_point_list
.Erase(node
);
2062 node
= wx_spline_point_list
.GetFirst();
2066 void wxDCBase::DoDrawSpline( wxList
*points
)
2068 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2071 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2072 double x1
, y1
, x2
, y2
;
2074 wxList::compatibility_iterator node
= points
->GetFirst();
2079 p
= (wxPoint
*)node
->GetData();
2084 node
= node
->GetNext();
2085 p
= (wxPoint
*)node
->GetData();
2089 cx1
= (double)((x1
+ x2
) / 2);
2090 cy1
= (double)((y1
+ y2
) / 2);
2091 cx2
= (double)((cx1
+ x2
) / 2);
2092 cy2
= (double)((cy1
+ y2
) / 2);
2094 wx_spline_add_point(x1
, y1
);
2096 while ((node
= node
->GetNext())
2099 #endif // !wxUSE_STL
2102 p
= (wxPoint
*)node
->GetData();
2107 cx4
= (double)(x1
+ x2
) / 2;
2108 cy4
= (double)(y1
+ y2
) / 2;
2109 cx3
= (double)(x1
+ cx4
) / 2;
2110 cy3
= (double)(y1
+ cy4
) / 2;
2112 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2116 cx2
= (double)(cx1
+ x2
) / 2;
2117 cy2
= (double)(cy1
+ y2
) / 2;
2120 wx_spline_add_point( cx1
, cy1
);
2121 wx_spline_add_point( x2
, y2
);
2123 wx_spline_draw_point_array( this );
2126 #endif // wxUSE_SPLINES
2128 // ----------------------------------------------------------------------------
2129 // Partial Text Extents
2130 // ----------------------------------------------------------------------------
2133 // Each element of the widths array will be the width of the string up to and
2134 // including the corresponding character in text. This is the generic
2135 // implementation, the port-specific classes should do this with native APIs
2136 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2137 // than calling GetTextExtent!!
2139 #define FWC_SIZE 256
2141 class FontWidthCache
2144 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
2145 ~FontWidthCache() { delete []m_widths
; }
2150 m_widths
= new int[FWC_SIZE
];
2152 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
2160 static FontWidthCache s_fontWidthCache
;
2162 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
2166 const size_t len
= text
.length();
2170 // reset the cache if font or horizontal scale have changed
2171 if ( !s_fontWidthCache
.m_widths
||
2172 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
2173 (s_fontWidthCache
.m_font
!= GetFont()) )
2175 s_fontWidthCache
.Reset();
2176 s_fontWidthCache
.m_font
= GetFont();
2177 s_fontWidthCache
.m_scaleX
= m_scaleX
;
2180 // Calculate the position of each character based on the widths of
2181 // the previous characters
2183 for ( size_t i
= 0; i
< len
; i
++ )
2185 const wxChar c
= text
[i
];
2186 unsigned int c_int
= (unsigned int)c
;
2188 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
2190 w
= s_fontWidthCache
.m_widths
[c_int
];
2194 GetTextExtent(c
, &w
, &h
);
2195 if (c_int
< FWC_SIZE
)
2196 s_fontWidthCache
.m_widths
[c_int
] = w
;
2200 widths
[i
] = totalWidth
;
2207 // ----------------------------------------------------------------------------
2208 // enhanced text drawing
2209 // ----------------------------------------------------------------------------
2211 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
2215 const wxFont
*font
) const
2217 wxCoord widthTextMax
= 0, widthLine
,
2218 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
2221 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2223 if ( pc
== text
.end() || *pc
== _T('\n') )
2225 if ( curLine
.empty() )
2227 // we can't use GetTextExtent - it will return 0 for both width
2228 // and height and an empty line should count in height
2231 // assume that this line has the same height as the previous
2233 if ( !heightLineDefault
)
2234 heightLineDefault
= heightLine
;
2236 if ( !heightLineDefault
)
2238 // but we don't know it yet - choose something reasonable
2239 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
2243 heightTextTotal
+= heightLineDefault
;
2247 GetTextExtent(curLine
, &widthLine
, &heightLine
,
2249 if ( widthLine
> widthTextMax
)
2250 widthTextMax
= widthLine
;
2251 heightTextTotal
+= heightLine
;
2254 if ( pc
== text
.end() )
2272 *y
= heightTextTotal
;
2277 void wxDCBase::DrawLabel(const wxString
& text
,
2278 const wxBitmap
& bitmap
,
2282 wxRect
*rectBounding
)
2284 // find the text position
2285 wxCoord widthText
, heightText
, heightLine
;
2286 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
2288 wxCoord width
, height
;
2291 width
= widthText
+ bitmap
.GetWidth();
2292 height
= bitmap
.GetHeight();
2297 height
= heightText
;
2301 if ( alignment
& wxALIGN_RIGHT
)
2303 x
= rect
.GetRight() - width
;
2305 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
2307 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
2309 else // alignment & wxALIGN_LEFT
2314 if ( alignment
& wxALIGN_BOTTOM
)
2316 y
= rect
.GetBottom() - height
;
2318 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
2320 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
2322 else // alignment & wxALIGN_TOP
2327 // draw the bitmap first
2333 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
2335 wxCoord offset
= bitmap
.GetWidth() + 4;
2339 y
+= (height
- heightText
) / 2;
2342 // we will draw the underscore under the accel char later
2343 wxCoord startUnderscore
= 0,
2347 // split the string into lines and draw each of them separately
2349 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
2351 if ( pc
== text
.end() || *pc
== _T('\n') )
2353 int xRealStart
= x
; // init it here to avoid compielr warnings
2355 if ( !curLine
.empty() )
2357 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2358 // wxALIGN_LEFT is 0
2359 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
2362 GetTextExtent(curLine
, &widthLine
, NULL
);
2364 if ( alignment
& wxALIGN_RIGHT
)
2366 xRealStart
+= width
- widthLine
;
2368 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2370 xRealStart
+= (width
- widthLine
) / 2;
2373 //else: left aligned, nothing to do
2375 DrawText(curLine
, xRealStart
, y
);
2380 // do we have underscore in this line? we can check yUnderscore
2381 // because it is set below to just y + heightLine if we do
2382 if ( y
== yUnderscore
)
2384 // adjust the horz positions to account for the shift
2385 startUnderscore
+= xRealStart
;
2386 endUnderscore
+= xRealStart
;
2389 if ( pc
== text
.end() )
2394 else // not end of line
2396 if ( pc
- text
.begin() == indexAccel
)
2398 // remeber to draw underscore here
2399 GetTextExtent(curLine
, &startUnderscore
, NULL
);
2401 GetTextExtent(curLine
, &endUnderscore
, NULL
);
2403 yUnderscore
= y
+ heightLine
;
2412 // draw the underscore if found
2413 if ( startUnderscore
!= endUnderscore
)
2415 // it should be of the same colour as text
2416 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
2420 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
2423 // return bounding rect if requested
2426 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
2429 CalcBoundingBox(x0
, y0
);
2430 CalcBoundingBox(x0
+ width0
, y0
+ height
);
2434 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
2435 const wxColour
& initialColour
,
2436 const wxColour
& destColour
,
2437 wxDirection nDirection
)
2440 wxPen oldPen
= m_pen
;
2441 wxBrush oldBrush
= m_brush
;
2443 wxUint8 nR1
= initialColour
.Red();
2444 wxUint8 nG1
= initialColour
.Green();
2445 wxUint8 nB1
= initialColour
.Blue();
2446 wxUint8 nR2
= destColour
.Red();
2447 wxUint8 nG2
= destColour
.Green();
2448 wxUint8 nB2
= destColour
.Blue();
2451 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
2453 wxInt32 x
= rect
.GetWidth();
2454 wxInt32 w
= x
; // width of area to shade
2455 wxInt32 xDelta
= w
/256; // height of one shade bend
2463 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
2465 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
2468 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
2470 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
2473 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
2475 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
2477 wxColour
colour(nR
,nG
,nB
);
2478 SetPen(wxPen(colour
, 1, wxSOLID
));
2479 SetBrush(wxBrush(colour
));
2480 if(nDirection
== wxEAST
)
2481 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
2482 xDelta
, rect
.GetHeight());
2483 else //nDirection == wxWEST
2484 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
2485 xDelta
, rect
.GetHeight());
2488 else // nDirection == wxNORTH || nDirection == wxSOUTH
2490 wxInt32 y
= rect
.GetHeight();
2491 wxInt32 w
= y
; // height of area to shade
2492 wxInt32 yDelta
= w
/255; // height of one shade bend
2500 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
2502 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
2505 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
2507 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
2510 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
2512 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
2514 wxColour
colour(nR
,nG
,nB
);
2515 SetPen(wxPen(colour
, 1, wxSOLID
));
2516 SetBrush(wxBrush(colour
));
2517 if(nDirection
== wxNORTH
)
2518 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
2519 rect
.GetWidth(), yDelta
);
2520 else //nDirection == wxSOUTH
2521 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
2522 rect
.GetWidth(), yDelta
);
2530 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
2531 const wxColour
& initialColour
,
2532 const wxColour
& destColour
,
2533 const wxPoint
& circleCenter
)
2535 //save the old pen color
2536 wxColour oldPenColour
= m_pen
.GetColour();
2538 wxUint8 nR1
= destColour
.Red();
2539 wxUint8 nG1
= destColour
.Green();
2540 wxUint8 nB1
= destColour
.Blue();
2541 wxUint8 nR2
= initialColour
.Red();
2542 wxUint8 nG2
= initialColour
.Green();
2543 wxUint8 nB2
= initialColour
.Blue();
2548 wxInt32 cx
= rect
.GetWidth() / 2;
2549 wxInt32 cy
= rect
.GetHeight() / 2;
2557 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
2558 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
2560 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
2562 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
2564 //get color difference
2565 wxInt32 nGradient
= ((nRadius
-
2567 pow((double)(x
- cx
- nCircleOffX
), 2) +
2568 pow((double)(y
- cy
- nCircleOffY
), 2)
2569 )) * 100) / nRadius
;
2571 //normalize Gradient
2576 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
2577 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
2578 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
2581 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
2582 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
2585 //return old pen color
2586 m_pen
.SetColour(oldPenColour
);
2590 Notes for wxWidgets DrawEllipticArcRot(...)
2592 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2593 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2596 All methods are generic, so they can be implemented in wxDCBase.
2597 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2598 methods like (WinCE) wxDC::DoDrawArc(...).
2600 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2601 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2602 parts) or every column (in steep parts) only one pixel is calculated.
2603 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2604 starting angle is not equal to the ending angle. The calculation of the
2605 pixels is done using simple arithmetic only and should perform not too
2606 bad even on devices without floating point processor. I didn't test this yet.
2608 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2609 For instance: an ellipse rotated 180 degrees is drawn
2610 slightly different from the original.
2612 The points are then moved to an array and used to draw a polyline and/or polygon
2613 (with center added, the pie).
2614 The result looks quite similar to the native ellipse, only e few pixels differ.
2616 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2617 slower as DrawEllipse(...), which calls the native API.
2618 An rotated ellipse outside the clipping region takes nearly the same time,
2619 while an native ellipse outside takes nearly no time to draw.
2621 If you draw an arc with this new method, you will see the starting and ending angles
2622 are calculated properly.
2623 If you use DrawEllipticArc(...), you will see they are only correct for circles
2624 and not properly calculated for ellipses.
2627 p.lenhard@t-online.de
2631 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
2632 wxCoord w
, wxCoord h
,
2633 double sa
, double ea
, double angle
)
2637 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
2638 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
2640 // Add center (for polygon/pie)
2641 list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) );
2643 // copy list into array and delete list elements
2644 int n
= list
.GetCount();
2645 wxPoint
*points
= new wxPoint
[n
];
2648 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
2650 wxPoint
*point
= (wxPoint
*)node
->GetData();
2651 points
[i
].x
= point
->x
;
2652 points
[i
].y
= point
->y
;
2656 // first draw the pie without pen, if necessary
2657 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
2659 wxPen
tempPen( GetPen() );
2660 SetPen( *wxTRANSPARENT_PEN
);
2661 DoDrawPolygon( n
, points
, 0, 0 );
2665 // then draw the arc without brush, if necessary
2666 if( GetPen() != *wxTRANSPARENT_PEN
)
2669 DoDrawLines( n
-1, points
, 0, 0 );
2674 } // DrawEllipticArcRot
2676 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center
)
2681 double dSinA
= -sin(angle
*2.0*pi
/360.0);
2682 double dCosA
= cos(angle
*2.0*pi
/360.0);
2683 for ( wxNode
* node
= points
->GetFirst(); node
; node
= node
->GetNext() )
2685 wxPoint
* point
= (wxPoint
*)node
->GetData();
2687 // transform coordinates, if necessary
2688 if( center
.x
) point
->x
-= center
.x
;
2689 if( center
.y
) point
->y
-= center
.y
;
2691 // calculate rotation, rounding simply by implicit cast to integer
2692 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
2693 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
2696 // back transform coordinates, if necessary
2697 if( center
.x
) point
->x
+= center
.x
;
2698 if( center
.y
) point
->y
+= center
.y
;
2703 void wxDCBase::CalculateEllipticPoints( wxList
* points
,
2704 wxCoord xStart
, wxCoord yStart
,
2705 wxCoord w
, wxCoord h
,
2706 double sa
, double ea
)
2717 bool bUseAngles
= false;
2723 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2725 if( 2*a
== w
) decrX
= 1;
2727 if( 2*b
== h
) decrY
= 1;
2729 wxCoord xCenter
= xStart
+ a
;
2730 wxCoord yCenter
= yStart
+ b
;
2731 // calculate data for start and end, if necessary
2735 // normalisation of angles
2736 while( sa
<0 ) sa
+= 360;
2737 while( ea
<0 ) ea
+= 360;
2738 while( sa
>=360 ) sa
-= 360;
2739 while( ea
>=360 ) ea
-= 360;
2740 // calculate quadrant numbers
2741 if( sa
> 270 ) sq
= 3;
2742 else if( sa
> 180 ) sq
= 2;
2743 else if( sa
> 90 ) sq
= 1;
2744 if( ea
> 270 ) eq
= 3;
2745 else if( ea
> 180 ) eq
= 2;
2746 else if( ea
> 90 ) eq
= 1;
2747 sar
= sa
* pi
/ 180.0;
2748 ear
= ea
* pi
/ 180.0;
2749 // correct angle circle -> ellipse
2750 sar
= atan( -a
/(double)b
* tan( sar
) );
2751 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
2752 ear
= atan( -a
/(double)b
* tan( ear
) );
2753 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
2754 // coordinates of points
2755 xsa
= xCenter
+ a
* cos( sar
);
2756 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
2757 ysa
= yCenter
+ b
* sin( sar
);
2758 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
2759 xea
= xCenter
+ a
* cos( ear
);
2760 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
2761 yea
= yCenter
+ b
* sin( ear
);
2762 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
2764 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2766 double c2
= 2.0 / w
;
2775 // Lists for quadrant 1 to 4
2776 wxList pointsarray
[4];
2777 // Calculate points for first quadrant and set in all quadrants
2778 for( x
= 0; x
<= a
; ++x
)
2783 bool bNewPoint
= false;
2784 while( y2
> c1
- c2
* x2
&& y
> 0 )
2790 // old y now to big: set point with old y, old x
2791 if( bNewPoint
&& x
>1)
2794 // remove points on the same line
2795 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
2796 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
2797 pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
2798 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
2800 } // calculate point
2802 // Starting and/or ending points for the quadrants, first quadrant gets both.
2803 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2804 pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
- b
) );
2805 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- a
, yCenter
) );
2806 pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
2807 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
2809 // copy quadrants in original list
2812 // Copy the right part of the points in the lists
2813 // and delete the wxPoints, because they do not leave this method.
2814 points
->Append( (wxObject
*) new wxPoint( xsa
, ysa
) );
2816 bool bStarted
= false;
2817 bool bReady
= false;
2818 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
2821 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2823 // once: go to starting point in start quadrant
2826 ( (wxPoint
*) node
->GetData() )->x
< xsa
+1 && q
<= 1
2828 ( (wxPoint
*) node
->GetData() )->x
> xsa
-1 && q
>= 2
2835 // copy point, if not at ending point
2838 if( q
!= eq
|| bForceTurn
2840 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
2842 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
2846 wxPoint
* pPoint
= new wxPoint( *((wxPoint
*) node
->GetData() ) );
2847 points
->Append( (wxObject
*) pPoint
);
2849 else if( q
== eq
&& !bForceTurn
|| ( (wxPoint
*) node
->GetData() )->x
== xea
)
2859 } // while not bReady
2860 points
->Append( (wxObject
*) new wxPoint( xea
, yea
) );
2863 for( q
= 0; q
< 4; ++q
)
2865 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
2867 wxPoint
*p
= (wxPoint
*)node
->GetData();
2875 // copy whole ellipse, wxPoints will be deleted outside
2876 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
2878 wxObject
*p
= node
->GetData();
2879 points
->Append( p
);
2881 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
2883 wxObject
*p
= node
->GetData();
2884 points
->Append( p
);
2886 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
2888 wxObject
*p
= node
->GetData();
2889 points
->Append( p
);
2891 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
2893 wxObject
*p
= node
->GetData();
2894 points
->Append( p
);
2897 } // CalculateEllipticPoints
2899 #endif // __WXWINCE__
2901 #endif // wxUSE_NEW_DC