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