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