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