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