]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcbase.cpp
forward port of fix
[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/prntbase.h"
33
34 #ifndef WX_PRECOMP
35 #include "wx/math.h"
36 #include "wx/module.h"
37 #endif
38
39 #ifdef __WXMSW__
40 #include "wx/msw/dcclient.h"
41 #include "wx/msw/dcmemory.h"
42 #include "wx/msw/dcscreen.h"
43 #endif
44
45 #ifdef __WXGTK20__
46 #include "wx/gtk/dcclient.h"
47 #include "wx/gtk/dcmemory.h"
48 #include "wx/gtk/dcscreen.h"
49 #elif defined(__WXGTK__)
50 #include "wx/gtk1/dcclient.h"
51 #include "wx/gtk1/dcmemory.h"
52 #include "wx/gtk1/dcscreen.h"
53 #endif
54
55 #ifdef __WXMAC__
56 #include "wx/mac/dcclient.h"
57 #include "wx/mac/dcmemory.h"
58 #include "wx/mac/dcscreen.h"
59 #endif
60
61 #ifdef __WXPM__
62 #include "wx/os2/dcclient.h"
63 #include "wx/os2/dcmemory.h"
64 #include "wx/os2/dcscreen.h"
65 #endif
66
67 #ifdef __WXCOCOA__
68 #include "wx/cocoa/dcclient.h"
69 #include "wx/cocoa/dcmemory.h"
70 #include "wx/cocoa/dcscreen.h"
71 #endif
72
73 #ifdef __WXMOTIF__
74 #include "wx/motif/dcclient.h"
75 #include "wx/motif/dcmemory.h"
76 #include "wx/motif/dcscreen.h"
77 #endif
78
79 #ifdef __WXX11__
80 #include "wx/x11/dcclient.h"
81 #include "wx/x11/dcmemory.h"
82 #include "wx/x11/dcscreen.h"
83 #endif
84
85 #ifdef __WXDFB__
86 #include "wx/dfb/dcclient.h"
87 #include "wx/dfb/dcmemory.h"
88 #include "wx/dfb/dcscreen.h"
89 #endif
90
91 #ifdef __WXPALMOS__
92 #include "wx/palmos/dcclient.h"
93 #include "wx/palmos/dcmemory.h"
94 #include "wx/palmos/dcscreen.h"
95 #endif
96
97 //----------------------------------------------------------------------------
98 // wxDCFactory
99 //----------------------------------------------------------------------------
100
101 wxDCFactory *wxDCFactory::m_factory = NULL;
102
103 void wxDCFactory::Set(wxDCFactory *factory)
104 {
105 delete m_factory;
106
107 m_factory = factory;
108 }
109
110 wxDCFactory *wxDCFactory::Get()
111 {
112 if ( !m_factory )
113 m_factory = new wxNativeDCFactory;
114
115 return m_factory;
116 }
117
118 class wxDCFactoryCleanupModule : public wxModule
119 {
120 public:
121 virtual bool OnInit() { return true; }
122 virtual void OnExit() { wxDCFactory::Set(NULL); }
123
124 private:
125 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule)
126 };
127
128 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule)
129
130 //-----------------------------------------------------------------------------
131 // wxNativeDCFactory
132 //-----------------------------------------------------------------------------
133
134 wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
135 {
136 return new wxWindowDCImpl( owner );
137 }
138
139 wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
140 {
141 return new wxWindowDCImpl( owner, window );
142 }
143
144 wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
145 {
146 return new wxClientDCImpl( owner );
147 }
148
149 wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
150 {
151 return new wxClientDCImpl( owner, window );
152 }
153
154 wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
155 {
156 return new wxPaintDCImpl( owner );
157 }
158
159 wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
160 {
161 return new wxPaintDCImpl( owner, window );
162 }
163
164 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
165 {
166 return new wxMemoryDCImpl( owner );
167 }
168
169 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
170 {
171 return new wxMemoryDCImpl( owner, bitmap );
172 }
173
174 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
175 {
176 return new wxMemoryDCImpl( owner, dc );
177 }
178
179 wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
180 {
181 return new wxScreenDCImpl( owner );
182 }
183
184 #if wxUSE_PRINTING_ARCHITECTURE
185 wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
186 {
187 wxPrintFactory *factory = wxPrintFactory::GetFactory();
188 return factory->CreatePrinterDCImpl( owner, data );
189 }
190 #endif
191
192 //-----------------------------------------------------------------------------
193 // wxWindowDC
194 //-----------------------------------------------------------------------------
195
196 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC)
197
198 wxWindowDC::wxWindowDC(wxWindow *win)
199 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win))
200 {
201 }
202
203 //-----------------------------------------------------------------------------
204 // wxClientDC
205 //-----------------------------------------------------------------------------
206
207 IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC)
208
209 wxClientDC::wxClientDC(wxWindow *win)
210 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win))
211 {
212 }
213
214 //-----------------------------------------------------------------------------
215 // wxMemoryDC
216 //-----------------------------------------------------------------------------
217
218 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
219
220 wxMemoryDC::wxMemoryDC()
221 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
222 {
223 }
224
225 wxMemoryDC::wxMemoryDC(wxBitmap& bitmap)
226 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap))
227 {
228 }
229
230 wxMemoryDC::wxMemoryDC(wxDC *dc)
231 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc))
232 {
233 }
234
235 void wxMemoryDC::SelectObject(wxBitmap& bmp)
236 {
237 // make sure that the given wxBitmap is not sharing its data with other
238 // wxBitmap instances as its contents will be modified by any drawing
239 // operation done on this DC
240 if (bmp.IsOk())
241 bmp.UnShare();
242
243 GetImpl()->DoSelect(bmp);
244 }
245
246 void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
247 {
248 GetImpl()->DoSelect(bmp);
249 }
250
251 const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
252 {
253 return GetImpl()->GetSelectedBitmap();
254 }
255
256 wxBitmap& wxMemoryDC::GetSelectedBitmap()
257 {
258 return GetImpl()->GetSelectedBitmap();
259 }
260
261
262 //-----------------------------------------------------------------------------
263 // wxPaintDC
264 //-----------------------------------------------------------------------------
265
266 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC)
267
268 wxPaintDC::wxPaintDC(wxWindow *win)
269 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win))
270 {
271 }
272
273 //-----------------------------------------------------------------------------
274 // wxScreenDC
275 //-----------------------------------------------------------------------------
276
277 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
278
279 wxScreenDC::wxScreenDC()
280 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
281 {
282 }
283
284 //-----------------------------------------------------------------------------
285 // wxPrinterDC
286 //-----------------------------------------------------------------------------
287
288 #if wxUSE_PRINTING_ARCHITECTURE
289
290 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
291
292 wxPrinterDC::wxPrinterDC()
293 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
294 {
295 }
296
297 wxPrinterDC::wxPrinterDC(const wxPrintData& data)
298 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data))
299 {
300 }
301
302 wxRect wxPrinterDC::GetPaperRect()
303 {
304 return GetImpl()->GetPaperRect();
305 }
306
307 int wxPrinterDC::GetResolution()
308 {
309 return GetImpl()->GetResolution();
310 }
311
312 #endif // wxUSE_PRINTING_ARCHITECTURE
313
314 //-----------------------------------------------------------------------------
315 // wxDCImpl
316 //-----------------------------------------------------------------------------
317
318 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
319
320 wxDCImpl::wxDCImpl( wxDC *owner )
321 : m_window(NULL)
322 , m_colour(wxColourDisplay())
323 , m_ok(true)
324 , m_clipping(false)
325 , m_isInteractive(0)
326 , m_isBBoxValid(false)
327 , m_logicalOriginX(0), m_logicalOriginY(0)
328 , m_deviceOriginX(0), m_deviceOriginY(0)
329 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
330 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
331 , m_userScaleX(1.0), m_userScaleY(1.0)
332 , m_scaleX(1.0), m_scaleY(1.0)
333 , m_signX(1), m_signY(1)
334 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
335 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
336 , m_logicalFunction(wxCOPY)
337 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT)
338 , m_mappingMode(wxMM_TEXT)
339 , m_pen()
340 , m_brush()
341 , m_backgroundBrush()
342 , m_textForegroundColour(*wxBLACK)
343 , m_textBackgroundColour(*wxWHITE)
344 , m_font()
345 #if wxUSE_PALETTE
346 , m_palette()
347 , m_hasCustomPalette(false)
348 #endif // wxUSE_PALETTE
349 {
350 m_owner = owner;
351
352 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
353 (double)wxGetDisplaySizeMM().GetWidth();
354 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
355 (double)wxGetDisplaySizeMM().GetHeight();
356
357 ResetBoundingBox();
358 ResetClipping();
359 }
360
361 wxDCImpl::~wxDCImpl()
362 {
363 }
364
365 // ----------------------------------------------------------------------------
366 // coordinate conversions and transforms
367 // ----------------------------------------------------------------------------
368
369 wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
370 {
371 return wxRound( (double)((x - m_deviceOriginX - m_deviceLocalOriginX) * m_signX) / m_scaleX ) + m_logicalOriginX ;
372 }
373
374 wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
375 {
376 return wxRound( (double)((y - m_deviceOriginY - m_deviceLocalOriginY) * m_signY) / m_scaleY ) + m_logicalOriginY ;
377 }
378
379 wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
380 {
381 return wxRound((double)(x) / m_scaleX);
382 }
383
384 wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
385 {
386 return wxRound((double)(y) / m_scaleY);
387 }
388
389 wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
390 {
391 return wxRound( (double)((x - m_logicalOriginX) * m_signX) * m_scaleX) + m_deviceOriginX + m_deviceLocalOriginX;
392 }
393
394 wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
395 {
396 return wxRound( (double)((y - m_logicalOriginY) * m_signY) * m_scaleY) + m_deviceOriginY + m_deviceLocalOriginY;
397 }
398
399 wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
400 {
401 return wxRound((double)(x) * m_scaleX);
402 }
403
404 wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
405 {
406 return wxRound((double)(y) * m_scaleY);
407 }
408
409 void wxDCImpl::ComputeScaleAndOrigin()
410 {
411 m_scaleX = m_logicalScaleX * m_userScaleX;
412 m_scaleY = m_logicalScaleY * m_userScaleY;
413 }
414
415 void wxDCImpl::SetMapMode( int mode )
416 {
417 switch (mode)
418 {
419 case wxMM_TWIPS:
420 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
421 break;
422 case wxMM_POINTS:
423 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
424 break;
425 case wxMM_METRIC:
426 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
427 break;
428 case wxMM_LOMETRIC:
429 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
430 break;
431 default:
432 case wxMM_TEXT:
433 SetLogicalScale( 1.0, 1.0 );
434 break;
435 }
436 m_mappingMode = mode;
437 }
438
439 void wxDCImpl::SetUserScale( double x, double y )
440 {
441 // allow negative ? -> no
442 m_userScaleX = x;
443 m_userScaleY = y;
444 ComputeScaleAndOrigin();
445 }
446
447 void wxDCImpl::SetLogicalScale( double x, double y )
448 {
449 // allow negative ?
450 m_logicalScaleX = x;
451 m_logicalScaleY = y;
452 ComputeScaleAndOrigin();
453 }
454
455 void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
456 {
457 m_logicalOriginX = x * m_signX;
458 m_logicalOriginY = y * m_signY;
459 ComputeScaleAndOrigin();
460 }
461
462 void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
463 {
464 m_deviceOriginX = x;
465 m_deviceOriginY = y;
466 ComputeScaleAndOrigin();
467 }
468
469 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
470 {
471 m_deviceLocalOriginX = x;
472 m_deviceLocalOriginY = y;
473 ComputeScaleAndOrigin();
474 }
475
476 void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
477 {
478 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
479 // wxWidgets 2.9: no longer override it
480 m_signX = (xLeftRight ? 1 : -1);
481 m_signY = (yBottomUp ? -1 : 1);
482 ComputeScaleAndOrigin();
483 }
484
485
486 // Each element of the widths array will be the width of the string up to and
487 // including the corresponding character in text. This is the generic
488 // implementation, the port-specific classes should do this with native APIs
489 // if available and if faster. Note: pango_layout_index_to_pos is much slower
490 // than calling GetTextExtent!!
491
492 #define FWC_SIZE 256
493
494 class FontWidthCache
495 {
496 public:
497 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
498 ~FontWidthCache() { delete []m_widths; }
499
500 void Reset()
501 {
502 if (!m_widths)
503 m_widths = new int[FWC_SIZE];
504
505 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
506 }
507
508 wxFont m_font;
509 double m_scaleX;
510 int *m_widths;
511 };
512
513 static FontWidthCache s_fontWidthCache;
514
515 bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
516 {
517 int totalWidth = 0;
518
519 const size_t len = text.length();
520 widths.Empty();
521 widths.Add(0, len);
522
523 // reset the cache if font or horizontal scale have changed
524 if ( !s_fontWidthCache.m_widths ||
525 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
526 (s_fontWidthCache.m_font != GetFont()) )
527 {
528 s_fontWidthCache.Reset();
529 s_fontWidthCache.m_font = GetFont();
530 s_fontWidthCache.m_scaleX = m_scaleX;
531 }
532
533 // Calculate the position of each character based on the widths of
534 // the previous characters
535 int w, h;
536 for ( size_t i = 0; i < len; i++ )
537 {
538 const wxChar c = text[i];
539 unsigned int c_int = (unsigned int)c;
540
541 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
542 {
543 w = s_fontWidthCache.m_widths[c_int];
544 }
545 else
546 {
547 DoGetTextExtent(c, &w, &h);
548 if (c_int < FWC_SIZE)
549 s_fontWidthCache.m_widths[c_int] = w;
550 }
551
552 totalWidth += w;
553 widths[i] = totalWidth;
554 }
555
556 return true;
557 }
558
559 void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
560 wxCoord *x,
561 wxCoord *y,
562 wxCoord *h,
563 const wxFont *font) const
564 {
565 wxCoord widthTextMax = 0, widthLine,
566 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
567
568 wxString curLine;
569 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
570 {
571 if ( pc == text.end() || *pc == _T('\n') )
572 {
573 if ( curLine.empty() )
574 {
575 // we can't use GetTextExtent - it will return 0 for both width
576 // and height and an empty line should count in height
577 // calculation
578
579 // assume that this line has the same height as the previous
580 // one
581 if ( !heightLineDefault )
582 heightLineDefault = heightLine;
583
584 if ( !heightLineDefault )
585 {
586 // but we don't know it yet - choose something reasonable
587 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
588 NULL, NULL, font);
589 }
590
591 heightTextTotal += heightLineDefault;
592 }
593 else
594 {
595 DoGetTextExtent(curLine, &widthLine, &heightLine,
596 NULL, NULL, font);
597 if ( widthLine > widthTextMax )
598 widthTextMax = widthLine;
599 heightTextTotal += heightLine;
600 }
601
602 if ( pc == text.end() )
603 {
604 break;
605 }
606 else // '\n'
607 {
608 curLine.clear();
609 }
610 }
611 else
612 {
613 curLine += *pc;
614 }
615 }
616
617 if ( x )
618 *x = widthTextMax;
619 if ( y )
620 *y = heightTextTotal;
621 if ( h )
622 *h = heightLine;
623 }
624
625 void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
626 wxCoord width, wxCoord height)
627 {
628 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
629
630 wxCoord x2 = x1 + width,
631 y2 = y1 + height;
632
633 // the pen width is calibrated to give 3 for width == height == 10
634 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
635
636 // we're drawing a scaled version of wx/generic/tick.xpm here
637 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
638 y3 = y1 + height / 2; // y of the left tick branch
639 DoDrawLine(x1, y3, x3, y2);
640 DoDrawLine(x3, y2, x2, y1);
641
642 CalcBoundingBox(x1, y1);
643 CalcBoundingBox(x2, y2);
644 }
645
646 bool
647 wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
648 wxCoord dstWidth, wxCoord dstHeight,
649 wxDC *source,
650 wxCoord xsrc, wxCoord ysrc,
651 wxCoord srcWidth, wxCoord srcHeight,
652 int rop,
653 bool useMask,
654 wxCoord xsrcMask,
655 wxCoord ysrcMask)
656 {
657 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
658 _T("invalid blit size") );
659
660 // emulate the stretching by modifying the DC scale
661 double xscale = (double)srcWidth/dstWidth,
662 yscale = (double)srcHeight/dstHeight;
663
664 double xscaleOld, yscaleOld;
665 GetUserScale(&xscaleOld, &yscaleOld);
666 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
667
668 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
669 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
670 source,
671 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
672
673 SetUserScale(xscaleOld, yscaleOld);
674
675 return rc;
676 }
677
678 void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
679 {
680 int n = list->GetCount();
681 wxPoint *points = new wxPoint[n];
682
683 int i = 0;
684 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
685 {
686 wxPoint *point = node->GetData();
687 points[i].x = point->x;
688 points[i].y = point->y;
689 }
690
691 DoDrawLines(n, points, xoffset, yoffset);
692
693 delete [] points;
694 }
695
696 void wxDCImpl::DrawPolygon(const wxPointList *list,
697 wxCoord xoffset, wxCoord yoffset,
698 int fillStyle)
699 {
700 int n = list->GetCount();
701 wxPoint *points = new wxPoint[n];
702
703 int i = 0;
704 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
705 {
706 wxPoint *point = node->GetData();
707 points[i].x = point->x;
708 points[i].y = point->y;
709 }
710
711 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
712
713 delete [] points;
714 }
715
716 void
717 wxDCImpl::DoDrawPolyPolygon(int n,
718 int count[],
719 wxPoint points[],
720 wxCoord xoffset, wxCoord yoffset,
721 int fillStyle)
722 {
723 if ( n == 1 )
724 {
725 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
726 return;
727 }
728
729 int i, j, lastOfs;
730 wxPoint* pts;
731 wxPen pen;
732
733 for (i = j = lastOfs = 0; i < n; i++)
734 {
735 lastOfs = j;
736 j += count[i];
737 }
738 pts = new wxPoint[j+n-1];
739 for (i = 0; i < j; i++)
740 pts[i] = points[i];
741 for (i = 2; i <= n; i++)
742 {
743 lastOfs -= count[n-i];
744 pts[j++] = pts[lastOfs];
745 }
746
747 pen = GetPen();
748 SetPen(wxPen(*wxBLACK, 0, wxPENSTYLE_TRANSPARENT));
749 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
750 SetPen(pen);
751 for (i = j = 0; i < n; i++)
752 {
753 DoDrawLines(count[i], pts+j, xoffset, yoffset);
754 j += count[i];
755 }
756 delete[] pts;
757 }
758
759 #if wxUSE_SPLINES
760
761 void wxDCImpl::DrawSpline(wxCoord x1, wxCoord y1,
762 wxCoord x2, wxCoord y2,
763 wxCoord x3, wxCoord y3)
764 {
765 wxPoint points[] = { wxPoint(x1, y1), wxPoint(x2, y2), wxPoint(x3, y3) };
766 DrawSpline(WXSIZEOF(points), points);
767 }
768
769 void wxDCImpl::DrawSpline(int n, wxPoint points[])
770 {
771 wxPointList list;
772 for ( int i = 0; i < n; i++ )
773 list.Append(&points[i]);
774
775 DrawSpline(&list);
776 }
777
778 // ----------------------------------- spline code ----------------------------------------
779
780 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
781 double a3, double b3, double a4, double b4);
782 void wx_clear_stack();
783 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
784 double *y3, double *x4, double *y4);
785 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
786 double x4, double y4);
787 static bool wx_spline_add_point(double x, double y);
788 static void wx_spline_draw_point_array(wxDC *dc);
789
790 wxPointList wx_spline_point_list;
791
792 #define half(z1, z2) ((z1+z2)/2.0)
793 #define THRESHOLD 5
794
795 /* iterative version */
796
797 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
798 double b4)
799 {
800 register double xmid, ymid;
801 double x1, y1, x2, y2, x3, y3, x4, y4;
802
803 wx_clear_stack();
804 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
805
806 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
807 xmid = (double)half(x2, x3);
808 ymid = (double)half(y2, y3);
809 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
810 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
811 wx_spline_add_point( x1, y1 );
812 wx_spline_add_point( xmid, ymid );
813 } else {
814 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
815 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
816 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
817 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
818 }
819 }
820 }
821
822 /* utilities used by spline drawing routines */
823
824 typedef struct wx_spline_stack_struct {
825 double x1, y1, x2, y2, x3, y3, x4, y4;
826 } Stack;
827
828 #define SPLINE_STACK_DEPTH 20
829 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
830 static Stack *wx_stack_top;
831 static int wx_stack_count;
832
833 void wx_clear_stack()
834 {
835 wx_stack_top = wx_spline_stack;
836 wx_stack_count = 0;
837 }
838
839 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
840 {
841 wx_stack_top->x1 = x1;
842 wx_stack_top->y1 = y1;
843 wx_stack_top->x2 = x2;
844 wx_stack_top->y2 = y2;
845 wx_stack_top->x3 = x3;
846 wx_stack_top->y3 = y3;
847 wx_stack_top->x4 = x4;
848 wx_stack_top->y4 = y4;
849 wx_stack_top++;
850 wx_stack_count++;
851 }
852
853 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
854 double *x3, double *y3, double *x4, double *y4)
855 {
856 if (wx_stack_count == 0)
857 return (0);
858 wx_stack_top--;
859 wx_stack_count--;
860 *x1 = wx_stack_top->x1;
861 *y1 = wx_stack_top->y1;
862 *x2 = wx_stack_top->x2;
863 *y2 = wx_stack_top->y2;
864 *x3 = wx_stack_top->x3;
865 *y3 = wx_stack_top->y3;
866 *x4 = wx_stack_top->x4;
867 *y4 = wx_stack_top->y4;
868 return (1);
869 }
870
871 static bool wx_spline_add_point(double x, double y)
872 {
873 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
874 wx_spline_point_list.Append(point );
875 return true;
876 }
877
878 static void wx_spline_draw_point_array(wxDC *dc)
879 {
880 dc->DrawLines(&wx_spline_point_list, 0, 0 );
881 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
882 while (node)
883 {
884 wxPoint *point = node->GetData();
885 delete point;
886 wx_spline_point_list.Erase(node);
887 node = wx_spline_point_list.GetFirst();
888 }
889 }
890
891 void wxDCImpl::DoDrawSpline( const wxPointList *points )
892 {
893 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
894
895 wxPoint *p;
896 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
897 double x1, y1, x2, y2;
898
899 wxPointList::compatibility_iterator node = points->GetFirst();
900 if (!node)
901 // empty list
902 return;
903
904 p = (wxPoint *)node->GetData();
905
906 x1 = p->x;
907 y1 = p->y;
908
909 node = node->GetNext();
910 p = node->GetData();
911
912 x2 = p->x;
913 y2 = p->y;
914 cx1 = (double)((x1 + x2) / 2);
915 cy1 = (double)((y1 + y2) / 2);
916 cx2 = (double)((cx1 + x2) / 2);
917 cy2 = (double)((cy1 + y2) / 2);
918
919 wx_spline_add_point(x1, y1);
920
921 while ((node = node->GetNext())
922 #if !wxUSE_STL
923 != NULL
924 #endif // !wxUSE_STL
925 )
926 {
927 p = node->GetData();
928 x1 = x2;
929 y1 = y2;
930 x2 = p->x;
931 y2 = p->y;
932 cx4 = (double)(x1 + x2) / 2;
933 cy4 = (double)(y1 + y2) / 2;
934 cx3 = (double)(x1 + cx4) / 2;
935 cy3 = (double)(y1 + cy4) / 2;
936
937 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
938
939 cx1 = cx4;
940 cy1 = cy4;
941 cx2 = (double)(cx1 + x2) / 2;
942 cy2 = (double)(cy1 + y2) / 2;
943 }
944
945 wx_spline_add_point( cx1, cy1 );
946 wx_spline_add_point( x2, y2 );
947
948 wx_spline_draw_point_array( m_owner );
949 }
950
951 #endif // wxUSE_SPLINES
952
953
954
955 void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
956 const wxColour& initialColour,
957 const wxColour& destColour,
958 wxDirection nDirection)
959 {
960 // save old pen
961 wxPen oldPen = m_pen;
962 wxBrush oldBrush = m_brush;
963
964 wxUint8 nR1 = initialColour.Red();
965 wxUint8 nG1 = initialColour.Green();
966 wxUint8 nB1 = initialColour.Blue();
967 wxUint8 nR2 = destColour.Red();
968 wxUint8 nG2 = destColour.Green();
969 wxUint8 nB2 = destColour.Blue();
970 wxUint8 nR, nG, nB;
971
972 if ( nDirection == wxEAST || nDirection == wxWEST )
973 {
974 wxInt32 x = rect.GetWidth();
975 wxInt32 w = x; // width of area to shade
976 wxInt32 xDelta = w/256; // height of one shade bend
977 if (xDelta < 1)
978 xDelta = 1;
979
980 while (x >= xDelta)
981 {
982 x -= xDelta;
983 if (nR1 > nR2)
984 nR = nR1 - (nR1-nR2)*(w-x)/w;
985 else
986 nR = nR1 + (nR2-nR1)*(w-x)/w;
987
988 if (nG1 > nG2)
989 nG = nG1 - (nG1-nG2)*(w-x)/w;
990 else
991 nG = nG1 + (nG2-nG1)*(w-x)/w;
992
993 if (nB1 > nB2)
994 nB = nB1 - (nB1-nB2)*(w-x)/w;
995 else
996 nB = nB1 + (nB2-nB1)*(w-x)/w;
997
998 wxColour colour(nR,nG,nB);
999 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
1000 SetBrush(wxBrush(colour));
1001 if(nDirection == wxEAST)
1002 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
1003 xDelta, rect.GetHeight());
1004 else //nDirection == wxWEST
1005 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1006 xDelta, rect.GetHeight());
1007 }
1008 }
1009 else // nDirection == wxNORTH || nDirection == wxSOUTH
1010 {
1011 wxInt32 y = rect.GetHeight();
1012 wxInt32 w = y; // height of area to shade
1013 wxInt32 yDelta = w/255; // height of one shade bend
1014 if (yDelta < 1)
1015 yDelta = 1;
1016
1017 while (y > 0)
1018 {
1019 y -= yDelta;
1020 if (nR1 > nR2)
1021 nR = nR1 - (nR1-nR2)*(w-y)/w;
1022 else
1023 nR = nR1 + (nR2-nR1)*(w-y)/w;
1024
1025 if (nG1 > nG2)
1026 nG = nG1 - (nG1-nG2)*(w-y)/w;
1027 else
1028 nG = nG1 + (nG2-nG1)*(w-y)/w;
1029
1030 if (nB1 > nB2)
1031 nB = nB1 - (nB1-nB2)*(w-y)/w;
1032 else
1033 nB = nB1 + (nB2-nB1)*(w-y)/w;
1034
1035 wxColour colour(nR,nG,nB);
1036 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
1037 SetBrush(wxBrush(colour));
1038 if(nDirection == wxNORTH)
1039 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1040 rect.GetWidth(), yDelta);
1041 else //nDirection == wxSOUTH
1042 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
1043 rect.GetWidth(), yDelta);
1044 }
1045 }
1046
1047 SetPen(oldPen);
1048 SetBrush(oldBrush);
1049 }
1050
1051 void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
1052 const wxColour& initialColour,
1053 const wxColour& destColour,
1054 const wxPoint& circleCenter)
1055 {
1056 //save the old pen color
1057 wxColour oldPenColour = m_pen.GetColour();
1058
1059 wxUint8 nR1 = destColour.Red();
1060 wxUint8 nG1 = destColour.Green();
1061 wxUint8 nB1 = destColour.Blue();
1062 wxUint8 nR2 = initialColour.Red();
1063 wxUint8 nG2 = initialColour.Green();
1064 wxUint8 nB2 = initialColour.Blue();
1065 wxUint8 nR, nG, nB;
1066
1067
1068 //Radius
1069 wxInt32 cx = rect.GetWidth() / 2;
1070 wxInt32 cy = rect.GetHeight() / 2;
1071 wxInt32 nRadius;
1072 if (cx < cy)
1073 nRadius = cx;
1074 else
1075 nRadius = cy;
1076
1077 //Offset of circle
1078 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1079 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1080
1081 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1082 {
1083 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1084 {
1085 //get color difference
1086 wxInt32 nGradient = ((nRadius -
1087 (wxInt32)sqrt(
1088 pow((double)(x - cx - nCircleOffX), 2) +
1089 pow((double)(y - cy - nCircleOffY), 2)
1090 )) * 100) / nRadius;
1091
1092 //normalize Gradient
1093 if (nGradient < 0 )
1094 nGradient = 0;
1095
1096 //get dest colors
1097 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1098 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1099 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1100
1101 //set the pixel
1102 m_pen.SetColour(wxColour(nR,nG,nB));
1103 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
1104 }
1105 }
1106 //return old pen color
1107 m_pen.SetColour(oldPenColour);
1108 }
1109
1110 //-----------------------------------------------------------------------------
1111 // wxDC
1112 //-----------------------------------------------------------------------------
1113
1114 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1115
1116 void wxDC::DrawLabel(const wxString& text,
1117 const wxBitmap& bitmap,
1118 const wxRect& rect,
1119 int alignment,
1120 int indexAccel,
1121 wxRect *rectBounding)
1122 {
1123 // find the text position
1124 wxCoord widthText, heightText, heightLine;
1125 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1126
1127 wxCoord width, height;
1128 if ( bitmap.Ok() )
1129 {
1130 width = widthText + bitmap.GetWidth();
1131 height = bitmap.GetHeight();
1132 }
1133 else // no bitmap
1134 {
1135 width = widthText;
1136 height = heightText;
1137 }
1138
1139 wxCoord x, y;
1140 if ( alignment & wxALIGN_RIGHT )
1141 {
1142 x = rect.GetRight() - width;
1143 }
1144 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1145 {
1146 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1147 }
1148 else // alignment & wxALIGN_LEFT
1149 {
1150 x = rect.GetLeft();
1151 }
1152
1153 if ( alignment & wxALIGN_BOTTOM )
1154 {
1155 y = rect.GetBottom() - height;
1156 }
1157 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1158 {
1159 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1160 }
1161 else // alignment & wxALIGN_TOP
1162 {
1163 y = rect.GetTop();
1164 }
1165
1166 // draw the bitmap first
1167 wxCoord x0 = x,
1168 y0 = y,
1169 width0 = width;
1170 if ( bitmap.Ok() )
1171 {
1172 DrawBitmap(bitmap, x, y, true /* use mask */);
1173
1174 wxCoord offset = bitmap.GetWidth() + 4;
1175 x += offset;
1176 width -= offset;
1177
1178 y += (height - heightText) / 2;
1179 }
1180
1181 // we will draw the underscore under the accel char later
1182 wxCoord startUnderscore = 0,
1183 endUnderscore = 0,
1184 yUnderscore = 0;
1185
1186 // split the string into lines and draw each of them separately
1187 wxString curLine;
1188 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1189 {
1190 if ( pc == text.end() || *pc == '\n' )
1191 {
1192 int xRealStart = x; // init it here to avoid compielr warnings
1193
1194 if ( !curLine.empty() )
1195 {
1196 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1197 // wxALIGN_LEFT is 0
1198 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1199 {
1200 wxCoord widthLine;
1201 GetTextExtent(curLine, &widthLine, NULL);
1202
1203 if ( alignment & wxALIGN_RIGHT )
1204 {
1205 xRealStart += width - widthLine;
1206 }
1207 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1208 {
1209 xRealStart += (width - widthLine) / 2;
1210 }
1211 }
1212 //else: left aligned, nothing to do
1213
1214 DrawText(curLine, xRealStart, y);
1215 }
1216
1217 y += heightLine;
1218
1219 // do we have underscore in this line? we can check yUnderscore
1220 // because it is set below to just y + heightLine if we do
1221 if ( y == yUnderscore )
1222 {
1223 // adjust the horz positions to account for the shift
1224 startUnderscore += xRealStart;
1225 endUnderscore += xRealStart;
1226 }
1227
1228 if ( pc == text.end() )
1229 break;
1230
1231 curLine.clear();
1232 }
1233 else // not end of line
1234 {
1235 if ( pc - text.begin() == indexAccel )
1236 {
1237 // remeber to draw underscore here
1238 GetTextExtent(curLine, &startUnderscore, NULL);
1239 curLine += *pc;
1240 GetTextExtent(curLine, &endUnderscore, NULL);
1241
1242 yUnderscore = y + heightLine;
1243 }
1244 else
1245 {
1246 curLine += *pc;
1247 }
1248 }
1249 }
1250
1251 // draw the underscore if found
1252 if ( startUnderscore != endUnderscore )
1253 {
1254 // it should be of the same colour as text
1255 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID));
1256
1257 yUnderscore--;
1258
1259 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1260 }
1261
1262 // return bounding rect if requested
1263 if ( rectBounding )
1264 {
1265 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1266 }
1267
1268 CalcBoundingBox(x0, y0);
1269 CalcBoundingBox(x0 + width0, y0 + height);
1270 }
1271
1272 #if WXWIN_COMPATIBILITY_2_8
1273 // for compatibility with the old code when wxCoord was long everywhere
1274 void wxDC::GetTextExtent(const wxString& string,
1275 long *x, long *y,
1276 long *descent,
1277 long *externalLeading,
1278 const wxFont *theFont) const
1279 {
1280 wxCoord x2, y2, descent2, externalLeading2;
1281 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1282 &descent2, &externalLeading2,
1283 theFont);
1284 if ( x )
1285 *x = x2;
1286 if ( y )
1287 *y = y2;
1288 if ( descent )
1289 *descent = descent2;
1290 if ( externalLeading )
1291 *externalLeading = externalLeading2;
1292 }
1293
1294 void wxDC::GetLogicalOrigin(long *x, long *y) const
1295 {
1296 wxCoord x2, y2;
1297 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1298 if ( x )
1299 *x = x2;
1300 if ( y )
1301 *y = y2;
1302 }
1303
1304 void wxDC::GetDeviceOrigin(long *x, long *y) const
1305 {
1306 wxCoord x2, y2;
1307 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1308 if ( x )
1309 *x = x2;
1310 if ( y )
1311 *y = y2;
1312 }
1313
1314 void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1315 {
1316 wxCoord xx,yy,ww,hh;
1317 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1318 if (x) *x = xx;
1319 if (y) *y = yy;
1320 if (w) *w = ww;
1321 if (h) *h = hh;
1322 }
1323
1324 #endif // WXWIN_COMPATIBILITY_2_8
1325
1326 /*
1327 Notes for wxWidgets DrawEllipticArcRot(...)
1328
1329 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1330 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1331 which are also new.
1332
1333 All methods are generic, so they can be implemented in wxDCBase.
1334 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1335 methods like (WinCE) wxDC::DoDrawArc(...).
1336
1337 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1338 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1339 parts) or every column (in steep parts) only one pixel is calculated.
1340 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1341 starting angle is not equal to the ending angle. The calculation of the
1342 pixels is done using simple arithmetic only and should perform not too
1343 bad even on devices without floating point processor. I didn't test this yet.
1344
1345 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1346 For instance: an ellipse rotated 180 degrees is drawn
1347 slightly different from the original.
1348
1349 The points are then moved to an array and used to draw a polyline and/or polygon
1350 (with center added, the pie).
1351 The result looks quite similar to the native ellipse, only e few pixels differ.
1352
1353 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1354 slower as DrawEllipse(...), which calls the native API.
1355 An rotated ellipse outside the clipping region takes nearly the same time,
1356 while an native ellipse outside takes nearly no time to draw.
1357
1358 If you draw an arc with this new method, you will see the starting and ending angles
1359 are calculated properly.
1360 If you use DrawEllipticArc(...), you will see they are only correct for circles
1361 and not properly calculated for ellipses.
1362
1363 Peter Lenhard
1364 p.lenhard@t-online.de
1365 */
1366
1367 #ifdef __WXWINCE__
1368 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
1369 wxCoord w, wxCoord h,
1370 double sa, double ea, double angle )
1371 {
1372 wxPointList list;
1373
1374 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
1375 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
1376
1377 // Add center (for polygon/pie)
1378 list.Append( new wxPoint( x+w/2, y+h/2 ) );
1379
1380 // copy list into array and delete list elements
1381 int n = list.GetCount();
1382 wxPoint *points = new wxPoint[n];
1383 int i = 0;
1384 wxPointList::compatibility_iterator node;
1385 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
1386 {
1387 wxPoint *point = node->GetData();
1388 points[i].x = point->x;
1389 points[i].y = point->y;
1390 delete point;
1391 }
1392
1393 // first draw the pie without pen, if necessary
1394 if( GetBrush() != *wxTRANSPARENT_BRUSH )
1395 {
1396 wxPen tempPen( GetPen() );
1397 SetPen( *wxTRANSPARENT_PEN );
1398 DoDrawPolygon( n, points, 0, 0 );
1399 SetPen( tempPen );
1400 }
1401
1402 // then draw the arc without brush, if necessary
1403 if( GetPen() != *wxTRANSPARENT_PEN )
1404 {
1405 // without center
1406 DoDrawLines( n-1, points, 0, 0 );
1407 }
1408
1409 delete [] points;
1410
1411 } // DrawEllipticArcRot
1412
1413 void wxDCImpl::Rotate( wxPointList* points, double angle, wxPoint center )
1414 {
1415 if( angle != 0.0 )
1416 {
1417 double pi(M_PI);
1418 double dSinA = -sin(angle*2.0*pi/360.0);
1419 double dCosA = cos(angle*2.0*pi/360.0);
1420 wxPointList::compatibility_iterator node;
1421 for ( node = points->GetFirst(); node; node = node->GetNext() )
1422 {
1423 wxPoint* point = node->GetData();
1424
1425 // transform coordinates, if necessary
1426 if( center.x ) point->x -= center.x;
1427 if( center.y ) point->y -= center.y;
1428
1429 // calculate rotation, rounding simply by implicit cast to integer
1430 int xTemp = point->x * dCosA - point->y * dSinA;
1431 point->y = point->x * dSinA + point->y * dCosA;
1432 point->x = xTemp;
1433
1434 // back transform coordinates, if necessary
1435 if( center.x ) point->x += center.x;
1436 if( center.y ) point->y += center.y;
1437 }
1438 }
1439 }
1440
1441 void wxDCImpl::CalculateEllipticPoints( wxPointList* points,
1442 wxCoord xStart, wxCoord yStart,
1443 wxCoord w, wxCoord h,
1444 double sa, double ea )
1445 {
1446 double pi = M_PI;
1447 double sar = 0;
1448 double ear = 0;
1449 int xsa = 0;
1450 int ysa = 0;
1451 int xea = 0;
1452 int yea = 0;
1453 int sq = 0;
1454 int eq = 0;
1455 bool bUseAngles = false;
1456 if( w<0 ) w = -w;
1457 if( h<0 ) h = -h;
1458 // half-axes
1459 wxCoord a = w/2;
1460 wxCoord b = h/2;
1461 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1462 int decrX = 0;
1463 if( 2*a == w ) decrX = 1;
1464 int decrY = 0;
1465 if( 2*b == h ) decrY = 1;
1466 // center
1467 wxCoord xCenter = xStart + a;
1468 wxCoord yCenter = yStart + b;
1469 // calculate data for start and end, if necessary
1470 if( sa != ea )
1471 {
1472 bUseAngles = true;
1473 // normalisation of angles
1474 while( sa<0 ) sa += 360;
1475 while( ea<0 ) ea += 360;
1476 while( sa>=360 ) sa -= 360;
1477 while( ea>=360 ) ea -= 360;
1478 // calculate quadrant numbers
1479 if( sa > 270 ) sq = 3;
1480 else if( sa > 180 ) sq = 2;
1481 else if( sa > 90 ) sq = 1;
1482 if( ea > 270 ) eq = 3;
1483 else if( ea > 180 ) eq = 2;
1484 else if( ea > 90 ) eq = 1;
1485 sar = sa * pi / 180.0;
1486 ear = ea * pi / 180.0;
1487 // correct angle circle -> ellipse
1488 sar = atan( -a/(double)b * tan( sar ) );
1489 if ( sq == 1 || sq == 2 ) sar += pi;
1490 ear = atan( -a/(double)b * tan( ear ) );
1491 if ( eq == 1 || eq == 2 ) ear += pi;
1492 // coordinates of points
1493 xsa = xCenter + a * cos( sar );
1494 if( sq == 0 || sq == 3 ) xsa -= decrX;
1495 ysa = yCenter + b * sin( sar );
1496 if( sq == 2 || sq == 3 ) ysa -= decrY;
1497 xea = xCenter + a * cos( ear );
1498 if( eq == 0 || eq == 3 ) xea -= decrX;
1499 yea = yCenter + b * sin( ear );
1500 if( eq == 2 || eq == 3 ) yea -= decrY;
1501 } // if iUseAngles
1502 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1503 double c1 = b * b;
1504 double c2 = 2.0 / w;
1505 c2 *= c2;
1506 c2 *= c1;
1507 wxCoord x = 0;
1508 wxCoord y = b;
1509 long x2 = 1;
1510 long y2 = y*y;
1511 long y2_old = 0;
1512 long y_old = 0;
1513 // Lists for quadrant 1 to 4
1514 wxPointList pointsarray[4];
1515 // Calculate points for first quadrant and set in all quadrants
1516 for( x = 0; x <= a; ++x )
1517 {
1518 x2 = x2+x+x-1;
1519 y2_old = y2;
1520 y_old = y;
1521 bool bNewPoint = false;
1522 while( y2 > c1 - c2 * x2 && y > 0 )
1523 {
1524 bNewPoint = true;
1525 y2 = y2-y-y+1;
1526 --y;
1527 }
1528 // old y now to big: set point with old y, old x
1529 if( bNewPoint && x>1)
1530 {
1531 int x1 = x - 1;
1532 // remove points on the same line
1533 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
1534 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
1535 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
1536 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
1537 } // set point
1538 } // calculate point
1539
1540 // Starting and/or ending points for the quadrants, first quadrant gets both.
1541 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
1542 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
1543 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
1544 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
1545 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
1546
1547 // copy quadrants in original list
1548 if( bUseAngles )
1549 {
1550 // Copy the right part of the points in the lists
1551 // and delete the wxPoints, because they do not leave this method.
1552 points->Append( new wxPoint( xsa, ysa ) );
1553 int q = sq;
1554 bool bStarted = false;
1555 bool bReady = false;
1556 bool bForceTurn = ( sq == eq && sa > ea );
1557 while( !bReady )
1558 {
1559 wxPointList::compatibility_iterator node;
1560 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1561 {
1562 // once: go to starting point in start quadrant
1563 if( !bStarted &&
1564 (
1565 node->GetData()->x < xsa+1 && q <= 1
1566 ||
1567 node->GetData()->x > xsa-1 && q >= 2
1568 )
1569 )
1570 {
1571 bStarted = true;
1572 }
1573
1574 // copy point, if not at ending point
1575 if( bStarted )
1576 {
1577 if( q != eq || bForceTurn
1578 ||
1579 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
1580 ||
1581 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
1582 )
1583 {
1584 // copy point
1585 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
1586 points->Append( pPoint );
1587 }
1588 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
1589 {
1590 bReady = true;
1591 }
1592 }
1593 } // for node
1594 ++q;
1595 if( q > 3 ) q = 0;
1596 bForceTurn = false;
1597 bStarted = true;
1598 } // while not bReady
1599 points->Append( new wxPoint( xea, yea ) );
1600
1601 // delete points
1602 for( q = 0; q < 4; ++q )
1603 {
1604 wxPointList::compatibility_iterator node;
1605 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1606 {
1607 wxPoint *p = node->GetData();
1608 delete p;
1609 }
1610 }
1611 }
1612 else
1613 {
1614 wxPointList::compatibility_iterator node;
1615 // copy whole ellipse, wxPoints will be deleted outside
1616 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
1617 {
1618 wxPoint *p = node->GetData();
1619 points->Append( p );
1620 }
1621 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
1622 {
1623 wxPoint *p = node->GetData();
1624 points->Append( p );
1625 }
1626 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
1627 {
1628 wxPoint *p = node->GetData();
1629 points->Append( p );
1630 }
1631 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
1632 {
1633 wxPoint *p = node->GetData();
1634 points->Append( p );
1635 }
1636 } // not iUseAngles
1637 } // CalculateEllipticPoints
1638
1639 #endif // __WXWINCE__