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