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