]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcbase.cpp
graphics context additions and merging graphics bitmap additions from Kevin O.
[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(wxTRANSPARENT)
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_scaleX) * m_signX + m_logicalOriginX;
372 }
373
374 wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
375 {
376 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + 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_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
392 }
393
394 wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
395 {
396 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + 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, wxTRANSPARENT));
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::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
762 {
763 wxPointList point_list;
764
765 wxPoint *point1 = new wxPoint;
766 point1->x = x1; point1->y = y1;
767 point_list.Append( point1 );
768
769 wxPoint *point2 = new wxPoint;
770 point2->x = x2; point2->y = y2;
771 point_list.Append( point2 );
772
773 wxPoint *point3 = new wxPoint;
774 point3->x = x3; point3->y = y3;
775 point_list.Append( point3 );
776
777 DoDrawSpline(&point_list);
778
779 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
780 {
781 wxPoint *p = node->GetData();
782 delete p;
783 }
784 }
785
786 void wxDCImpl::DoDrawSpline(int n, wxPoint points[])
787 {
788 wxPointList list;
789 for (int i =0; i < n; i++)
790 list.Append( &points[i] );
791
792 DoDrawSpline(&list);
793 }
794
795 // ----------------------------------- spline code ----------------------------------------
796
797 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
798 double a3, double b3, double a4, double b4);
799 void wx_clear_stack();
800 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
801 double *y3, double *x4, double *y4);
802 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
803 double x4, double y4);
804 static bool wx_spline_add_point(double x, double y);
805 static void wx_spline_draw_point_array(wxDC *dc);
806
807 wxPointList wx_spline_point_list;
808
809 #define half(z1, z2) ((z1+z2)/2.0)
810 #define THRESHOLD 5
811
812 /* iterative version */
813
814 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
815 double b4)
816 {
817 register double xmid, ymid;
818 double x1, y1, x2, y2, x3, y3, x4, y4;
819
820 wx_clear_stack();
821 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
822
823 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
824 xmid = (double)half(x2, x3);
825 ymid = (double)half(y2, y3);
826 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
827 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
828 wx_spline_add_point( x1, y1 );
829 wx_spline_add_point( xmid, ymid );
830 } else {
831 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
832 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
833 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
834 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
835 }
836 }
837 }
838
839 /* utilities used by spline drawing routines */
840
841 typedef struct wx_spline_stack_struct {
842 double x1, y1, x2, y2, x3, y3, x4, y4;
843 } Stack;
844
845 #define SPLINE_STACK_DEPTH 20
846 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
847 static Stack *wx_stack_top;
848 static int wx_stack_count;
849
850 void wx_clear_stack()
851 {
852 wx_stack_top = wx_spline_stack;
853 wx_stack_count = 0;
854 }
855
856 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
857 {
858 wx_stack_top->x1 = x1;
859 wx_stack_top->y1 = y1;
860 wx_stack_top->x2 = x2;
861 wx_stack_top->y2 = y2;
862 wx_stack_top->x3 = x3;
863 wx_stack_top->y3 = y3;
864 wx_stack_top->x4 = x4;
865 wx_stack_top->y4 = y4;
866 wx_stack_top++;
867 wx_stack_count++;
868 }
869
870 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
871 double *x3, double *y3, double *x4, double *y4)
872 {
873 if (wx_stack_count == 0)
874 return (0);
875 wx_stack_top--;
876 wx_stack_count--;
877 *x1 = wx_stack_top->x1;
878 *y1 = wx_stack_top->y1;
879 *x2 = wx_stack_top->x2;
880 *y2 = wx_stack_top->y2;
881 *x3 = wx_stack_top->x3;
882 *y3 = wx_stack_top->y3;
883 *x4 = wx_stack_top->x4;
884 *y4 = wx_stack_top->y4;
885 return (1);
886 }
887
888 static bool wx_spline_add_point(double x, double y)
889 {
890 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
891 wx_spline_point_list.Append(point );
892 return true;
893 }
894
895 static void wx_spline_draw_point_array(wxDC *dc)
896 {
897 dc->DrawLines(&wx_spline_point_list, 0, 0 );
898 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
899 while (node)
900 {
901 wxPoint *point = node->GetData();
902 delete point;
903 wx_spline_point_list.Erase(node);
904 node = wx_spline_point_list.GetFirst();
905 }
906 }
907
908 void wxDCImpl::DoDrawSpline( const wxPointList *points )
909 {
910 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
911
912 wxPoint *p;
913 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
914 double x1, y1, x2, y2;
915
916 wxPointList::compatibility_iterator node = points->GetFirst();
917 if (!node)
918 // empty list
919 return;
920
921 p = (wxPoint *)node->GetData();
922
923 x1 = p->x;
924 y1 = p->y;
925
926 node = node->GetNext();
927 p = node->GetData();
928
929 x2 = p->x;
930 y2 = p->y;
931 cx1 = (double)((x1 + x2) / 2);
932 cy1 = (double)((y1 + y2) / 2);
933 cx2 = (double)((cx1 + x2) / 2);
934 cy2 = (double)((cy1 + y2) / 2);
935
936 wx_spline_add_point(x1, y1);
937
938 while ((node = node->GetNext())
939 #if !wxUSE_STL
940 != NULL
941 #endif // !wxUSE_STL
942 )
943 {
944 p = node->GetData();
945 x1 = x2;
946 y1 = y2;
947 x2 = p->x;
948 y2 = p->y;
949 cx4 = (double)(x1 + x2) / 2;
950 cy4 = (double)(y1 + y2) / 2;
951 cx3 = (double)(x1 + cx4) / 2;
952 cy3 = (double)(y1 + cy4) / 2;
953
954 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
955
956 cx1 = cx4;
957 cy1 = cy4;
958 cx2 = (double)(cx1 + x2) / 2;
959 cy2 = (double)(cy1 + y2) / 2;
960 }
961
962 wx_spline_add_point( cx1, cy1 );
963 wx_spline_add_point( x2, y2 );
964
965 wx_spline_draw_point_array( m_owner );
966 }
967
968 #endif // wxUSE_SPLINES
969
970
971
972 void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
973 const wxColour& initialColour,
974 const wxColour& destColour,
975 wxDirection nDirection)
976 {
977 // save old pen
978 wxPen oldPen = m_pen;
979 wxBrush oldBrush = m_brush;
980
981 wxUint8 nR1 = initialColour.Red();
982 wxUint8 nG1 = initialColour.Green();
983 wxUint8 nB1 = initialColour.Blue();
984 wxUint8 nR2 = destColour.Red();
985 wxUint8 nG2 = destColour.Green();
986 wxUint8 nB2 = destColour.Blue();
987 wxUint8 nR, nG, nB;
988
989 if ( nDirection == wxEAST || nDirection == wxWEST )
990 {
991 wxInt32 x = rect.GetWidth();
992 wxInt32 w = x; // width of area to shade
993 wxInt32 xDelta = w/256; // height of one shade bend
994 if (xDelta < 1)
995 xDelta = 1;
996
997 while (x >= xDelta)
998 {
999 x -= xDelta;
1000 if (nR1 > nR2)
1001 nR = nR1 - (nR1-nR2)*(w-x)/w;
1002 else
1003 nR = nR1 + (nR2-nR1)*(w-x)/w;
1004
1005 if (nG1 > nG2)
1006 nG = nG1 - (nG1-nG2)*(w-x)/w;
1007 else
1008 nG = nG1 + (nG2-nG1)*(w-x)/w;
1009
1010 if (nB1 > nB2)
1011 nB = nB1 - (nB1-nB2)*(w-x)/w;
1012 else
1013 nB = nB1 + (nB2-nB1)*(w-x)/w;
1014
1015 wxColour colour(nR,nG,nB);
1016 SetPen(wxPen(colour, 1, wxSOLID));
1017 SetBrush(wxBrush(colour));
1018 if(nDirection == wxEAST)
1019 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
1020 xDelta, rect.GetHeight());
1021 else //nDirection == wxWEST
1022 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1023 xDelta, rect.GetHeight());
1024 }
1025 }
1026 else // nDirection == wxNORTH || nDirection == wxSOUTH
1027 {
1028 wxInt32 y = rect.GetHeight();
1029 wxInt32 w = y; // height of area to shade
1030 wxInt32 yDelta = w/255; // height of one shade bend
1031 if (yDelta < 1)
1032 yDelta = 1;
1033
1034 while (y > 0)
1035 {
1036 y -= yDelta;
1037 if (nR1 > nR2)
1038 nR = nR1 - (nR1-nR2)*(w-y)/w;
1039 else
1040 nR = nR1 + (nR2-nR1)*(w-y)/w;
1041
1042 if (nG1 > nG2)
1043 nG = nG1 - (nG1-nG2)*(w-y)/w;
1044 else
1045 nG = nG1 + (nG2-nG1)*(w-y)/w;
1046
1047 if (nB1 > nB2)
1048 nB = nB1 - (nB1-nB2)*(w-y)/w;
1049 else
1050 nB = nB1 + (nB2-nB1)*(w-y)/w;
1051
1052 wxColour colour(nR,nG,nB);
1053 SetPen(wxPen(colour, 1, wxSOLID));
1054 SetBrush(wxBrush(colour));
1055 if(nDirection == wxNORTH)
1056 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1057 rect.GetWidth(), yDelta);
1058 else //nDirection == wxSOUTH
1059 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
1060 rect.GetWidth(), yDelta);
1061 }
1062 }
1063
1064 SetPen(oldPen);
1065 SetBrush(oldBrush);
1066 }
1067
1068 void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
1069 const wxColour& initialColour,
1070 const wxColour& destColour,
1071 const wxPoint& circleCenter)
1072 {
1073 //save the old pen color
1074 wxColour oldPenColour = m_pen.GetColour();
1075
1076 wxUint8 nR1 = destColour.Red();
1077 wxUint8 nG1 = destColour.Green();
1078 wxUint8 nB1 = destColour.Blue();
1079 wxUint8 nR2 = initialColour.Red();
1080 wxUint8 nG2 = initialColour.Green();
1081 wxUint8 nB2 = initialColour.Blue();
1082 wxUint8 nR, nG, nB;
1083
1084
1085 //Radius
1086 wxInt32 cx = rect.GetWidth() / 2;
1087 wxInt32 cy = rect.GetHeight() / 2;
1088 wxInt32 nRadius;
1089 if (cx < cy)
1090 nRadius = cx;
1091 else
1092 nRadius = cy;
1093
1094 //Offset of circle
1095 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1096 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1097
1098 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1099 {
1100 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1101 {
1102 //get color difference
1103 wxInt32 nGradient = ((nRadius -
1104 (wxInt32)sqrt(
1105 pow((double)(x - cx - nCircleOffX), 2) +
1106 pow((double)(y - cy - nCircleOffY), 2)
1107 )) * 100) / nRadius;
1108
1109 //normalize Gradient
1110 if (nGradient < 0 )
1111 nGradient = 0;
1112
1113 //get dest colors
1114 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1115 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1116 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1117
1118 //set the pixel
1119 m_pen.SetColour(wxColour(nR,nG,nB));
1120 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
1121 }
1122 }
1123 //return old pen color
1124 m_pen.SetColour(oldPenColour);
1125 }
1126
1127 //-----------------------------------------------------------------------------
1128 // wxDC
1129 //-----------------------------------------------------------------------------
1130
1131 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1132
1133 void wxDC::DrawLabel(const wxString& text,
1134 const wxBitmap& bitmap,
1135 const wxRect& rect,
1136 int alignment,
1137 int indexAccel,
1138 wxRect *rectBounding)
1139 {
1140 // find the text position
1141 wxCoord widthText, heightText, heightLine;
1142 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1143
1144 wxCoord width, height;
1145 if ( bitmap.Ok() )
1146 {
1147 width = widthText + bitmap.GetWidth();
1148 height = bitmap.GetHeight();
1149 }
1150 else // no bitmap
1151 {
1152 width = widthText;
1153 height = heightText;
1154 }
1155
1156 wxCoord x, y;
1157 if ( alignment & wxALIGN_RIGHT )
1158 {
1159 x = rect.GetRight() - width;
1160 }
1161 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1162 {
1163 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1164 }
1165 else // alignment & wxALIGN_LEFT
1166 {
1167 x = rect.GetLeft();
1168 }
1169
1170 if ( alignment & wxALIGN_BOTTOM )
1171 {
1172 y = rect.GetBottom() - height;
1173 }
1174 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1175 {
1176 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1177 }
1178 else // alignment & wxALIGN_TOP
1179 {
1180 y = rect.GetTop();
1181 }
1182
1183 // draw the bitmap first
1184 wxCoord x0 = x,
1185 y0 = y,
1186 width0 = width;
1187 if ( bitmap.Ok() )
1188 {
1189 DrawBitmap(bitmap, x, y, true /* use mask */);
1190
1191 wxCoord offset = bitmap.GetWidth() + 4;
1192 x += offset;
1193 width -= offset;
1194
1195 y += (height - heightText) / 2;
1196 }
1197
1198 // we will draw the underscore under the accel char later
1199 wxCoord startUnderscore = 0,
1200 endUnderscore = 0,
1201 yUnderscore = 0;
1202
1203 // split the string into lines and draw each of them separately
1204 wxString curLine;
1205 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1206 {
1207 if ( *pc == _T('\n') || pc == text.end() )
1208 {
1209 int xRealStart = x; // init it here to avoid compielr warnings
1210
1211 if ( !curLine.empty() )
1212 {
1213 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1214 // wxALIGN_LEFT is 0
1215 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1216 {
1217 wxCoord widthLine;
1218 GetTextExtent(curLine, &widthLine, NULL);
1219
1220 if ( alignment & wxALIGN_RIGHT )
1221 {
1222 xRealStart += width - widthLine;
1223 }
1224 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1225 {
1226 xRealStart += (width - widthLine) / 2;
1227 }
1228 }
1229 //else: left aligned, nothing to do
1230
1231 DrawText(curLine, xRealStart, y);
1232 }
1233
1234 y += heightLine;
1235
1236 // do we have underscore in this line? we can check yUnderscore
1237 // because it is set below to just y + heightLine if we do
1238 if ( y == yUnderscore )
1239 {
1240 // adjust the horz positions to account for the shift
1241 startUnderscore += xRealStart;
1242 endUnderscore += xRealStart;
1243 }
1244
1245 if ( pc == text.end() )
1246 break;
1247
1248 curLine.clear();
1249 }
1250 else // not end of line
1251 {
1252 if ( pc - text.begin() == indexAccel )
1253 {
1254 // remeber to draw underscore here
1255 GetTextExtent(curLine, &startUnderscore, NULL);
1256 curLine += *pc;
1257 GetTextExtent(curLine, &endUnderscore, NULL);
1258
1259 yUnderscore = y + heightLine;
1260 }
1261 else
1262 {
1263 curLine += *pc;
1264 }
1265 }
1266 }
1267
1268 // draw the underscore if found
1269 if ( startUnderscore != endUnderscore )
1270 {
1271 // it should be of the same colour as text
1272 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1273
1274 yUnderscore--;
1275
1276 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1277 }
1278
1279 // return bounding rect if requested
1280 if ( rectBounding )
1281 {
1282 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1283 }
1284
1285 CalcBoundingBox(x0, y0);
1286 CalcBoundingBox(x0 + width0, y0 + height);
1287 }
1288
1289 #if WXWIN_COMPATIBILITY_2_8
1290 // for compatibility with the old code when wxCoord was long everywhere
1291 void wxDC::GetTextExtent(const wxString& string,
1292 long *x, long *y,
1293 long *descent,
1294 long *externalLeading,
1295 const wxFont *theFont) const
1296 {
1297 wxCoord x2, y2, descent2, externalLeading2;
1298 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1299 &descent2, &externalLeading2,
1300 theFont);
1301 if ( x )
1302 *x = x2;
1303 if ( y )
1304 *y = y2;
1305 if ( descent )
1306 *descent = descent2;
1307 if ( externalLeading )
1308 *externalLeading = externalLeading2;
1309 }
1310
1311 void wxDC::GetLogicalOrigin(long *x, long *y) const
1312 {
1313 wxCoord x2, y2;
1314 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1315 if ( x )
1316 *x = x2;
1317 if ( y )
1318 *y = y2;
1319 }
1320
1321 void wxDC::GetDeviceOrigin(long *x, long *y) const
1322 {
1323 wxCoord x2, y2;
1324 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1325 if ( x )
1326 *x = x2;
1327 if ( y )
1328 *y = y2;
1329 }
1330
1331 void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1332 {
1333 wxCoord xx,yy,ww,hh;
1334 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1335 if (x) *x = xx;
1336 if (y) *y = yy;
1337 if (w) *w = ww;
1338 if (h) *h = hh;
1339 }
1340
1341 #endif // WXWIN_COMPATIBILITY_2_8
1342
1343 /*
1344 Notes for wxWidgets DrawEllipticArcRot(...)
1345
1346 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1347 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1348 which are also new.
1349
1350 All methods are generic, so they can be implemented in wxDCBase.
1351 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1352 methods like (WinCE) wxDC::DoDrawArc(...).
1353
1354 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1355 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1356 parts) or every column (in steep parts) only one pixel is calculated.
1357 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1358 starting angle is not equal to the ending angle. The calculation of the
1359 pixels is done using simple arithmetic only and should perform not too
1360 bad even on devices without floating point processor. I didn't test this yet.
1361
1362 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1363 For instance: an ellipse rotated 180 degrees is drawn
1364 slightly different from the original.
1365
1366 The points are then moved to an array and used to draw a polyline and/or polygon
1367 (with center added, the pie).
1368 The result looks quite similar to the native ellipse, only e few pixels differ.
1369
1370 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1371 slower as DrawEllipse(...), which calls the native API.
1372 An rotated ellipse outside the clipping region takes nearly the same time,
1373 while an native ellipse outside takes nearly no time to draw.
1374
1375 If you draw an arc with this new method, you will see the starting and ending angles
1376 are calculated properly.
1377 If you use DrawEllipticArc(...), you will see they are only correct for circles
1378 and not properly calculated for ellipses.
1379
1380 Peter Lenhard
1381 p.lenhard@t-online.de
1382 */
1383
1384 #ifdef __WXWINCE__
1385 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
1386 wxCoord w, wxCoord h,
1387 double sa, double ea, double angle )
1388 {
1389 wxPointList list;
1390
1391 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
1392 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
1393
1394 // Add center (for polygon/pie)
1395 list.Append( new wxPoint( x+w/2, y+h/2 ) );
1396
1397 // copy list into array and delete list elements
1398 int n = list.GetCount();
1399 wxPoint *points = new wxPoint[n];
1400 int i = 0;
1401 wxPointList::compatibility_iterator node;
1402 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
1403 {
1404 wxPoint *point = node->GetData();
1405 points[i].x = point->x;
1406 points[i].y = point->y;
1407 delete point;
1408 }
1409
1410 // first draw the pie without pen, if necessary
1411 if( GetBrush() != *wxTRANSPARENT_BRUSH )
1412 {
1413 wxPen tempPen( GetPen() );
1414 SetPen( *wxTRANSPARENT_PEN );
1415 DoDrawPolygon( n, points, 0, 0 );
1416 SetPen( tempPen );
1417 }
1418
1419 // then draw the arc without brush, if necessary
1420 if( GetPen() != *wxTRANSPARENT_PEN )
1421 {
1422 // without center
1423 DoDrawLines( n-1, points, 0, 0 );
1424 }
1425
1426 delete [] points;
1427
1428 } // DrawEllipticArcRot
1429
1430 void wxDCImpl::Rotate( wxPointList* points, double angle, wxPoint center )
1431 {
1432 if( angle != 0.0 )
1433 {
1434 double pi(M_PI);
1435 double dSinA = -sin(angle*2.0*pi/360.0);
1436 double dCosA = cos(angle*2.0*pi/360.0);
1437 wxPointList::compatibility_iterator node;
1438 for ( node = points->GetFirst(); node; node = node->GetNext() )
1439 {
1440 wxPoint* point = node->GetData();
1441
1442 // transform coordinates, if necessary
1443 if( center.x ) point->x -= center.x;
1444 if( center.y ) point->y -= center.y;
1445
1446 // calculate rotation, rounding simply by implicit cast to integer
1447 int xTemp = point->x * dCosA - point->y * dSinA;
1448 point->y = point->x * dSinA + point->y * dCosA;
1449 point->x = xTemp;
1450
1451 // back transform coordinates, if necessary
1452 if( center.x ) point->x += center.x;
1453 if( center.y ) point->y += center.y;
1454 }
1455 }
1456 }
1457
1458 void wxDCImpl::CalculateEllipticPoints( wxPointList* points,
1459 wxCoord xStart, wxCoord yStart,
1460 wxCoord w, wxCoord h,
1461 double sa, double ea )
1462 {
1463 double pi = M_PI;
1464 double sar = 0;
1465 double ear = 0;
1466 int xsa = 0;
1467 int ysa = 0;
1468 int xea = 0;
1469 int yea = 0;
1470 int sq = 0;
1471 int eq = 0;
1472 bool bUseAngles = false;
1473 if( w<0 ) w = -w;
1474 if( h<0 ) h = -h;
1475 // half-axes
1476 wxCoord a = w/2;
1477 wxCoord b = h/2;
1478 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1479 int decrX = 0;
1480 if( 2*a == w ) decrX = 1;
1481 int decrY = 0;
1482 if( 2*b == h ) decrY = 1;
1483 // center
1484 wxCoord xCenter = xStart + a;
1485 wxCoord yCenter = yStart + b;
1486 // calculate data for start and end, if necessary
1487 if( sa != ea )
1488 {
1489 bUseAngles = true;
1490 // normalisation of angles
1491 while( sa<0 ) sa += 360;
1492 while( ea<0 ) ea += 360;
1493 while( sa>=360 ) sa -= 360;
1494 while( ea>=360 ) ea -= 360;
1495 // calculate quadrant numbers
1496 if( sa > 270 ) sq = 3;
1497 else if( sa > 180 ) sq = 2;
1498 else if( sa > 90 ) sq = 1;
1499 if( ea > 270 ) eq = 3;
1500 else if( ea > 180 ) eq = 2;
1501 else if( ea > 90 ) eq = 1;
1502 sar = sa * pi / 180.0;
1503 ear = ea * pi / 180.0;
1504 // correct angle circle -> ellipse
1505 sar = atan( -a/(double)b * tan( sar ) );
1506 if ( sq == 1 || sq == 2 ) sar += pi;
1507 ear = atan( -a/(double)b * tan( ear ) );
1508 if ( eq == 1 || eq == 2 ) ear += pi;
1509 // coordinates of points
1510 xsa = xCenter + a * cos( sar );
1511 if( sq == 0 || sq == 3 ) xsa -= decrX;
1512 ysa = yCenter + b * sin( sar );
1513 if( sq == 2 || sq == 3 ) ysa -= decrY;
1514 xea = xCenter + a * cos( ear );
1515 if( eq == 0 || eq == 3 ) xea -= decrX;
1516 yea = yCenter + b * sin( ear );
1517 if( eq == 2 || eq == 3 ) yea -= decrY;
1518 } // if iUseAngles
1519 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1520 double c1 = b * b;
1521 double c2 = 2.0 / w;
1522 c2 *= c2;
1523 c2 *= c1;
1524 wxCoord x = 0;
1525 wxCoord y = b;
1526 long x2 = 1;
1527 long y2 = y*y;
1528 long y2_old = 0;
1529 long y_old = 0;
1530 // Lists for quadrant 1 to 4
1531 wxPointList pointsarray[4];
1532 // Calculate points for first quadrant and set in all quadrants
1533 for( x = 0; x <= a; ++x )
1534 {
1535 x2 = x2+x+x-1;
1536 y2_old = y2;
1537 y_old = y;
1538 bool bNewPoint = false;
1539 while( y2 > c1 - c2 * x2 && y > 0 )
1540 {
1541 bNewPoint = true;
1542 y2 = y2-y-y+1;
1543 --y;
1544 }
1545 // old y now to big: set point with old y, old x
1546 if( bNewPoint && x>1)
1547 {
1548 int x1 = x - 1;
1549 // remove points on the same line
1550 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
1551 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
1552 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
1553 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
1554 } // set point
1555 } // calculate point
1556
1557 // Starting and/or ending points for the quadrants, first quadrant gets both.
1558 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
1559 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
1560 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
1561 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
1562 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
1563
1564 // copy quadrants in original list
1565 if( bUseAngles )
1566 {
1567 // Copy the right part of the points in the lists
1568 // and delete the wxPoints, because they do not leave this method.
1569 points->Append( new wxPoint( xsa, ysa ) );
1570 int q = sq;
1571 bool bStarted = false;
1572 bool bReady = false;
1573 bool bForceTurn = ( sq == eq && sa > ea );
1574 while( !bReady )
1575 {
1576 wxPointList::compatibility_iterator node;
1577 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1578 {
1579 // once: go to starting point in start quadrant
1580 if( !bStarted &&
1581 (
1582 node->GetData()->x < xsa+1 && q <= 1
1583 ||
1584 node->GetData()->x > xsa-1 && q >= 2
1585 )
1586 )
1587 {
1588 bStarted = true;
1589 }
1590
1591 // copy point, if not at ending point
1592 if( bStarted )
1593 {
1594 if( q != eq || bForceTurn
1595 ||
1596 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
1597 ||
1598 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
1599 )
1600 {
1601 // copy point
1602 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
1603 points->Append( pPoint );
1604 }
1605 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
1606 {
1607 bReady = true;
1608 }
1609 }
1610 } // for node
1611 ++q;
1612 if( q > 3 ) q = 0;
1613 bForceTurn = false;
1614 bStarted = true;
1615 } // while not bReady
1616 points->Append( new wxPoint( xea, yea ) );
1617
1618 // delete points
1619 for( q = 0; q < 4; ++q )
1620 {
1621 wxPointList::compatibility_iterator node;
1622 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1623 {
1624 wxPoint *p = node->GetData();
1625 delete p;
1626 }
1627 }
1628 }
1629 else
1630 {
1631 wxPointList::compatibility_iterator node;
1632 // copy whole ellipse, wxPoints will be deleted outside
1633 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
1634 {
1635 wxPoint *p = node->GetData();
1636 points->Append( p );
1637 }
1638 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
1639 {
1640 wxPoint *p = node->GetData();
1641 points->Append( p );
1642 }
1643 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
1644 {
1645 wxPoint *p = node->GetData();
1646 points->Append( p );
1647 }
1648 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
1649 {
1650 wxPoint *p = node->GetData();
1651 points->Append( p );
1652 }
1653 } // not iUseAngles
1654 } // CalculateEllipticPoints
1655
1656 #endif // __WXWINCE__