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