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