Use wxPointList instead of wxList in wxDC code
[wxWidgets.git] / src / common / dcbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 05/25/99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/dc.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
32
33 #ifndef WX_PRECOMP
34 #include "wx/math.h"
35 #endif
36
37
38
39 #if wxUSE_NEW_DC
40
41 //----------------------------------------------------------------------------
42 // wxDCFactory
43 //----------------------------------------------------------------------------
44
45 wxDCFactory *wxDCFactory::m_factory = NULL;
46
47 void wxDCFactory::SetDCFactory( wxDCFactory *factory )
48 {
49 if (wxDCFactory::m_factory)
50 delete wxDCFactory::m_factory;
51
52 wxDCFactory::m_factory = factory;
53 }
54
55 wxDCFactory *wxDCFactory::GetFactory()
56 {
57 if (!wxDCFactory::m_factory)
58 wxDCFactory::m_factory = new wxNativeDCFactory;
59
60 return wxDCFactory::m_factory;
61 }
62
63 //-----------------------------------------------------------------------------
64 // wxNativeDCFactory
65 //-----------------------------------------------------------------------------
66
67 wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
68 {
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 );
91 #endif
92 }
93
94 wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
95 {
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 );
118 #endif
119 }
120
121 wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
122 {
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 );
145 #endif
146 }
147
148 wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
149 {
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 );
172 #endif
173 }
174
175 wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
176 {
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 );
199 #endif
200 }
201
202 wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
203 {
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 );
226 #endif
227 }
228
229 wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
230 {
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 );
253 #endif
254 }
255
256 wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
257 {
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 );
280 #endif
281 }
282
283 wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
284 {
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 );
307 #endif
308 }
309
310 wxImplDC* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
311 {
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 );
334 #endif
335 }
336
337 //-----------------------------------------------------------------------------
338 // wxWindowDC
339 //-----------------------------------------------------------------------------
340
341 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
342
343 wxWindowDC::wxWindowDC()
344 {
345 wxDCFactory *factory = wxDCFactory::GetFactory();
346 m_pimpl = factory->CreateWindowDC( this );
347 }
348
349 wxWindowDC::wxWindowDC( wxWindow *win )
350 {
351 wxDCFactory *factory = wxDCFactory::GetFactory();
352 m_pimpl = factory->CreateWindowDC( this, win );
353 }
354
355 //-----------------------------------------------------------------------------
356 // wxClientDC
357 //-----------------------------------------------------------------------------
358
359 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxDC)
360
361 wxClientDC::wxClientDC()
362 {
363 wxDCFactory *factory = wxDCFactory::GetFactory();
364 m_pimpl = factory->CreateClientDC( this );
365 }
366
367 wxClientDC::wxClientDC( wxWindow *win )
368 {
369 wxDCFactory *factory = wxDCFactory::GetFactory();
370 m_pimpl = factory->CreateClientDC( this, win );
371 }
372
373 //-----------------------------------------------------------------------------
374 // wxMemoryDC
375 //-----------------------------------------------------------------------------
376
377 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
378
379 wxMemoryDC::wxMemoryDC()
380 {
381 wxDCFactory *factory = wxDCFactory::GetFactory();
382 m_pimpl = factory->CreateMemoryDC( this );
383 }
384
385 wxMemoryDC::wxMemoryDC( wxBitmap& bitmap )
386 {
387 wxDCFactory *factory = wxDCFactory::GetFactory();
388 m_pimpl = factory->CreateMemoryDC( this, bitmap );
389 }
390
391 wxMemoryDC::wxMemoryDC( wxDC *dc )
392 {
393 wxDCFactory *factory = wxDCFactory::GetFactory();
394 m_pimpl = factory->CreateMemoryDC( this, dc );
395 }
396
397 void wxMemoryDC::SelectObject(wxBitmap& bmp)
398 {
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
402 if (bmp.IsOk())
403 bmp.UnShare();
404
405 #ifdef __WXGTK__
406 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
407 #else
408 // TODO
409 #endif
410 if (mem_pimpl)
411 mem_pimpl->DoSelect(bmp);
412 }
413
414 void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
415 {
416 #ifdef __WXGTK__
417 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
418 #else
419 // TODO
420 #endif
421 mem_pimpl->DoSelect(bmp);
422 }
423
424 const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
425 {
426 #ifdef __WXGTK__
427 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
428 #else
429 // TODO
430 #endif
431 if (mem_pimpl)
432 return mem_pimpl->DoGetSelectedBitmap();
433
434 return wxNullBitmap;
435 }
436
437 wxBitmap& wxMemoryDC::GetSelectedBitmap()
438 {
439 #ifdef __WXGTK__
440 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
441 #else
442 // TODO
443 #endif
444
445 if (mem_pimpl)
446 return mem_pimpl->DoGetSelectedBitmap();
447
448 return wxNullBitmap;
449 }
450
451
452 //-----------------------------------------------------------------------------
453 // wxPaintDC
454 //-----------------------------------------------------------------------------
455
456 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxDC)
457
458 wxPaintDC::wxPaintDC()
459 {
460 wxDCFactory *factory = wxDCFactory::GetFactory();
461 m_pimpl = factory->CreatePaintDC( this );
462 }
463
464 wxPaintDC::wxPaintDC( wxWindow *win )
465 {
466 wxDCFactory *factory = wxDCFactory::GetFactory();
467 m_pimpl = factory->CreatePaintDC( this, win );
468 }
469
470 //-----------------------------------------------------------------------------
471 // wxScreenDC
472 //-----------------------------------------------------------------------------
473
474 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
475
476 wxScreenDC::wxScreenDC()
477 {
478 wxDCFactory *factory = wxDCFactory::GetFactory();
479 m_pimpl = factory->CreateScreenDC( this );
480 }
481
482 //-----------------------------------------------------------------------------
483 // wxImplDC
484 //-----------------------------------------------------------------------------
485
486 IMPLEMENT_ABSTRACT_CLASS(wxImplDC, wxObject)
487
488 wxImplDC::wxImplDC( wxDC *owner )
489 : m_colour(wxColourDisplay())
490 , m_ok(true)
491 , m_clipping(false)
492 , m_isInteractive(0)
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)
506 , m_pen()
507 , m_brush()
508 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
509 , m_textForegroundColour(*wxBLACK)
510 , m_textBackgroundColour(*wxWHITE)
511 , m_font()
512 #if wxUSE_PALETTE
513 , m_palette()
514 , m_hasCustomPalette(false)
515 #endif // wxUSE_PALETTE
516 {
517 m_owner = owner;
518
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();
523
524 ResetBoundingBox();
525 ResetClipping();
526 }
527
528 wxImplDC::~wxImplDC()
529 {
530 }
531
532 // ----------------------------------------------------------------------------
533 // coordinate conversions and transforms
534 // ----------------------------------------------------------------------------
535
536 wxCoord wxImplDC::DeviceToLogicalX(wxCoord x) const
537 {
538 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
539 }
540
541 wxCoord wxImplDC::DeviceToLogicalY(wxCoord y) const
542 {
543 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
544 }
545
546 wxCoord wxImplDC::DeviceToLogicalXRel(wxCoord x) const
547 {
548 return wxRound((double)(x) / m_scaleX);
549 }
550
551 wxCoord wxImplDC::DeviceToLogicalYRel(wxCoord y) const
552 {
553 return wxRound((double)(y) / m_scaleY);
554 }
555
556 wxCoord wxImplDC::LogicalToDeviceX(wxCoord x) const
557 {
558 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
559 }
560
561 wxCoord wxImplDC::LogicalToDeviceY(wxCoord y) const
562 {
563 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY;
564 }
565
566 wxCoord wxImplDC::LogicalToDeviceXRel(wxCoord x) const
567 {
568 return wxRound((double)(x) * m_scaleX);
569 }
570
571 wxCoord wxImplDC::LogicalToDeviceYRel(wxCoord y) const
572 {
573 return wxRound((double)(y) * m_scaleY);
574 }
575
576 void wxImplDC::ComputeScaleAndOrigin()
577 {
578 m_scaleX = m_logicalScaleX * m_userScaleX;
579 m_scaleY = m_logicalScaleY * m_userScaleY;
580 }
581
582 void wxImplDC::SetMapMode( int mode )
583 {
584 switch (mode)
585 {
586 case wxMM_TWIPS:
587 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
588 break;
589 case wxMM_POINTS:
590 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
591 break;
592 case wxMM_METRIC:
593 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
594 break;
595 case wxMM_LOMETRIC:
596 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
597 break;
598 default:
599 case wxMM_TEXT:
600 SetLogicalScale( 1.0, 1.0 );
601 break;
602 }
603 m_mappingMode = mode;
604 }
605
606 void wxImplDC::SetUserScale( double x, double y )
607 {
608 // allow negative ? -> no
609 m_userScaleX = x;
610 m_userScaleY = y;
611 ComputeScaleAndOrigin();
612 }
613
614 void wxImplDC::SetLogicalScale( double x, double y )
615 {
616 // allow negative ?
617 m_logicalScaleX = x;
618 m_logicalScaleY = y;
619 ComputeScaleAndOrigin();
620 }
621
622 void wxImplDC::SetLogicalOrigin( wxCoord x, wxCoord y )
623 {
624 m_logicalOriginX = x * m_signX;
625 m_logicalOriginY = y * m_signY;
626 ComputeScaleAndOrigin();
627 }
628
629 void wxImplDC::SetDeviceOrigin( wxCoord x, wxCoord y )
630 {
631 m_deviceOriginX = x;
632 m_deviceOriginY = y;
633 ComputeScaleAndOrigin();
634 }
635
636 void wxImplDC::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
637 {
638 m_deviceLocalOriginX = x;
639 m_deviceLocalOriginY = y;
640 ComputeScaleAndOrigin();
641 }
642
643 void wxImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
644 {
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();
650 }
651
652
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!!
658
659 #define FWC_SIZE 256
660
661 class FontWidthCache
662 {
663 public:
664 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
665 ~FontWidthCache() { delete []m_widths; }
666
667 void Reset()
668 {
669 if (!m_widths)
670 m_widths = new int[FWC_SIZE];
671
672 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
673 }
674
675 wxFont m_font;
676 double m_scaleX;
677 int *m_widths;
678 };
679
680 static FontWidthCache s_fontWidthCache;
681
682 bool wxImplDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
683 {
684 int totalWidth = 0;
685
686 const size_t len = text.length();
687 widths.Empty();
688 widths.Add(0, len);
689
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()) )
694 {
695 s_fontWidthCache.Reset();
696 s_fontWidthCache.m_font = GetFont();
697 s_fontWidthCache.m_scaleX = m_scaleX;
698 }
699
700 // Calculate the position of each character based on the widths of
701 // the previous characters
702 int w, h;
703 for ( size_t i = 0; i < len; i++ )
704 {
705 const wxChar c = text[i];
706 unsigned int c_int = (unsigned int)c;
707
708 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
709 {
710 w = s_fontWidthCache.m_widths[c_int];
711 }
712 else
713 {
714 DoGetTextExtent(c, &w, &h);
715 if (c_int < FWC_SIZE)
716 s_fontWidthCache.m_widths[c_int] = w;
717 }
718
719 totalWidth += w;
720 widths[i] = totalWidth;
721 }
722
723 return true;
724 }
725
726 void wxImplDC::GetMultiLineTextExtent(const wxString& text,
727 wxCoord *x,
728 wxCoord *y,
729 wxCoord *h,
730 const wxFont *font) const
731 {
732 wxCoord widthTextMax = 0, widthLine,
733 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
734
735 wxString curLine;
736 for ( const wxChar *pc = text; ; pc++ )
737 {
738 if ( *pc == _T('\n') || *pc == _T('\0') )
739 {
740 if ( curLine.empty() )
741 {
742 // we can't use GetTextExtent - it will return 0 for both width
743 // and height and an empty line should count in height
744 // calculation
745
746 // assume that this line has the same height as the previous
747 // one
748 if ( !heightLineDefault )
749 heightLineDefault = heightLine;
750
751 if ( !heightLineDefault )
752 {
753 // but we don't know it yet - choose something reasonable
754 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
755 NULL, NULL, font);
756 }
757
758 heightTextTotal += heightLineDefault;
759 }
760 else
761 {
762 DoGetTextExtent(curLine, &widthLine, &heightLine,
763 NULL, NULL, font);
764 if ( widthLine > widthTextMax )
765 widthTextMax = widthLine;
766 heightTextTotal += heightLine;
767 }
768
769 if ( *pc == _T('\n') )
770 {
771 curLine.clear();
772 }
773 else
774 {
775 // the end of string
776 break;
777 }
778 }
779 else
780 {
781 curLine += *pc;
782 }
783 }
784
785 if ( x )
786 *x = widthTextMax;
787 if ( y )
788 *y = heightTextTotal;
789 if ( h )
790 *h = heightLine;
791 }
792
793 void wxImplDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
794 wxCoord width, wxCoord height)
795 {
796 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
797
798 wxCoord x2 = x1 + width,
799 y2 = y1 + height;
800
801 // the pen width is calibrated to give 3 for width == height == 10
802 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
803
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);
809
810 CalcBoundingBox(x1, y1);
811 CalcBoundingBox(x2, y2);
812 }
813
814 bool
815 wxImplDC::DoStretchBlit(wxCoord xdest, wxCoord ydest,
816 wxCoord dstWidth, wxCoord dstHeight,
817 wxDC *source,
818 wxCoord xsrc, wxCoord ysrc,
819 wxCoord srcWidth, wxCoord srcHeight,
820 int rop,
821 bool useMask,
822 wxCoord xsrcMask,
823 wxCoord ysrcMask)
824 {
825 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
826 _T("invalid blit size") );
827
828 // emulate the stretching by modifying the DC scale
829 double xscale = (double)srcWidth/dstWidth,
830 yscale = (double)srcHeight/dstHeight;
831
832 double xscaleOld, yscaleOld;
833 GetUserScale(&xscaleOld, &yscaleOld);
834 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
835
836 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
837 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
838 source,
839 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
840
841 SetUserScale(xscaleOld, yscaleOld);
842
843 return rc;
844 }
845
846 void wxImplDC::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
847 {
848 int n = list->GetCount();
849 wxPoint *points = new wxPoint[n];
850
851 int i = 0;
852 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
853 {
854 wxPoint *point = node->GetData();
855 points[i].x = point->x;
856 points[i].y = point->y;
857 }
858
859 DoDrawLines(n, points, xoffset, yoffset);
860
861 delete [] points;
862 }
863
864 void wxImplDC::DrawPolygon(const wxPointList *list,
865 wxCoord xoffset, wxCoord yoffset,
866 int fillStyle)
867 {
868 int n = list->GetCount();
869 wxPoint *points = new wxPoint[n];
870
871 int i = 0;
872 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
873 {
874 wxPoint *point = node->GetData();
875 points[i].x = point->x;
876 points[i].y = point->y;
877 }
878
879 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
880
881 delete [] points;
882 }
883
884 void
885 wxImplDC::DoDrawPolyPolygon(int n,
886 int count[],
887 wxPoint points[],
888 wxCoord xoffset, wxCoord yoffset,
889 int fillStyle)
890 {
891 if ( n == 1 )
892 {
893 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
894 return;
895 }
896
897 int i, j, lastOfs;
898 wxPoint* pts;
899 wxPen pen;
900
901 for (i = j = lastOfs = 0; i < n; i++)
902 {
903 lastOfs = j;
904 j += count[i];
905 }
906 pts = new wxPoint[j+n-1];
907 for (i = 0; i < j; i++)
908 pts[i] = points[i];
909 for (i = 2; i <= n; i++)
910 {
911 lastOfs -= count[n-i];
912 pts[j++] = pts[lastOfs];
913 }
914
915 pen = GetPen();
916 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
917 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
918 SetPen(pen);
919 for (i = j = 0; i < n; i++)
920 {
921 DoDrawLines(count[i], pts+j, xoffset, yoffset);
922 j += count[i];
923 }
924 delete[] pts;
925 }
926
927 #if wxUSE_SPLINES
928
929 void wxImplDC::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
930 {
931 wxPointList point_list;
932
933 wxPoint *point1 = new wxPoint;
934 point1->x = x1; point1->y = y1;
935 point_list.Append( point1 );
936
937 wxPoint *point2 = new wxPoint;
938 point2->x = x2; point2->y = y2;
939 point_list.Append( point2 );
940
941 wxPoint *point3 = new wxPoint;
942 point3->x = x3; point3->y = y3;
943 point_list.Append( point3 );
944
945 DoDrawSpline(&point_list);
946
947 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
948 {
949 wxPoint *p = node->GetData();
950 delete p;
951 }
952 }
953
954 void wxImplDC::DoDrawSpline(int n, wxPoint points[])
955 {
956 wxPointList list;
957 for (int i =0; i < n; i++)
958 list.Append( &points[i] );
959
960 DoDrawSpline(&list);
961 }
962
963 // ----------------------------------- spline code ----------------------------------------
964
965 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
966 double a3, double b3, double a4, double b4);
967 void wx_clear_stack();
968 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
969 double *y3, double *x4, double *y4);
970 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
971 double x4, double y4);
972 static bool wx_spline_add_point(double x, double y);
973 static void wx_spline_draw_point_array(wxDC *dc);
974
975 wxPointList wx_spline_point_list;
976
977 #define half(z1, z2) ((z1+z2)/2.0)
978 #define THRESHOLD 5
979
980 /* iterative version */
981
982 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
983 double b4)
984 {
985 register double xmid, ymid;
986 double x1, y1, x2, y2, x3, y3, x4, y4;
987
988 wx_clear_stack();
989 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
990
991 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
992 xmid = (double)half(x2, x3);
993 ymid = (double)half(y2, y3);
994 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
995 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
996 wx_spline_add_point( x1, y1 );
997 wx_spline_add_point( xmid, ymid );
998 } else {
999 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1000 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1001 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1002 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1003 }
1004 }
1005 }
1006
1007 /* utilities used by spline drawing routines */
1008
1009 typedef struct wx_spline_stack_struct {
1010 double x1, y1, x2, y2, x3, y3, x4, y4;
1011 } Stack;
1012
1013 #define SPLINE_STACK_DEPTH 20
1014 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1015 static Stack *wx_stack_top;
1016 static int wx_stack_count;
1017
1018 void wx_clear_stack()
1019 {
1020 wx_stack_top = wx_spline_stack;
1021 wx_stack_count = 0;
1022 }
1023
1024 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1025 {
1026 wx_stack_top->x1 = x1;
1027 wx_stack_top->y1 = y1;
1028 wx_stack_top->x2 = x2;
1029 wx_stack_top->y2 = y2;
1030 wx_stack_top->x3 = x3;
1031 wx_stack_top->y3 = y3;
1032 wx_stack_top->x4 = x4;
1033 wx_stack_top->y4 = y4;
1034 wx_stack_top++;
1035 wx_stack_count++;
1036 }
1037
1038 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1039 double *x3, double *y3, double *x4, double *y4)
1040 {
1041 if (wx_stack_count == 0)
1042 return (0);
1043 wx_stack_top--;
1044 wx_stack_count--;
1045 *x1 = wx_stack_top->x1;
1046 *y1 = wx_stack_top->y1;
1047 *x2 = wx_stack_top->x2;
1048 *y2 = wx_stack_top->y2;
1049 *x3 = wx_stack_top->x3;
1050 *y3 = wx_stack_top->y3;
1051 *x4 = wx_stack_top->x4;
1052 *y4 = wx_stack_top->y4;
1053 return (1);
1054 }
1055
1056 static bool wx_spline_add_point(double x, double y)
1057 {
1058 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
1059 wx_spline_point_list.Append(point );
1060 return true;
1061 }
1062
1063 static void wx_spline_draw_point_array(wxDC *dc)
1064 {
1065 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
1066 while (node)
1067 {
1068 wxPoint *point = node->GetData();
1069 delete point;
1070 wx_spline_point_list.Erase(node);
1071 node = wx_spline_point_list.GetFirst();
1072 }
1073 }
1074
1075 void wxImplDC::DoDrawSpline( const wxPointList *points )
1076 {
1077 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
1078
1079 wxPoint *p;
1080 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1081 double x1, y1, x2, y2;
1082
1083 wxPointList::compatibility_iterator node = points->GetFirst();
1084 if (!node)
1085 // empty list
1086 return;
1087
1088 p = (wxPoint *)node->GetData();
1089
1090 x1 = p->x;
1091 y1 = p->y;
1092
1093 node = node->GetNext();
1094 p = node->GetData();
1095
1096 x2 = p->x;
1097 y2 = p->y;
1098 cx1 = (double)((x1 + x2) / 2);
1099 cy1 = (double)((y1 + y2) / 2);
1100 cx2 = (double)((cx1 + x2) / 2);
1101 cy2 = (double)((cy1 + y2) / 2);
1102
1103 wx_spline_add_point(x1, y1);
1104
1105 while ((node = node->GetNext())
1106 #if !wxUSE_STL
1107 != NULL
1108 #endif // !wxUSE_STL
1109 )
1110 {
1111 p = node->GetData();
1112 x1 = x2;
1113 y1 = y2;
1114 x2 = p->x;
1115 y2 = p->y;
1116 cx4 = (double)(x1 + x2) / 2;
1117 cy4 = (double)(y1 + y2) / 2;
1118 cx3 = (double)(x1 + cx4) / 2;
1119 cy3 = (double)(y1 + cy4) / 2;
1120
1121 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1122
1123 cx1 = cx4;
1124 cy1 = cy4;
1125 cx2 = (double)(cx1 + x2) / 2;
1126 cy2 = (double)(cy1 + y2) / 2;
1127 }
1128
1129 wx_spline_add_point( cx1, cy1 );
1130 wx_spline_add_point( x2, y2 );
1131
1132 wx_spline_draw_point_array( m_owner );
1133 }
1134
1135 #endif // wxUSE_SPLINES
1136
1137
1138
1139 void wxImplDC::DoGradientFillLinear(const wxRect& rect,
1140 const wxColour& initialColour,
1141 const wxColour& destColour,
1142 wxDirection nDirection)
1143 {
1144 // save old pen
1145 wxPen oldPen = m_pen;
1146 wxBrush oldBrush = m_brush;
1147
1148 wxUint8 nR1 = initialColour.Red();
1149 wxUint8 nG1 = initialColour.Green();
1150 wxUint8 nB1 = initialColour.Blue();
1151 wxUint8 nR2 = destColour.Red();
1152 wxUint8 nG2 = destColour.Green();
1153 wxUint8 nB2 = destColour.Blue();
1154 wxUint8 nR, nG, nB;
1155
1156 if ( nDirection == wxEAST || nDirection == wxWEST )
1157 {
1158 wxInt32 x = rect.GetWidth();
1159 wxInt32 w = x; // width of area to shade
1160 wxInt32 xDelta = w/256; // height of one shade bend
1161 if (xDelta < 1)
1162 xDelta = 1;
1163
1164 while (x >= xDelta)
1165 {
1166 x -= xDelta;
1167 if (nR1 > nR2)
1168 nR = nR1 - (nR1-nR2)*(w-x)/w;
1169 else
1170 nR = nR1 + (nR2-nR1)*(w-x)/w;
1171
1172 if (nG1 > nG2)
1173 nG = nG1 - (nG1-nG2)*(w-x)/w;
1174 else
1175 nG = nG1 + (nG2-nG1)*(w-x)/w;
1176
1177 if (nB1 > nB2)
1178 nB = nB1 - (nB1-nB2)*(w-x)/w;
1179 else
1180 nB = nB1 + (nB2-nB1)*(w-x)/w;
1181
1182 wxColour colour(nR,nG,nB);
1183 SetPen(wxPen(colour, 1, wxSOLID));
1184 SetBrush(wxBrush(colour));
1185 if(nDirection == wxEAST)
1186 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
1187 xDelta, rect.GetHeight());
1188 else //nDirection == wxWEST
1189 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1190 xDelta, rect.GetHeight());
1191 }
1192 }
1193 else // nDirection == wxNORTH || nDirection == wxSOUTH
1194 {
1195 wxInt32 y = rect.GetHeight();
1196 wxInt32 w = y; // height of area to shade
1197 wxInt32 yDelta = w/255; // height of one shade bend
1198 if (yDelta < 1)
1199 yDelta = 1;
1200
1201 while (y > 0)
1202 {
1203 y -= yDelta;
1204 if (nR1 > nR2)
1205 nR = nR1 - (nR1-nR2)*(w-y)/w;
1206 else
1207 nR = nR1 + (nR2-nR1)*(w-y)/w;
1208
1209 if (nG1 > nG2)
1210 nG = nG1 - (nG1-nG2)*(w-y)/w;
1211 else
1212 nG = nG1 + (nG2-nG1)*(w-y)/w;
1213
1214 if (nB1 > nB2)
1215 nB = nB1 - (nB1-nB2)*(w-y)/w;
1216 else
1217 nB = nB1 + (nB2-nB1)*(w-y)/w;
1218
1219 wxColour colour(nR,nG,nB);
1220 SetPen(wxPen(colour, 1, wxSOLID));
1221 SetBrush(wxBrush(colour));
1222 if(nDirection == wxNORTH)
1223 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1224 rect.GetWidth(), yDelta);
1225 else //nDirection == wxSOUTH
1226 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
1227 rect.GetWidth(), yDelta);
1228 }
1229 }
1230
1231 SetPen(oldPen);
1232 SetBrush(oldBrush);
1233 }
1234
1235 void wxImplDC::DoGradientFillConcentric(const wxRect& rect,
1236 const wxColour& initialColour,
1237 const wxColour& destColour,
1238 const wxPoint& circleCenter)
1239 {
1240 //save the old pen color
1241 wxColour oldPenColour = m_pen.GetColour();
1242
1243 wxUint8 nR1 = destColour.Red();
1244 wxUint8 nG1 = destColour.Green();
1245 wxUint8 nB1 = destColour.Blue();
1246 wxUint8 nR2 = initialColour.Red();
1247 wxUint8 nG2 = initialColour.Green();
1248 wxUint8 nB2 = initialColour.Blue();
1249 wxUint8 nR, nG, nB;
1250
1251
1252 //Radius
1253 wxInt32 cx = rect.GetWidth() / 2;
1254 wxInt32 cy = rect.GetHeight() / 2;
1255 wxInt32 nRadius;
1256 if (cx < cy)
1257 nRadius = cx;
1258 else
1259 nRadius = cy;
1260
1261 //Offset of circle
1262 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1263 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1264
1265 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1266 {
1267 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1268 {
1269 //get color difference
1270 wxInt32 nGradient = ((nRadius -
1271 (wxInt32)sqrt(
1272 pow((double)(x - cx - nCircleOffX), 2) +
1273 pow((double)(y - cy - nCircleOffY), 2)
1274 )) * 100) / nRadius;
1275
1276 //normalize Gradient
1277 if (nGradient < 0 )
1278 nGradient = 0;
1279
1280 //get dest colors
1281 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1282 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1283 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1284
1285 //set the pixel
1286 m_pen.SetColour(wxColour(nR,nG,nB));
1287 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
1288 }
1289 }
1290 //return old pen color
1291 m_pen.SetColour(oldPenColour);
1292 }
1293
1294 //-----------------------------------------------------------------------------
1295 // wxDC
1296 //-----------------------------------------------------------------------------
1297
1298 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1299
1300 void wxDC::DrawLabel(const wxString& text,
1301 const wxBitmap& bitmap,
1302 const wxRect& rect,
1303 int alignment,
1304 int indexAccel,
1305 wxRect *rectBounding)
1306 {
1307 // find the text position
1308 wxCoord widthText, heightText, heightLine;
1309 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1310
1311 wxCoord width, height;
1312 if ( bitmap.Ok() )
1313 {
1314 width = widthText + bitmap.GetWidth();
1315 height = bitmap.GetHeight();
1316 }
1317 else // no bitmap
1318 {
1319 width = widthText;
1320 height = heightText;
1321 }
1322
1323 wxCoord x, y;
1324 if ( alignment & wxALIGN_RIGHT )
1325 {
1326 x = rect.GetRight() - width;
1327 }
1328 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1329 {
1330 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1331 }
1332 else // alignment & wxALIGN_LEFT
1333 {
1334 x = rect.GetLeft();
1335 }
1336
1337 if ( alignment & wxALIGN_BOTTOM )
1338 {
1339 y = rect.GetBottom() - height;
1340 }
1341 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1342 {
1343 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1344 }
1345 else // alignment & wxALIGN_TOP
1346 {
1347 y = rect.GetTop();
1348 }
1349
1350 // draw the bitmap first
1351 wxCoord x0 = x,
1352 y0 = y,
1353 width0 = width;
1354 if ( bitmap.Ok() )
1355 {
1356 DrawBitmap(bitmap, x, y, true /* use mask */);
1357
1358 wxCoord offset = bitmap.GetWidth() + 4;
1359 x += offset;
1360 width -= offset;
1361
1362 y += (height - heightText) / 2;
1363 }
1364
1365 // we will draw the underscore under the accel char later
1366 wxCoord startUnderscore = 0,
1367 endUnderscore = 0,
1368 yUnderscore = 0;
1369
1370 // split the string into lines and draw each of them separately
1371 wxString curLine;
1372 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1373 {
1374 if ( *pc == _T('\n') || pc == text.end() )
1375 {
1376 int xRealStart = x; // init it here to avoid compielr warnings
1377
1378 if ( !curLine.empty() )
1379 {
1380 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1381 // wxALIGN_LEFT is 0
1382 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1383 {
1384 wxCoord widthLine;
1385 GetTextExtent(curLine, &widthLine, NULL);
1386
1387 if ( alignment & wxALIGN_RIGHT )
1388 {
1389 xRealStart += width - widthLine;
1390 }
1391 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1392 {
1393 xRealStart += (width - widthLine) / 2;
1394 }
1395 }
1396 //else: left aligned, nothing to do
1397
1398 DrawText(curLine, xRealStart, y);
1399 }
1400
1401 y += heightLine;
1402
1403 // do we have underscore in this line? we can check yUnderscore
1404 // because it is set below to just y + heightLine if we do
1405 if ( y == yUnderscore )
1406 {
1407 // adjust the horz positions to account for the shift
1408 startUnderscore += xRealStart;
1409 endUnderscore += xRealStart;
1410 }
1411
1412 if ( pc == text.end() )
1413 break;
1414
1415 curLine.clear();
1416 }
1417 else // not end of line
1418 {
1419 if ( pc - text.begin() == indexAccel )
1420 {
1421 // remeber to draw underscore here
1422 GetTextExtent(curLine, &startUnderscore, NULL);
1423 curLine += *pc;
1424 GetTextExtent(curLine, &endUnderscore, NULL);
1425
1426 yUnderscore = y + heightLine;
1427 }
1428 else
1429 {
1430 curLine += *pc;
1431 }
1432 }
1433 }
1434
1435 // draw the underscore if found
1436 if ( startUnderscore != endUnderscore )
1437 {
1438 // it should be of the same colour as text
1439 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1440
1441 yUnderscore--;
1442
1443 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1444 }
1445
1446 // return bounding rect if requested
1447 if ( rectBounding )
1448 {
1449 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1450 }
1451
1452 CalcBoundingBox(x0, y0);
1453 CalcBoundingBox(x0 + width0, y0 + height);
1454 }
1455
1456 #if WXWIN_COMPATIBILITY_2_8
1457 // for compatibility with the old code when wxCoord was long everywhere
1458 void wxDC::GetTextExtent(const wxString& string,
1459 long *x, long *y,
1460 long *descent,
1461 long *externalLeading,
1462 const wxFont *theFont) const
1463 {
1464 wxCoord x2, y2, descent2, externalLeading2;
1465 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1466 &descent2, &externalLeading2,
1467 theFont);
1468 if ( x )
1469 *x = x2;
1470 if ( y )
1471 *y = y2;
1472 if ( descent )
1473 *descent = descent2;
1474 if ( externalLeading )
1475 *externalLeading = externalLeading2;
1476 }
1477
1478 void wxDC::GetLogicalOrigin(long *x, long *y) const
1479 {
1480 wxCoord x2, y2;
1481 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1482 if ( x )
1483 *x = x2;
1484 if ( y )
1485 *y = y2;
1486 }
1487
1488 void wxDC::GetDeviceOrigin(long *x, long *y) const
1489 {
1490 wxCoord x2, y2;
1491 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1492 if ( x )
1493 *x = x2;
1494 if ( y )
1495 *y = y2;
1496 }
1497
1498 void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1499 {
1500 wxCoord xx,yy,ww,hh;
1501 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1502 if (x) *x = xx;
1503 if (y) *y = yy;
1504 if (w) *w = ww;
1505 if (h) *h = hh;
1506 }
1507
1508 #endif // WXWIN_COMPATIBILITY_2_8
1509
1510
1511 #else // wxUSE_NEW_DC
1512
1513
1514 // bool wxDCBase::sm_cacheing = false;
1515
1516 IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
1517
1518 // ============================================================================
1519 // implementation
1520 // ============================================================================
1521
1522 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
1523 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
1524
1525 wxDCBase::wxDCBase()
1526 : m_colour(wxColourDisplay())
1527 , m_ok(true)
1528 , m_clipping(false)
1529 , m_isInteractive(0)
1530 , m_isBBoxValid(false)
1531 , m_logicalOriginX(0), m_logicalOriginY(0)
1532 , m_deviceOriginX(0), m_deviceOriginY(0)
1533 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1534 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1535 , m_userScaleX(1.0), m_userScaleY(1.0)
1536 , m_scaleX(1.0), m_scaleY(1.0)
1537 , m_signX(1), m_signY(1)
1538 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1539 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1540 , m_logicalFunction(wxCOPY)
1541 , m_backgroundMode(wxTRANSPARENT)
1542 , m_mappingMode(wxMM_TEXT)
1543 , m_pen()
1544 , m_brush()
1545 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
1546 , m_textForegroundColour(*wxBLACK)
1547 , m_textBackgroundColour(*wxWHITE)
1548 , m_font()
1549 #if wxUSE_PALETTE
1550 , m_palette()
1551 , m_hasCustomPalette(false)
1552 #endif // wxUSE_PALETTE
1553 {
1554 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
1555 (double)wxGetDisplaySizeMM().GetWidth();
1556 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
1557 (double)wxGetDisplaySizeMM().GetHeight();
1558
1559 ResetBoundingBox();
1560 ResetClipping();
1561 }
1562
1563 wxDCBase::~wxDCBase()
1564 {
1565 }
1566
1567 #if WXWIN_COMPATIBILITY_2_6
1568 void wxDCBase::BeginDrawing()
1569 {
1570 }
1571
1572 void wxDCBase::EndDrawing()
1573 {
1574 }
1575 #endif // WXWIN_COMPATIBILITY_2_6
1576
1577 #if WXWIN_COMPATIBILITY_2_8
1578 // for compatibility with the old code when wxCoord was long everywhere
1579 void wxDCBase::GetTextExtent(const wxString& string,
1580 long *x, long *y,
1581 long *descent,
1582 long *externalLeading,
1583 const wxFont *theFont) const
1584 {
1585 wxCoord x2, y2, descent2, externalLeading2;
1586 DoGetTextExtent(string, &x2, &y2,
1587 &descent2, &externalLeading2,
1588 theFont);
1589 if ( x )
1590 *x = x2;
1591 if ( y )
1592 *y = y2;
1593 if ( descent )
1594 *descent = descent2;
1595 if ( externalLeading )
1596 *externalLeading = externalLeading2;
1597 }
1598
1599 void wxDCBase::GetLogicalOrigin(long *x, long *y) const
1600 {
1601 wxCoord x2, y2;
1602 DoGetLogicalOrigin(&x2, &y2);
1603 if ( x )
1604 *x = x2;
1605 if ( y )
1606 *y = y2;
1607 }
1608
1609 void wxDCBase::GetDeviceOrigin(long *x, long *y) const
1610 {
1611 wxCoord x2, y2;
1612 DoGetDeviceOrigin(&x2, &y2);
1613 if ( x )
1614 *x = x2;
1615 if ( y )
1616 *y = y2;
1617 }
1618
1619 void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const
1620 {
1621 wxCoord xx,yy,ww,hh;
1622 DoGetClippingBox(&xx, &yy, &ww, &hh);
1623 if (x) *x = xx;
1624 if (y) *y = yy;
1625 if (w) *w = ww;
1626 if (h) *h = hh;
1627 }
1628 #endif // WXWIN_COMPATIBILITY_2_8
1629
1630
1631
1632 // ----------------------------------------------------------------------------
1633 // coordinate conversions and transforms
1634 // ----------------------------------------------------------------------------
1635
1636 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1637 {
1638 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
1639 }
1640
1641 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1642 {
1643 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
1644 }
1645
1646 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1647 {
1648 return wxRound((double)(x) / m_scaleX);
1649 }
1650
1651 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1652 {
1653 return wxRound((double)(y) / m_scaleY);
1654 }
1655
1656 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1657 {
1658 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
1659 }
1660
1661 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1662 {
1663 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
1664 }
1665
1666 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1667 {
1668 return wxRound((double)(x) * m_scaleX);
1669 }
1670
1671 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1672 {
1673 return wxRound((double)(y) * m_scaleY);
1674 }
1675
1676 void wxDCBase::ComputeScaleAndOrigin()
1677 {
1678 m_scaleX = m_logicalScaleX * m_userScaleX;
1679 m_scaleY = m_logicalScaleY * m_userScaleY;
1680 }
1681
1682 void wxDCBase::SetMapMode( int mode )
1683 {
1684 switch (mode)
1685 {
1686 case wxMM_TWIPS:
1687 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
1688 break;
1689 case wxMM_POINTS:
1690 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
1691 break;
1692 case wxMM_METRIC:
1693 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1694 break;
1695 case wxMM_LOMETRIC:
1696 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
1697 break;
1698 default:
1699 case wxMM_TEXT:
1700 SetLogicalScale( 1.0, 1.0 );
1701 break;
1702 }
1703 m_mappingMode = mode;
1704 }
1705
1706 void wxDCBase::SetUserScale( double x, double y )
1707 {
1708 // allow negative ? -> no
1709 m_userScaleX = x;
1710 m_userScaleY = y;
1711 ComputeScaleAndOrigin();
1712 }
1713
1714 void wxDCBase::SetLogicalScale( double x, double y )
1715 {
1716 // allow negative ?
1717 m_logicalScaleX = x;
1718 m_logicalScaleY = y;
1719 ComputeScaleAndOrigin();
1720 }
1721
1722 void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
1723 {
1724 m_logicalOriginX = x * m_signX;
1725 m_logicalOriginY = y * m_signY;
1726 ComputeScaleAndOrigin();
1727 }
1728
1729 void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
1730 {
1731 m_deviceOriginX = x;
1732 m_deviceOriginY = y;
1733 ComputeScaleAndOrigin();
1734 }
1735
1736 void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
1737 {
1738 m_deviceLocalOriginX = x;
1739 m_deviceLocalOriginY = y;
1740 ComputeScaleAndOrigin();
1741 }
1742
1743 void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1744 {
1745 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1746 // wxWidgets 2.9: no longer override it
1747 m_signX = (xLeftRight ? 1 : -1);
1748 m_signY = (yBottomUp ? -1 : 1);
1749 ComputeScaleAndOrigin();
1750 }
1751
1752 // ----------------------------------------------------------------------------
1753 // special symbols
1754 // ----------------------------------------------------------------------------
1755
1756 void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
1757 wxCoord width, wxCoord height)
1758 {
1759 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1760
1761 wxCoord x2 = x1 + width,
1762 y2 = y1 + height;
1763
1764 // the pen width is calibrated to give 3 for width == height == 10
1765 wxDCPenChanger pen((wxDC&)*this,
1766 wxPen(GetTextForeground(), (width + height + 1)/7));
1767
1768 // we're drawing a scaled version of wx/generic/tick.xpm here
1769 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
1770 y3 = y1 + height / 2; // y of the left tick branch
1771 DoDrawLine(x1, y3, x3, y2);
1772 DoDrawLine(x3, y2, x2, y1);
1773
1774 CalcBoundingBox(x1, y1);
1775 CalcBoundingBox(x2, y2);
1776 }
1777
1778 // ----------------------------------------------------------------------------
1779 // stubs for functions not implemented in all ports
1780 // ----------------------------------------------------------------------------
1781
1782 bool
1783 wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
1784 wxCoord dstWidth, wxCoord dstHeight,
1785 wxDC *source,
1786 wxCoord xsrc, wxCoord ysrc,
1787 wxCoord srcWidth, wxCoord srcHeight,
1788 int rop,
1789 bool useMask,
1790 wxCoord xsrcMask,
1791 wxCoord ysrcMask)
1792 {
1793 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
1794 _T("invalid blit size") );
1795
1796 // emulate the stretching by modifying the DC scale
1797 double xscale = (double)srcWidth/dstWidth,
1798 yscale = (double)srcHeight/dstHeight;
1799
1800 double xscaleOld, yscaleOld;
1801 GetUserScale(&xscaleOld, &yscaleOld);
1802 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
1803
1804 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
1805 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
1806 source,
1807 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
1808
1809 SetUserScale(xscaleOld, yscaleOld);
1810
1811 return rc;
1812 }
1813
1814 // ----------------------------------------------------------------------------
1815 // line/polygons
1816 // ----------------------------------------------------------------------------
1817
1818 void wxDCBase::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
1819 {
1820 unsigned int n = list->GetCount();
1821 wxPoint *points = new wxPoint[n];
1822
1823 unsigned int i = 0;
1824 wxPointList::compatibility_iterator node;
1825 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1826 {
1827 wxPoint *point = node->GetData();
1828 points[i].x = point->x;
1829 points[i].y = point->y;
1830 }
1831
1832 DoDrawLines(n, points, xoffset, yoffset);
1833
1834 delete [] points;
1835 }
1836
1837 #if WXWIN_COMPATIBILITY_2_8
1838 void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset )
1839 {
1840 unsigned int n = list->GetCount();
1841 wxPoint *points = new wxPoint[n];
1842
1843 unsigned int i = 0;
1844 wxNode *node;
1845 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1846 {
1847 wxPoint *point = (wxPoint*) node->GetData();
1848 points[i].x = point->x;
1849 points[i].y = point->y;
1850 }
1851
1852 DoDrawLines(n, points, xoffset, yoffset);
1853
1854 delete [] points;
1855 }
1856 #endif // WXWIN_COMPATIBILITY_2_8
1857
1858
1859 void wxDCBase::DrawPolygon(const wxPointList *list,
1860 wxCoord xoffset, wxCoord yoffset,
1861 int fillStyle)
1862 {
1863 unsigned int n = list->GetCount();
1864 wxPoint *points = new wxPoint[n];
1865
1866 unsigned int i = 0;
1867 wxPointList::compatibility_iterator node;
1868 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1869 {
1870 wxPoint *point = node->GetData();
1871 points[i].x = point->x;
1872 points[i].y = point->y;
1873 }
1874
1875 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1876
1877 delete [] points;
1878 }
1879
1880
1881 #if WXWIN_COMPATIBILITY_2_8
1882 void wxDCBase::DrawPolygon(const wxList *list,
1883 wxCoord xoffset, wxCoord yoffset,
1884 int fillStyle )
1885 {
1886 unsigned int n = list->GetCount();
1887 wxPoint *points = new wxPoint[n];
1888
1889 unsigned int i = 0;
1890 wxNode *node;
1891 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1892 {
1893 wxPoint *point = (wxPoint*) node->GetData();
1894 points[i].x = point->x;
1895 points[i].y = point->y;
1896 }
1897
1898 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1899
1900 delete [] points;
1901 }
1902 #endif // WXWIN_COMPATIBILITY_2_8
1903
1904 void
1905 wxDCBase::DoDrawPolyPolygon(int n,
1906 int count[],
1907 wxPoint points[],
1908 wxCoord xoffset, wxCoord yoffset,
1909 int fillStyle)
1910 {
1911 if ( n == 1 )
1912 {
1913 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
1914 return;
1915 }
1916
1917 int i, j, lastOfs;
1918 wxPoint* pts;
1919 wxPen pen;
1920
1921 for (i = j = lastOfs = 0; i < n; i++)
1922 {
1923 lastOfs = j;
1924 j += count[i];
1925 }
1926 pts = new wxPoint[j+n-1];
1927 for (i = 0; i < j; i++)
1928 pts[i] = points[i];
1929 for (i = 2; i <= n; i++)
1930 {
1931 lastOfs -= count[n-i];
1932 pts[j++] = pts[lastOfs];
1933 }
1934
1935 pen = GetPen();
1936 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
1937 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
1938 SetPen(pen);
1939 for (i = j = 0; i < n; i++)
1940 {
1941 DoDrawLines(count[i], pts+j, xoffset, yoffset);
1942 j += count[i];
1943 }
1944 delete[] pts;
1945 }
1946
1947 // ----------------------------------------------------------------------------
1948 // splines
1949 // ----------------------------------------------------------------------------
1950
1951 #if wxUSE_SPLINES
1952
1953 void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
1954 {
1955 wxPointList point_list;
1956
1957 wxPoint *point1 = new wxPoint;
1958 point1->x = x1; point1->y = y1;
1959 point_list.Append( point1 );
1960
1961 wxPoint *point2 = new wxPoint;
1962 point2->x = x2; point2->y = y2;
1963 point_list.Append( point2 );
1964
1965 wxPoint *point3 = new wxPoint;
1966 point3->x = x3; point3->y = y3;
1967 point_list.Append( point3 );
1968
1969 DrawSpline(&point_list);
1970
1971 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
1972 {
1973 wxPoint *p = node->GetData();
1974 delete p;
1975 }
1976 }
1977
1978 void wxDCBase::DrawSpline(int n, wxPoint points[])
1979 {
1980 wxPointList list;
1981 for (int i =0; i < n; i++)
1982 list.Append( &points[i] );
1983
1984 DrawSpline(&list);
1985 }
1986
1987 // ----------------------------------- spline code ----------------------------------------
1988
1989 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1990 double a3, double b3, double a4, double b4);
1991 void wx_clear_stack();
1992 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1993 double *y3, double *x4, double *y4);
1994 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1995 double x4, double y4);
1996 static bool wx_spline_add_point(double x, double y);
1997 static void wx_spline_draw_point_array(wxDCBase *dc);
1998
1999 wxPointList wx_spline_point_list;
2000
2001 #define half(z1, z2) ((z1+z2)/2.0)
2002 #define THRESHOLD 5
2003
2004 /* iterative version */
2005
2006 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
2007 double b4)
2008 {
2009 register double xmid, ymid;
2010 double x1, y1, x2, y2, x3, y3, x4, y4;
2011
2012 wx_clear_stack();
2013 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
2014
2015 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
2016 xmid = (double)half(x2, x3);
2017 ymid = (double)half(y2, y3);
2018 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
2019 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
2020 wx_spline_add_point( x1, y1 );
2021 wx_spline_add_point( xmid, ymid );
2022 } else {
2023 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
2024 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
2025 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
2026 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
2027 }
2028 }
2029 }
2030
2031 /* utilities used by spline drawing routines */
2032
2033 typedef struct wx_spline_stack_struct {
2034 double x1, y1, x2, y2, x3, y3, x4, y4;
2035 } Stack;
2036
2037 #define SPLINE_STACK_DEPTH 20
2038 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
2039 static Stack *wx_stack_top;
2040 static int wx_stack_count;
2041
2042 void wx_clear_stack()
2043 {
2044 wx_stack_top = wx_spline_stack;
2045 wx_stack_count = 0;
2046 }
2047
2048 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
2049 {
2050 wx_stack_top->x1 = x1;
2051 wx_stack_top->y1 = y1;
2052 wx_stack_top->x2 = x2;
2053 wx_stack_top->y2 = y2;
2054 wx_stack_top->x3 = x3;
2055 wx_stack_top->y3 = y3;
2056 wx_stack_top->x4 = x4;
2057 wx_stack_top->y4 = y4;
2058 wx_stack_top++;
2059 wx_stack_count++;
2060 }
2061
2062 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
2063 double *x3, double *y3, double *x4, double *y4)
2064 {
2065 if (wx_stack_count == 0)
2066 return (0);
2067 wx_stack_top--;
2068 wx_stack_count--;
2069 *x1 = wx_stack_top->x1;
2070 *y1 = wx_stack_top->y1;
2071 *x2 = wx_stack_top->x2;
2072 *y2 = wx_stack_top->y2;
2073 *x3 = wx_stack_top->x3;
2074 *y3 = wx_stack_top->y3;
2075 *x4 = wx_stack_top->x4;
2076 *y4 = wx_stack_top->y4;
2077 return (1);
2078 }
2079
2080 static bool wx_spline_add_point(double x, double y)
2081 {
2082 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
2083 wx_spline_point_list.Append( point );
2084 return true;
2085 }
2086
2087 static void wx_spline_draw_point_array(wxDCBase *dc)
2088 {
2089 dc->DrawLines(&wx_spline_point_list, 0, 0 );
2090 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
2091 while (node)
2092 {
2093 wxPoint *point = node->GetData();
2094 delete point;
2095 wx_spline_point_list.Erase(node);
2096 node = wx_spline_point_list.GetFirst();
2097 }
2098 }
2099
2100 #if WXWIN_COMPATIBILITY_2_8
2101 void wxDCBase::DrawSpline(const wxList *points)
2102 {
2103 wxPointList list;
2104 wxNode *node = points->GetFirst();
2105 while (node)
2106 {
2107 list.Append( (wxPoint*) node->GetData() );
2108 node = node->GetNext();
2109 }
2110 DoDrawSpline( &list );
2111 }
2112 #endif // WXWIN_COMPATIBILITY_2_8
2113
2114 void wxDCBase::DoDrawSpline( const wxPointList *points )
2115 {
2116 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2117
2118 wxPoint *p;
2119 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2120 double x1, y1, x2, y2;
2121
2122 wxPointList::compatibility_iterator node = points->GetFirst();
2123 if (!node)
2124 // empty list
2125 return;
2126
2127 p = node->GetData();
2128
2129 x1 = p->x;
2130 y1 = p->y;
2131
2132 node = node->GetNext();
2133 p = node->GetData();
2134
2135 x2 = p->x;
2136 y2 = p->y;
2137 cx1 = (double)((x1 + x2) / 2);
2138 cy1 = (double)((y1 + y2) / 2);
2139 cx2 = (double)((cx1 + x2) / 2);
2140 cy2 = (double)((cy1 + y2) / 2);
2141
2142 wx_spline_add_point(x1, y1);
2143
2144 while ((node = node->GetNext())
2145 #if !wxUSE_STL
2146 != NULL
2147 #endif // !wxUSE_STL
2148 )
2149 {
2150 p = node->GetData();
2151 x1 = x2;
2152 y1 = y2;
2153 x2 = p->x;
2154 y2 = p->y;
2155 cx4 = (double)(x1 + x2) / 2;
2156 cy4 = (double)(y1 + y2) / 2;
2157 cx3 = (double)(x1 + cx4) / 2;
2158 cy3 = (double)(y1 + cy4) / 2;
2159
2160 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
2161
2162 cx1 = cx4;
2163 cy1 = cy4;
2164 cx2 = (double)(cx1 + x2) / 2;
2165 cy2 = (double)(cy1 + y2) / 2;
2166 }
2167
2168 wx_spline_add_point( cx1, cy1 );
2169 wx_spline_add_point( x2, y2 );
2170
2171 wx_spline_draw_point_array( this );
2172 }
2173
2174 #endif // wxUSE_SPLINES
2175
2176 // ----------------------------------------------------------------------------
2177 // Partial Text Extents
2178 // ----------------------------------------------------------------------------
2179
2180
2181 // Each element of the widths array will be the width of the string up to and
2182 // including the corresponding character in text. This is the generic
2183 // implementation, the port-specific classes should do this with native APIs
2184 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2185 // than calling GetTextExtent!!
2186
2187 #define FWC_SIZE 256
2188
2189 class FontWidthCache
2190 {
2191 public:
2192 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
2193 ~FontWidthCache() { delete []m_widths; }
2194
2195 void Reset()
2196 {
2197 if (!m_widths)
2198 m_widths = new int[FWC_SIZE];
2199
2200 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
2201 }
2202
2203 wxFont m_font;
2204 double m_scaleX;
2205 int *m_widths;
2206 };
2207
2208 static FontWidthCache s_fontWidthCache;
2209
2210 bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2211 {
2212 int totalWidth = 0;
2213
2214 const size_t len = text.length();
2215 widths.Empty();
2216 widths.Add(0, len);
2217
2218 // reset the cache if font or horizontal scale have changed
2219 if ( !s_fontWidthCache.m_widths ||
2220 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
2221 (s_fontWidthCache.m_font != GetFont()) )
2222 {
2223 s_fontWidthCache.Reset();
2224 s_fontWidthCache.m_font = GetFont();
2225 s_fontWidthCache.m_scaleX = m_scaleX;
2226 }
2227
2228 // Calculate the position of each character based on the widths of
2229 // the previous characters
2230 int w, h;
2231 for ( size_t i = 0; i < len; i++ )
2232 {
2233 const wxChar c = text[i];
2234 unsigned int c_int = (unsigned int)c;
2235
2236 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
2237 {
2238 w = s_fontWidthCache.m_widths[c_int];
2239 }
2240 else
2241 {
2242 GetTextExtent(c, &w, &h);
2243 if (c_int < FWC_SIZE)
2244 s_fontWidthCache.m_widths[c_int] = w;
2245 }
2246
2247 totalWidth += w;
2248 widths[i] = totalWidth;
2249 }
2250
2251 return true;
2252 }
2253
2254
2255 // ----------------------------------------------------------------------------
2256 // enhanced text drawing
2257 // ----------------------------------------------------------------------------
2258
2259 void wxDCBase::GetMultiLineTextExtent(const wxString& text,
2260 wxCoord *x,
2261 wxCoord *y,
2262 wxCoord *h,
2263 const wxFont *font) const
2264 {
2265 wxCoord widthTextMax = 0, widthLine,
2266 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
2267
2268 wxString curLine;
2269 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2270 {
2271 if ( pc == text.end() || *pc == _T('\n') )
2272 {
2273 if ( curLine.empty() )
2274 {
2275 // we can't use GetTextExtent - it will return 0 for both width
2276 // and height and an empty line should count in height
2277 // calculation
2278
2279 // assume that this line has the same height as the previous
2280 // one
2281 if ( !heightLineDefault )
2282 heightLineDefault = heightLine;
2283
2284 if ( !heightLineDefault )
2285 {
2286 // but we don't know it yet - choose something reasonable
2287 GetTextExtent(_T("W"), NULL, &heightLineDefault,
2288 NULL, NULL, font);
2289 }
2290
2291 heightTextTotal += heightLineDefault;
2292 }
2293 else
2294 {
2295 GetTextExtent(curLine, &widthLine, &heightLine,
2296 NULL, NULL, font);
2297 if ( widthLine > widthTextMax )
2298 widthTextMax = widthLine;
2299 heightTextTotal += heightLine;
2300 }
2301
2302 if ( pc == text.end() )
2303 {
2304 break;
2305 }
2306 else // '\n'
2307 {
2308 curLine.clear();
2309 }
2310 }
2311 else
2312 {
2313 curLine += *pc;
2314 }
2315 }
2316
2317 if ( x )
2318 *x = widthTextMax;
2319 if ( y )
2320 *y = heightTextTotal;
2321 if ( h )
2322 *h = heightLine;
2323 }
2324
2325 void wxDCBase::DrawLabel(const wxString& text,
2326 const wxBitmap& bitmap,
2327 const wxRect& rect,
2328 int alignment,
2329 int indexAccel,
2330 wxRect *rectBounding)
2331 {
2332 // find the text position
2333 wxCoord widthText, heightText, heightLine;
2334 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
2335
2336 wxCoord width, height;
2337 if ( bitmap.Ok() )
2338 {
2339 width = widthText + bitmap.GetWidth();
2340 height = bitmap.GetHeight();
2341 }
2342 else // no bitmap
2343 {
2344 width = widthText;
2345 height = heightText;
2346 }
2347
2348 wxCoord x, y;
2349 if ( alignment & wxALIGN_RIGHT )
2350 {
2351 x = rect.GetRight() - width;
2352 }
2353 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2354 {
2355 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
2356 }
2357 else // alignment & wxALIGN_LEFT
2358 {
2359 x = rect.GetLeft();
2360 }
2361
2362 if ( alignment & wxALIGN_BOTTOM )
2363 {
2364 y = rect.GetBottom() - height;
2365 }
2366 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
2367 {
2368 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
2369 }
2370 else // alignment & wxALIGN_TOP
2371 {
2372 y = rect.GetTop();
2373 }
2374
2375 // draw the bitmap first
2376 wxCoord x0 = x,
2377 y0 = y,
2378 width0 = width;
2379 if ( bitmap.Ok() )
2380 {
2381 DrawBitmap(bitmap, x, y, true /* use mask */);
2382
2383 wxCoord offset = bitmap.GetWidth() + 4;
2384 x += offset;
2385 width -= offset;
2386
2387 y += (height - heightText) / 2;
2388 }
2389
2390 // we will draw the underscore under the accel char later
2391 wxCoord startUnderscore = 0,
2392 endUnderscore = 0,
2393 yUnderscore = 0;
2394
2395 // split the string into lines and draw each of them separately
2396 wxString curLine;
2397 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2398 {
2399 if ( pc == text.end() || *pc == _T('\n') )
2400 {
2401 int xRealStart = x; // init it here to avoid compielr warnings
2402
2403 if ( !curLine.empty() )
2404 {
2405 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2406 // wxALIGN_LEFT is 0
2407 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
2408 {
2409 wxCoord widthLine;
2410 GetTextExtent(curLine, &widthLine, NULL);
2411
2412 if ( alignment & wxALIGN_RIGHT )
2413 {
2414 xRealStart += width - widthLine;
2415 }
2416 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2417 {
2418 xRealStart += (width - widthLine) / 2;
2419 }
2420 }
2421 //else: left aligned, nothing to do
2422
2423 DrawText(curLine, xRealStart, y);
2424 }
2425
2426 y += heightLine;
2427
2428 // do we have underscore in this line? we can check yUnderscore
2429 // because it is set below to just y + heightLine if we do
2430 if ( y == yUnderscore )
2431 {
2432 // adjust the horz positions to account for the shift
2433 startUnderscore += xRealStart;
2434 endUnderscore += xRealStart;
2435 }
2436
2437 if ( pc == text.end() )
2438 break;
2439
2440 curLine.clear();
2441 }
2442 else // not end of line
2443 {
2444 if ( pc - text.begin() == indexAccel )
2445 {
2446 // remeber to draw underscore here
2447 GetTextExtent(curLine, &startUnderscore, NULL);
2448 curLine += *pc;
2449 GetTextExtent(curLine, &endUnderscore, NULL);
2450
2451 yUnderscore = y + heightLine;
2452 }
2453 else
2454 {
2455 curLine += *pc;
2456 }
2457 }
2458 }
2459
2460 // draw the underscore if found
2461 if ( startUnderscore != endUnderscore )
2462 {
2463 // it should be of the same colour as text
2464 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
2465
2466 yUnderscore--;
2467
2468 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
2469 }
2470
2471 // return bounding rect if requested
2472 if ( rectBounding )
2473 {
2474 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
2475 }
2476
2477 CalcBoundingBox(x0, y0);
2478 CalcBoundingBox(x0 + width0, y0 + height);
2479 }
2480
2481
2482 void wxDCBase::DoGradientFillLinear(const wxRect& rect,
2483 const wxColour& initialColour,
2484 const wxColour& destColour,
2485 wxDirection nDirection)
2486 {
2487 // save old pen
2488 wxPen oldPen = m_pen;
2489 wxBrush oldBrush = m_brush;
2490
2491 wxUint8 nR1 = initialColour.Red();
2492 wxUint8 nG1 = initialColour.Green();
2493 wxUint8 nB1 = initialColour.Blue();
2494 wxUint8 nR2 = destColour.Red();
2495 wxUint8 nG2 = destColour.Green();
2496 wxUint8 nB2 = destColour.Blue();
2497 wxUint8 nR, nG, nB;
2498
2499 if ( nDirection == wxEAST || nDirection == wxWEST )
2500 {
2501 wxInt32 x = rect.GetWidth();
2502 wxInt32 w = x; // width of area to shade
2503 wxInt32 xDelta = w/256; // height of one shade bend
2504 if (xDelta < 1)
2505 xDelta = 1;
2506
2507 while (x >= xDelta)
2508 {
2509 x -= xDelta;
2510 if (nR1 > nR2)
2511 nR = nR1 - (nR1-nR2)*(w-x)/w;
2512 else
2513 nR = nR1 + (nR2-nR1)*(w-x)/w;
2514
2515 if (nG1 > nG2)
2516 nG = nG1 - (nG1-nG2)*(w-x)/w;
2517 else
2518 nG = nG1 + (nG2-nG1)*(w-x)/w;
2519
2520 if (nB1 > nB2)
2521 nB = nB1 - (nB1-nB2)*(w-x)/w;
2522 else
2523 nB = nB1 + (nB2-nB1)*(w-x)/w;
2524
2525 wxColour colour(nR,nG,nB);
2526 SetPen(wxPen(colour, 1, wxSOLID));
2527 SetBrush(wxBrush(colour));
2528 if(nDirection == wxEAST)
2529 DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2530 xDelta, rect.GetHeight());
2531 else //nDirection == wxWEST
2532 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
2533 xDelta, rect.GetHeight());
2534 }
2535 }
2536 else // nDirection == wxNORTH || nDirection == wxSOUTH
2537 {
2538 wxInt32 y = rect.GetHeight();
2539 wxInt32 w = y; // height of area to shade
2540 wxInt32 yDelta = w/255; // height of one shade bend
2541 if (yDelta < 1)
2542 yDelta = 1;
2543
2544 while (y > 0)
2545 {
2546 y -= yDelta;
2547 if (nR1 > nR2)
2548 nR = nR1 - (nR1-nR2)*(w-y)/w;
2549 else
2550 nR = nR1 + (nR2-nR1)*(w-y)/w;
2551
2552 if (nG1 > nG2)
2553 nG = nG1 - (nG1-nG2)*(w-y)/w;
2554 else
2555 nG = nG1 + (nG2-nG1)*(w-y)/w;
2556
2557 if (nB1 > nB2)
2558 nB = nB1 - (nB1-nB2)*(w-y)/w;
2559 else
2560 nB = nB1 + (nB2-nB1)*(w-y)/w;
2561
2562 wxColour colour(nR,nG,nB);
2563 SetPen(wxPen(colour, 1, wxSOLID));
2564 SetBrush(wxBrush(colour));
2565 if(nDirection == wxNORTH)
2566 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
2567 rect.GetWidth(), yDelta);
2568 else //nDirection == wxSOUTH
2569 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2570 rect.GetWidth(), yDelta);
2571 }
2572 }
2573
2574 SetPen(oldPen);
2575 SetBrush(oldBrush);
2576 }
2577
2578 void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
2579 const wxColour& initialColour,
2580 const wxColour& destColour,
2581 const wxPoint& circleCenter)
2582 {
2583 //save the old pen color
2584 wxColour oldPenColour = m_pen.GetColour();
2585
2586 wxUint8 nR1 = destColour.Red();
2587 wxUint8 nG1 = destColour.Green();
2588 wxUint8 nB1 = destColour.Blue();
2589 wxUint8 nR2 = initialColour.Red();
2590 wxUint8 nG2 = initialColour.Green();
2591 wxUint8 nB2 = initialColour.Blue();
2592 wxUint8 nR, nG, nB;
2593
2594
2595 //Radius
2596 wxInt32 cx = rect.GetWidth() / 2;
2597 wxInt32 cy = rect.GetHeight() / 2;
2598 wxInt32 nRadius;
2599 if (cx < cy)
2600 nRadius = cx;
2601 else
2602 nRadius = cy;
2603
2604 //Offset of circle
2605 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
2606 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
2607
2608 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
2609 {
2610 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
2611 {
2612 //get color difference
2613 wxInt32 nGradient = ((nRadius -
2614 (wxInt32)sqrt(
2615 pow((double)(x - cx - nCircleOffX), 2) +
2616 pow((double)(y - cy - nCircleOffY), 2)
2617 )) * 100) / nRadius;
2618
2619 //normalize Gradient
2620 if (nGradient < 0 )
2621 nGradient = 0;
2622
2623 //get dest colors
2624 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2625 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2626 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
2627
2628 //set the pixel
2629 m_pen.SetColour(wxColour(nR,nG,nB));
2630 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
2631 }
2632 }
2633 //return old pen color
2634 m_pen.SetColour(oldPenColour);
2635 }
2636
2637 /*
2638 Notes for wxWidgets DrawEllipticArcRot(...)
2639
2640 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2641 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2642 which are also new.
2643
2644 All methods are generic, so they can be implemented in wxDCBase.
2645 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2646 methods like (WinCE) wxDC::DoDrawArc(...).
2647
2648 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2649 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2650 parts) or every column (in steep parts) only one pixel is calculated.
2651 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2652 starting angle is not equal to the ending angle. The calculation of the
2653 pixels is done using simple arithmetic only and should perform not too
2654 bad even on devices without floating point processor. I didn't test this yet.
2655
2656 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2657 For instance: an ellipse rotated 180 degrees is drawn
2658 slightly different from the original.
2659
2660 The points are then moved to an array and used to draw a polyline and/or polygon
2661 (with center added, the pie).
2662 The result looks quite similar to the native ellipse, only e few pixels differ.
2663
2664 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2665 slower as DrawEllipse(...), which calls the native API.
2666 An rotated ellipse outside the clipping region takes nearly the same time,
2667 while an native ellipse outside takes nearly no time to draw.
2668
2669 If you draw an arc with this new method, you will see the starting and ending angles
2670 are calculated properly.
2671 If you use DrawEllipticArc(...), you will see they are only correct for circles
2672 and not properly calculated for ellipses.
2673
2674 Peter Lenhard
2675 p.lenhard@t-online.de
2676 */
2677
2678 #ifdef __WXWINCE__
2679 void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2680 wxCoord w, wxCoord h,
2681 double sa, double ea, double angle )
2682 {
2683 wxPointList list;
2684
2685 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
2686 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
2687
2688 // Add center (for polygon/pie)
2689 list.Append( new wxPoint( x+w/2, y+h/2 ) );
2690
2691 // copy list into array and delete list elements
2692 int n = list.GetCount();
2693 wxPoint *points = new wxPoint[n];
2694 int i = 0;
2695 wxPointList::compatibility_iterator node;
2696 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
2697 {
2698 wxPoint *point = node->GetData();
2699 points[i].x = point->x;
2700 points[i].y = point->y;
2701 delete point;
2702 }
2703
2704 // first draw the pie without pen, if necessary
2705 if( GetBrush() != *wxTRANSPARENT_BRUSH )
2706 {
2707 wxPen tempPen( GetPen() );
2708 SetPen( *wxTRANSPARENT_PEN );
2709 DoDrawPolygon( n, points, 0, 0 );
2710 SetPen( tempPen );
2711 }
2712
2713 // then draw the arc without brush, if necessary
2714 if( GetPen() != *wxTRANSPARENT_PEN )
2715 {
2716 // without center
2717 DoDrawLines( n-1, points, 0, 0 );
2718 }
2719
2720 delete [] points;
2721
2722 } // DrawEllipticArcRot
2723
2724 void wxDCBase::Rotate( wxPointList* points, double angle, wxPoint center )
2725 {
2726 if( angle != 0.0 )
2727 {
2728 double pi(M_PI);
2729 double dSinA = -sin(angle*2.0*pi/360.0);
2730 double dCosA = cos(angle*2.0*pi/360.0);
2731 wxPointList::compatibility_iterator node;
2732 for ( node = points->GetFirst(); node; node = node->GetNext() )
2733 {
2734 wxPoint* point = node->GetData();
2735
2736 // transform coordinates, if necessary
2737 if( center.x ) point->x -= center.x;
2738 if( center.y ) point->y -= center.y;
2739
2740 // calculate rotation, rounding simply by implicit cast to integer
2741 int xTemp = point->x * dCosA - point->y * dSinA;
2742 point->y = point->x * dSinA + point->y * dCosA;
2743 point->x = xTemp;
2744
2745 // back transform coordinates, if necessary
2746 if( center.x ) point->x += center.x;
2747 if( center.y ) point->y += center.y;
2748 }
2749 }
2750 }
2751
2752 void wxDCBase::CalculateEllipticPoints( wxPointList* points,
2753 wxCoord xStart, wxCoord yStart,
2754 wxCoord w, wxCoord h,
2755 double sa, double ea )
2756 {
2757 double pi = M_PI;
2758 double sar = 0;
2759 double ear = 0;
2760 int xsa = 0;
2761 int ysa = 0;
2762 int xea = 0;
2763 int yea = 0;
2764 int sq = 0;
2765 int eq = 0;
2766 bool bUseAngles = false;
2767 if( w<0 ) w = -w;
2768 if( h<0 ) h = -h;
2769 // half-axes
2770 wxCoord a = w/2;
2771 wxCoord b = h/2;
2772 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2773 int decrX = 0;
2774 if( 2*a == w ) decrX = 1;
2775 int decrY = 0;
2776 if( 2*b == h ) decrY = 1;
2777 // center
2778 wxCoord xCenter = xStart + a;
2779 wxCoord yCenter = yStart + b;
2780 // calculate data for start and end, if necessary
2781 if( sa != ea )
2782 {
2783 bUseAngles = true;
2784 // normalisation of angles
2785 while( sa<0 ) sa += 360;
2786 while( ea<0 ) ea += 360;
2787 while( sa>=360 ) sa -= 360;
2788 while( ea>=360 ) ea -= 360;
2789 // calculate quadrant numbers
2790 if( sa > 270 ) sq = 3;
2791 else if( sa > 180 ) sq = 2;
2792 else if( sa > 90 ) sq = 1;
2793 if( ea > 270 ) eq = 3;
2794 else if( ea > 180 ) eq = 2;
2795 else if( ea > 90 ) eq = 1;
2796 sar = sa * pi / 180.0;
2797 ear = ea * pi / 180.0;
2798 // correct angle circle -> ellipse
2799 sar = atan( -a/(double)b * tan( sar ) );
2800 if ( sq == 1 || sq == 2 ) sar += pi;
2801 ear = atan( -a/(double)b * tan( ear ) );
2802 if ( eq == 1 || eq == 2 ) ear += pi;
2803 // coordinates of points
2804 xsa = xCenter + a * cos( sar );
2805 if( sq == 0 || sq == 3 ) xsa -= decrX;
2806 ysa = yCenter + b * sin( sar );
2807 if( sq == 2 || sq == 3 ) ysa -= decrY;
2808 xea = xCenter + a * cos( ear );
2809 if( eq == 0 || eq == 3 ) xea -= decrX;
2810 yea = yCenter + b * sin( ear );
2811 if( eq == 2 || eq == 3 ) yea -= decrY;
2812 } // if iUseAngles
2813 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2814 double c1 = b * b;
2815 double c2 = 2.0 / w;
2816 c2 *= c2;
2817 c2 *= c1;
2818 wxCoord x = 0;
2819 wxCoord y = b;
2820 long x2 = 1;
2821 long y2 = y*y;
2822 long y2_old = 0;
2823 long y_old = 0;
2824 // Lists for quadrant 1 to 4
2825 wxPointList pointsarray[4];
2826 // Calculate points for first quadrant and set in all quadrants
2827 for( x = 0; x <= a; ++x )
2828 {
2829 x2 = x2+x+x-1;
2830 y2_old = y2;
2831 y_old = y;
2832 bool bNewPoint = false;
2833 while( y2 > c1 - c2 * x2 && y > 0 )
2834 {
2835 bNewPoint = true;
2836 y2 = y2-y-y+1;
2837 --y;
2838 }
2839 // old y now to big: set point with old y, old x
2840 if( bNewPoint && x>1)
2841 {
2842 int x1 = x - 1;
2843 // remove points on the same line
2844 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
2845 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
2846 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
2847 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
2848 } // set point
2849 } // calculate point
2850
2851 // Starting and/or ending points for the quadrants, first quadrant gets both.
2852 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
2853 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
2854 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
2855 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
2856 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
2857
2858 // copy quadrants in original list
2859 if( bUseAngles )
2860 {
2861 // Copy the right part of the points in the lists
2862 // and delete the wxPoints, because they do not leave this method.
2863 points->Append( new wxPoint( xsa, ysa ) );
2864 int q = sq;
2865 bool bStarted = false;
2866 bool bReady = false;
2867 bool bForceTurn = ( sq == eq && sa > ea );
2868 while( !bReady )
2869 {
2870 wxPointList::compatibility_iterator node;
2871 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
2872 {
2873 // once: go to starting point in start quadrant
2874 if( !bStarted &&
2875 (
2876 node->GetData()->x < xsa+1 && q <= 1
2877 ||
2878 node->GetData()->x > xsa-1 && q >= 2
2879 )
2880 )
2881 {
2882 bStarted = true;
2883 }
2884
2885 // copy point, if not at ending point
2886 if( bStarted )
2887 {
2888 if( q != eq || bForceTurn
2889 ||
2890 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2891 ||
2892 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
2893 )
2894 {
2895 // copy point
2896 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
2897 points->Append( pPoint );
2898 }
2899 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
2900 {
2901 bReady = true;
2902 }
2903 }
2904 } // for node
2905 ++q;
2906 if( q > 3 ) q = 0;
2907 bForceTurn = false;
2908 bStarted = true;
2909 } // while not bReady
2910 points->Append( new wxPoint( xea, yea ) );
2911
2912 // delete points
2913 for( q = 0; q < 4; ++q )
2914 {
2915 wxPointList::compatibility_iterator node;
2916 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
2917 {
2918 wxPoint *p = node->GetData();
2919 delete p;
2920 }
2921 }
2922 }
2923 else
2924 {
2925 wxPointList::compatibility_iterator node;
2926 // copy whole ellipse, wxPoints will be deleted outside
2927 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
2928 {
2929 wxPoint *p = node->GetData();
2930 points->Append( p );
2931 }
2932 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
2933 {
2934 wxPoint *p = node->GetData();
2935 points->Append( p );
2936 }
2937 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
2938 {
2939 wxPoint *p = node->GetData();
2940 points->Append( p );
2941 }
2942 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
2943 {
2944 wxPoint *p = node->GetData();
2945 points->Append( p );
2946 }
2947 } // not iUseAngles
2948 } // CalculateEllipticPoints
2949
2950 #endif // __WXWINCE__
2951
2952 #endif // wxUSE_NEW_DC