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