1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        common/dcbase.cpp 
   3 // Purpose:     generic methods of the wxDC Class 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) wxWidgets team 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  30 // bool wxDCBase::sm_cacheing = false; 
  32 // ============================================================================ 
  34 // ============================================================================ 
  36 #if WXWIN_COMPATIBILITY_2_6 
  37 void wxDCBase::BeginDrawing() 
  41 void wxDCBase::EndDrawing() 
  44 #endif // WXWIN_COMPATIBILITY_2_6 
  46 // ---------------------------------------------------------------------------- 
  48 // ---------------------------------------------------------------------------- 
  50 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
  51                                wxCoord width
, wxCoord height
) 
  53     wxCHECK_RET( Ok(), wxT("invalid window dc") ); 
  55     wxCoord x2 
= x1 
+ width
, 
  58     // this is to yield width of 3 for width == height == 10 
  59     SetPen(wxPen(GetTextForeground(), (width 
+ height 
+ 1) / 7, wxSOLID
)); 
  61     // we're drawing a scaled version of wx/generic/tick.xpm here 
  62     wxCoord x3 
= x1 
+ (4*width
) / 10,   // x of the tick bottom 
  63             y3 
= y1 
+ height 
/ 2;       // y of the left tick branch 
  64     DoDrawLine(x1
, y3
, x3
, y2
); 
  65     DoDrawLine(x3
, y2
, x2
, y1
); 
  67     CalcBoundingBox(x1
, y1
); 
  68     CalcBoundingBox(x2
, y2
); 
  71 // ---------------------------------------------------------------------------- 
  73 // ---------------------------------------------------------------------------- 
  75 void wxDCBase::DrawLines(const wxList 
*list
, wxCoord xoffset
, wxCoord yoffset
) 
  77     int n 
= list
->GetCount(); 
  78     wxPoint 
*points 
= new wxPoint
[n
]; 
  81     for ( wxList::compatibility_iterator node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
  83         wxPoint 
*point 
= (wxPoint 
*)node
->GetData(); 
  84         points
[i
].x 
= point
->x
; 
  85         points
[i
].y 
= point
->y
; 
  88     DoDrawLines(n
, points
, xoffset
, yoffset
); 
  94 void wxDCBase::DrawPolygon(const wxList 
*list
, 
  95                            wxCoord xoffset
, wxCoord yoffset
, 
  98     int n 
= list
->GetCount(); 
  99     wxPoint 
*points 
= new wxPoint
[n
]; 
 102     for ( wxList::compatibility_iterator node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
 104         wxPoint 
*point 
= (wxPoint 
*)node
->GetData(); 
 105         points
[i
].x 
= point
->x
; 
 106         points
[i
].y 
= point
->y
; 
 109     DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
); 
 115 wxDCBase::DoDrawPolyPolygon(int n
, 
 118                             wxCoord xoffset
, wxCoord yoffset
, 
 123         DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
); 
 131     for (i 
= j 
= lastOfs 
= 0; i 
< n
; i
++) 
 136     pts 
= new wxPoint
[j
+n
-1]; 
 137     for (i 
= 0; i 
< j
; i
++) 
 139     for (i 
= 2; i 
<= n
; i
++) 
 141         lastOfs 
-= count
[n
-i
]; 
 142         pts
[j
++] = pts
[lastOfs
]; 
 146     SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
)); 
 147     DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
); 
 149     for (i 
= j 
= 0; i 
< n
; i
++) 
 151         DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
); 
 157 // ---------------------------------------------------------------------------- 
 159 // ---------------------------------------------------------------------------- 
 163 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) 
 164 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
) 
 168     wxPoint 
*point1 
= new wxPoint
; 
 169     point1
->x 
= x1
; point1
->y 
= y1
; 
 170     point_list
.Append((wxObject
*)point1
); 
 172     wxPoint 
*point2 
= new wxPoint
; 
 173     point2
->x 
= x2
; point2
->y 
= y2
; 
 174     point_list
.Append((wxObject
*)point2
); 
 176     wxPoint 
*point3 
= new wxPoint
; 
 177     point3
->x 
= x3
; point3
->y 
= y3
; 
 178     point_list
.Append((wxObject
*)point3
); 
 180     DrawSpline(&point_list
); 
 182     for( wxList::compatibility_iterator node 
= point_list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 184         wxPoint 
*p 
= (wxPoint 
*)node
->GetData(); 
 189 void wxDCBase::DrawSpline(int n
, wxPoint points
[]) 
 192     for (int i 
=0; i 
< n
; i
++) 
 194         list
.Append((wxObject
*)&points
[i
]); 
 200 // ----------------------------------- spline code ---------------------------------------- 
 202 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, 
 203                          double a3
, double b3
, double a4
, double b4
); 
 204 void wx_clear_stack(); 
 205 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
, 
 206         double *y3
, double *x4
, double *y4
); 
 207 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, 
 208           double x4
, double y4
); 
 209 static bool wx_spline_add_point(double x
, double y
); 
 210 static void wx_spline_draw_point_array(wxDCBase 
*dc
); 
 212 wxList wx_spline_point_list
; 
 214 #define                half(z1, z2)        ((z1+z2)/2.0) 
 217 /* iterative version */ 
 219 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
, 
 222     register double  xmid
, ymid
; 
 223     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
 226     wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
); 
 228     while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) { 
 229         xmid 
= (double)half(x2
, x3
); 
 230         ymid 
= (double)half(y2
, y3
); 
 231         if (fabs(x1 
- xmid
) < THRESHOLD 
&& fabs(y1 
- ymid
) < THRESHOLD 
&& 
 232             fabs(xmid 
- x4
) < THRESHOLD 
&& fabs(ymid 
- y4
) < THRESHOLD
) { 
 233             wx_spline_add_point( x1
, y1 
); 
 234             wx_spline_add_point( xmid
, ymid 
); 
 236             wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
), 
 237                  (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
); 
 238             wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
), 
 239                  (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
); 
 244 /* utilities used by spline drawing routines */ 
 246 typedef struct wx_spline_stack_struct 
{ 
 247     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
 250 #define         SPLINE_STACK_DEPTH             20 
 251 static Stack    wx_spline_stack
[SPLINE_STACK_DEPTH
]; 
 252 static Stack   
*wx_stack_top
; 
 253 static int      wx_stack_count
; 
 255 void wx_clear_stack() 
 257     wx_stack_top 
= wx_spline_stack
; 
 261 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
) 
 263     wx_stack_top
->x1 
= x1
; 
 264     wx_stack_top
->y1 
= y1
; 
 265     wx_stack_top
->x2 
= x2
; 
 266     wx_stack_top
->y2 
= y2
; 
 267     wx_stack_top
->x3 
= x3
; 
 268     wx_stack_top
->y3 
= y3
; 
 269     wx_stack_top
->x4 
= x4
; 
 270     wx_stack_top
->y4 
= y4
; 
 275 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, 
 276                   double *x3
, double *y3
, double *x4
, double *y4
) 
 278     if (wx_stack_count 
== 0) 
 282     *x1 
= wx_stack_top
->x1
; 
 283     *y1 
= wx_stack_top
->y1
; 
 284     *x2 
= wx_stack_top
->x2
; 
 285     *y2 
= wx_stack_top
->y2
; 
 286     *x3 
= wx_stack_top
->x3
; 
 287     *y3 
= wx_stack_top
->y3
; 
 288     *x4 
= wx_stack_top
->x4
; 
 289     *y4 
= wx_stack_top
->y4
; 
 293 static bool wx_spline_add_point(double x
, double y
) 
 295   wxPoint 
*point 
= new wxPoint 
; 
 298   wx_spline_point_list
.Append((wxObject
*)point
); 
 302 static void wx_spline_draw_point_array(wxDCBase 
*dc
) 
 304   dc
->DrawLines(&wx_spline_point_list
, 0, 0 ); 
 305   wxList::compatibility_iterator node 
= wx_spline_point_list
.GetFirst(); 
 308     wxPoint 
*point 
= (wxPoint 
*)node
->GetData(); 
 310     wx_spline_point_list
.Erase(node
); 
 311     node 
= wx_spline_point_list
.GetFirst(); 
 315 void wxDCBase::DoDrawSpline( wxList 
*points 
) 
 317     wxCHECK_RET( Ok(), wxT("invalid window dc") ); 
 320     double           cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
; 
 321     double           x1
, y1
, x2
, y2
; 
 323     wxList::compatibility_iterator node 
= points
->GetFirst(); 
 324     if (node 
== wxList::compatibility_iterator()) 
 328     p 
= (wxPoint 
*)node
->GetData(); 
 333     node 
= node
->GetNext(); 
 334     p 
= (wxPoint 
*)node
->GetData(); 
 338     cx1 
= (double)((x1 
+ x2
) / 2); 
 339     cy1 
= (double)((y1 
+ y2
) / 2); 
 340     cx2 
= (double)((cx1 
+ x2
) / 2); 
 341     cy2 
= (double)((cy1 
+ y2
) / 2); 
 343     wx_spline_add_point(x1
, y1
); 
 345     while ((node 
= node
->GetNext()) 
 351         p 
= (wxPoint 
*)node
->GetData(); 
 356         cx4 
= (double)(x1 
+ x2
) / 2; 
 357         cy4 
= (double)(y1 
+ y2
) / 2; 
 358         cx3 
= (double)(x1 
+ cx4
) / 2; 
 359         cy3 
= (double)(y1 
+ cy4
) / 2; 
 361         wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
); 
 365         cx2 
= (double)(cx1 
+ x2
) / 2; 
 366         cy2 
= (double)(cy1 
+ y2
) / 2; 
 369     wx_spline_add_point( cx1
, cy1 
); 
 370     wx_spline_add_point( x2
, y2 
); 
 372     wx_spline_draw_point_array( this ); 
 375 #endif // wxUSE_SPLINES 
 377 // ---------------------------------------------------------------------------- 
 378 // Partial Text Extents 
 379 // ---------------------------------------------------------------------------- 
 382 // Each element of the widths array will be the width of the string up to and 
 383 // including the corresponding character in text.  This is the generic 
 384 // implementation, the port-specific classes should do this with native APIs 
 385 // if available and if faster.  Note: pango_layout_index_to_pos is much slower 
 386 // than calling GetTextExtent!! 
 393     FontWidthCache() : m_scaleX(1), m_widths(NULL
) { } 
 394     ~FontWidthCache() { delete []m_widths
; } 
 399             m_widths 
= new int[FWC_SIZE
]; 
 401         memset(m_widths
, 0, sizeof(int)*FWC_SIZE
); 
 409 static FontWidthCache s_fontWidthCache
; 
 411 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const 
 415     const size_t len 
= text
.Length(); 
 419     // reset the cache if font or horizontal scale have changed 
 420     if ( !s_fontWidthCache
.m_widths 
|| 
 421          !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) || 
 422          (s_fontWidthCache
.m_font 
!= GetFont()) ) 
 424         s_fontWidthCache
.Reset(); 
 425         s_fontWidthCache
.m_font 
= GetFont(); 
 426         s_fontWidthCache
.m_scaleX 
= m_scaleX
; 
 429     // Calculate the position of each character based on the widths of 
 430     // the previous characters 
 432     for ( size_t i 
= 0; i 
< len
; i
++ ) 
 434         const wxChar c 
= text
[i
]; 
 435         unsigned int c_int 
= (unsigned int)c
; 
 437         if ((c_int 
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0)) 
 439             w 
= s_fontWidthCache
.m_widths
[c_int
]; 
 443             GetTextExtent(c
, &w
, &h
); 
 444             if (c_int 
< FWC_SIZE
) 
 445                 s_fontWidthCache
.m_widths
[c_int
] = w
; 
 449         widths
[i
] = totalWidth
; 
 456 // ---------------------------------------------------------------------------- 
 457 // enhanced text drawing 
 458 // ---------------------------------------------------------------------------- 
 460 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
, 
 466     wxCoord widthTextMax 
= 0, widthLine
, 
 467             heightTextTotal 
= 0, heightLineDefault 
= 0, heightLine 
= 0; 
 470     for ( const wxChar 
*pc 
= text
; ; pc
++ ) 
 472         if ( *pc 
== _T('\n') || *pc 
== _T('\0') ) 
 474             if ( curLine
.empty() ) 
 476                 // we can't use GetTextExtent - it will return 0 for both width 
 477                 // and height and an empty line should count in height 
 480                 // assume that this line has the same height as the previous 
 482                 if ( !heightLineDefault 
) 
 483                     heightLineDefault 
= heightLine
; 
 485                 if ( !heightLineDefault 
) 
 487                     // but we don't know it yet - choose something reasonable 
 488                     GetTextExtent(_T("W"), NULL
, &heightLineDefault
, 
 492                 heightTextTotal 
+= heightLineDefault
; 
 496                 GetTextExtent(curLine
, &widthLine
, &heightLine
, 
 498                 if ( widthLine 
> widthTextMax 
) 
 499                     widthTextMax 
= widthLine
; 
 500                 heightTextTotal 
+= heightLine
; 
 503             if ( *pc 
== _T('\n') ) 
 522         *y 
= heightTextTotal
; 
 527 void wxDCBase::DrawLabel(const wxString
& text
, 
 528                          const wxBitmap
& bitmap
, 
 532                          wxRect 
*rectBounding
) 
 534     // find the text position 
 535     wxCoord widthText
, heightText
, heightLine
; 
 536     GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
); 
 538     wxCoord width
, height
; 
 541         width 
= widthText 
+ bitmap
.GetWidth(); 
 542         height 
= bitmap
.GetHeight(); 
 551     if ( alignment 
& wxALIGN_RIGHT 
) 
 553         x 
= rect
.GetRight() - width
; 
 555     else if ( alignment 
& wxALIGN_CENTRE_HORIZONTAL 
) 
 557         x 
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2; 
 559     else // alignment & wxALIGN_LEFT 
 564     if ( alignment 
& wxALIGN_BOTTOM 
) 
 566         y 
= rect
.GetBottom() - height
; 
 568     else if ( alignment 
& wxALIGN_CENTRE_VERTICAL 
) 
 570         y 
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2; 
 572     else // alignment & wxALIGN_TOP 
 577     // draw the bitmap first 
 583         DrawBitmap(bitmap
, x
, y
, true /* use mask */); 
 585         wxCoord offset 
= bitmap
.GetWidth() + 4; 
 589         y 
+= (height 
- heightText
) / 2; 
 592     // we will draw the underscore under the accel char later 
 593     wxCoord startUnderscore 
= 0, 
 597     // split the string into lines and draw each of them separately 
 599     for ( const wxChar 
*pc 
= text
; ; pc
++ ) 
 601         if ( *pc 
== _T('\n') || *pc 
== _T('\0') ) 
 603             int xRealStart 
= x
; // init it here to avoid compielr warnings 
 605             if ( !curLine
.empty() ) 
 607                 // NB: can't test for !(alignment & wxALIGN_LEFT) because 
 609                 if ( alignment 
& (wxALIGN_RIGHT 
| wxALIGN_CENTRE_HORIZONTAL
) ) 
 612                     GetTextExtent(curLine
, &widthLine
, NULL
); 
 614                     if ( alignment 
& wxALIGN_RIGHT 
) 
 616                         xRealStart 
+= width 
- widthLine
; 
 618                     else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) 
 620                         xRealStart 
+= (width 
- widthLine
) / 2; 
 623                 //else: left aligned, nothing to do 
 625                 DrawText(curLine
, xRealStart
, y
); 
 630             // do we have underscore in this line? we can check yUnderscore 
 631             // because it is set below to just y + heightLine if we do 
 632             if ( y 
== yUnderscore 
) 
 634                 // adjust the horz positions to account for the shift 
 635                 startUnderscore 
+= xRealStart
; 
 636                 endUnderscore 
+= xRealStart
; 
 639             if ( *pc 
== _T('\0') ) 
 644         else // not end of line 
 646             if ( pc 
- text
.c_str() == indexAccel 
) 
 648                 // remeber to draw underscore here 
 649                 GetTextExtent(curLine
, &startUnderscore
, NULL
); 
 651                 GetTextExtent(curLine
, &endUnderscore
, NULL
); 
 653                 yUnderscore 
= y 
+ heightLine
; 
 662     // draw the underscore if found 
 663     if ( startUnderscore 
!= endUnderscore 
) 
 665         // it should be of the same colour as text 
 666         SetPen(wxPen(GetTextForeground(), 0, wxSOLID
)); 
 670         DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
); 
 673     // return bounding rect if requested 
 676         *rectBounding 
= wxRect(x
, y 
- heightText
, widthText
, heightText
); 
 679     CalcBoundingBox(x0
, y0
); 
 680     CalcBoundingBox(x0 
+ width0
, y0 
+ height
); 
 684 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
, 
 685                                     const wxColour
& initialColour
, 
 686                                     const wxColour
& destColour
, 
 687                                     wxDirection nDirection
) 
 690     wxPen oldPen 
= m_pen
; 
 692     wxUint8 nR1 
= destColour
.Red(); 
 693     wxUint8 nG1 
= destColour
.Green(); 
 694     wxUint8 nB1 
= destColour
.Blue(); 
 695     wxUint8 nR2 
= initialColour
.Red(); 
 696     wxUint8 nG2 
= initialColour
.Green(); 
 697     wxUint8 nB2 
= initialColour
.Blue(); 
 700     if ( nDirection 
== wxEAST 
|| nDirection 
== wxWEST 
) 
 702         wxInt32 x 
= rect
.GetWidth(); 
 703         wxInt32 w 
= x
;              // width of area to shade 
 704         wxInt32 xDelta 
= w
/256;     // height of one shade bend 
 712                 nR 
= nR1 
- (nR1
-nR2
)*(w
-x
)/w
; 
 714                 nR 
= nR1 
+ (nR2
-nR1
)*(w
-x
)/w
; 
 717                 nG 
= nG1 
- (nG1
-nG2
)*(w
-x
)/w
; 
 719                 nG 
= nG1 
+ (nG2
-nG1
)*(w
-x
)/w
; 
 722                 nB 
= nB1 
- (nB1
-nB2
)*(w
-x
)/w
; 
 724                 nB 
= nB1 
+ (nB2
-nB1
)*(w
-x
)/w
; 
 726             SetPen(wxPen(wxColour(nR
, nG
, nB
), 1, wxSOLID
)); 
 727             if(nDirection 
== wxEAST
) 
 728                 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(), 
 729                         xDelta
, rect
.GetHeight()); 
 730             else //nDirection == wxWEST 
 731                 DrawRectangle(rect
.GetRight()-x
-xDelta
, rect
.GetTop(), 
 732                         xDelta
, rect
.GetHeight()); 
 735     else  // nDirection == wxNORTH || nDirection == wxSOUTH 
 737         wxInt32 y 
= rect
.GetHeight(); 
 738         wxInt32 w 
= y
;              // height of area to shade 
 739         wxInt32 yDelta 
= w
/255;     // height of one shade bend 
 747                 nR 
= nR1 
- (nR1
-nR2
)*(w
-y
)/w
; 
 749                 nR 
= nR1 
+ (nR2
-nR1
)*(w
-y
)/w
; 
 752                 nG 
= nG1 
- (nG1
-nG2
)*(w
-y
)/w
; 
 754                 nG 
= nG1 
+ (nG2
-nG1
)*(w
-y
)/w
; 
 757                 nB 
= nB1 
- (nB1
-nB2
)*(w
-y
)/w
; 
 759                 nB 
= nB1 
+ (nB2
-nB1
)*(w
-y
)/w
; 
 761             SetPen(wxPen(wxColour(nR
, nG
, nB
), 1, wxSOLID
)); 
 762             if(nDirection 
== wxNORTH
) 
 763                 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
, 
 764                         rect
.GetWidth(), yDelta
); 
 765             else //nDirection == wxSOUTH 
 766                 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
, 
 767                         rect
.GetWidth(), yDelta
); 
 774 void wxDCBase::GradientFillConcentric(const wxRect
& rect
, 
 775                                       const wxColour
& initialColour
, 
 776                                       const wxColour
& destColour
, 
 777                                       const wxPoint
& circleCenter
) 
 779     //save the old pen color 
 780     wxColour oldPenColour 
= m_pen
.GetColour(); 
 782     wxUint8 nR1 
= destColour
.Red(); 
 783     wxUint8 nG1 
= destColour
.Green(); 
 784     wxUint8 nB1 
= destColour
.Blue(); 
 785     wxUint8 nR2 
= initialColour
.Red(); 
 786     wxUint8 nG2 
= initialColour
.Green(); 
 787     wxUint8 nB2 
= initialColour
.Blue(); 
 792     wxInt32 cx 
= rect
.GetWidth() / 2; 
 793     wxInt32 cy 
= rect
.GetHeight() / 2; 
 801     wxInt32 nCircleOffX 
= circleCenter
.x 
- (rect
.GetWidth() / 2); 
 802     wxInt32 nCircleOffY 
= circleCenter
.y 
- (rect
.GetHeight() / 2); 
 804     for ( wxInt32 x 
= 0; x 
< rect
.GetWidth(); x
++ ) 
 806         for ( wxInt32 y 
= 0; y 
< rect
.GetHeight(); y
++ ) 
 808             //get color difference 
 809             wxInt32 nGradient 
= ((nRadius 
- 
 811                                     pow((double)(x 
- cx 
- nCircleOffX
), 2) + 
 812                                     pow((double)(y 
- cy 
- nCircleOffY
), 2) 
 820             nR 
= nR1 
+ ((nR2 
- nR1
) * nGradient 
/ 100); 
 821             nG 
= nG1 
+ ((nG2 
- nG1
) * nGradient 
/ 100); 
 822             nB 
= nB1 
+ ((nB2 
- nB1
) * nGradient 
/ 100); 
 825             m_pen
.SetColour(wxColour(nR
,nG
,nB
)); 
 826             DrawPoint(wxPoint(x 
+ rect
.GetLeft(), y 
+ rect
.GetTop())); 
 829     //return old pen color 
 830     m_pen
.SetColour(oldPenColour
); 
 834 Notes for wxWidgets DrawEllipticArcRot(...) 
 836 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse. 
 837 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...), 
 840 All methods are generic, so they can be implemented in wxDCBase. 
 841 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper 
 842 methods like (WinCE) wxDC::DoDrawArc(...). 
 844 CalculateEllipticPoints(...) fills a given list of wxPoints with some points 
 845 of an elliptic arc. The algorithm is pixel-based: In every row (in flat 
 846 parts) or every column (in steep parts) only one pixel is calculated. 
 847 Trigonometric calculation (sin, cos, tan, atan) is only done if the 
 848 starting angle is not equal to the ending angle. The calculation of the 
 849 pixels is done using simple arithmetic only and should perform not too 
 850 bad even on devices without floating point processor. I didn't test this yet. 
 852 Rotate(...) rotates a list of point pixel-based, you will see rounding errors. 
 853 For instance: an ellipse rotated 180 degrees is drawn 
 854 slightly different from the original. 
 856 The points are then moved to an array and used to draw a polyline and/or polygon 
 857 (with center added, the pie). 
 858 The result looks quite similar to the native ellipse, only e few pixels differ. 
 860 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times 
 861 slower as DrawEllipse(...), which calls the native API. 
 862 An rotated ellipse outside the clipping region takes nearly the same time, 
 863 while an native ellipse outside takes nearly no time to draw. 
 865 If you draw an arc with this new method, you will see the starting and ending angles 
 866 are calculated properly. 
 867 If you use DrawEllipticArc(...), you will see they are only correct for circles 
 868 and not properly calculated for ellipses. 
 871 p.lenhard@t-online.de 
 875 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
, 
 876                                      wxCoord w
, wxCoord h
, 
 877                                      double sa
, double ea
, double angle 
) 
 881     CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea 
); 
 882     Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) ); 
 884     // Add center (for polygon/pie) 
 885     list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) ); 
 887     // copy list into array and delete list elements 
 888     int n 
= list
.Number(); 
 889     wxPoint 
*points 
= new wxPoint
[n
]; 
 892     for ( node 
= list
.First(); node
; node 
= node
->Next(), i
++ ) 
 894         wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
 895         points
[i
].x 
= point
->x
; 
 896         points
[i
].y 
= point
->y
; 
 900     // first draw the pie without pen, if necessary 
 901     if( GetBrush() != *wxTRANSPARENT_BRUSH 
) 
 903         wxPen 
tempPen( GetPen() ); 
 904         SetPen( *wxTRANSPARENT_PEN 
); 
 905         DoDrawPolygon( n
, points
, 0, 0 ); 
 909     // then draw the arc without brush, if necessary 
 910     if( GetPen() != *wxTRANSPARENT_PEN 
) 
 913         DoDrawLines( n
-1, points
, 0, 0 ); 
 918 } // DrawEllipticArcRot 
 920 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center 
) 
 925         double dSinA 
= -sin(angle
*2.0*pi
/360.0); 
 926         double dCosA 
= cos(angle
*2.0*pi
/360.0); 
 927         for ( wxNode
* node 
= points
->First(); node
; node 
= node
->Next() ) 
 929             wxPoint
* point 
= (wxPoint
*)node
->Data(); 
 931             // transform coordinates, if necessary 
 932             if( center
.x 
) point
->x 
-= center
.x
; 
 933             if( center
.y 
) point
->y 
-= center
.y
; 
 935             // calculate rotation, rounding simply by implicit cast to integer 
 936             int xTemp 
= point
->x 
* dCosA 
- point
->y 
* dSinA
; 
 937             point
->y 
= point
->x 
* dSinA 
+ point
->y 
* dCosA
; 
 940             // back transform coordinates, if necessary 
 941             if( center
.x 
) point
->x 
+= center
.x
; 
 942             if( center
.y 
) point
->y 
+= center
.y
; 
 947 void wxDCBase::CalculateEllipticPoints( wxList
* points
, 
 948                                         wxCoord xStart
, wxCoord yStart
, 
 949                                         wxCoord w
, wxCoord h
, 
 950                                         double sa
, double ea 
) 
 961     bool bUseAngles 
= false; 
 967     // decrement 1 pixel if ellipse is smaller than 2*a, 2*b 
 969     if( 2*a 
== w 
) decrX 
= 1; 
 971     if( 2*b 
== h 
) decrY 
= 1; 
 973     wxCoord xCenter 
= xStart 
+ a
; 
 974     wxCoord yCenter 
= yStart 
+ b
; 
 975     // calculate data for start and end, if necessary 
 979         // normalisation of angles 
 980         while( sa
<0 ) sa 
+= 360; 
 981         while( ea
<0 ) ea 
+= 360; 
 982         while( sa
>=360 ) sa 
-= 360; 
 983         while( ea
>=360 ) ea 
-= 360; 
 984         // calculate quadrant numbers 
 985         if( sa 
> 270 ) sq 
= 3; 
 986         else if( sa 
> 180 ) sq 
= 2; 
 987         else if( sa 
> 90 ) sq 
= 1; 
 988         if( ea 
> 270 ) eq 
= 3; 
 989         else if( ea 
> 180 ) eq 
= 2; 
 990         else if( ea 
> 90 ) eq 
= 1; 
 991         sar 
= sa 
* pi 
/ 180.0; 
 992         ear 
= ea 
* pi 
/ 180.0; 
 993         // correct angle circle -> ellipse 
 994         sar 
= atan( -a
/(double)b 
* tan( sar 
) ); 
 995         if ( sq 
== 1 || sq 
== 2 ) sar 
+= pi
; 
 996         ear 
= atan( -a
/(double)b 
* tan( ear 
) ); 
 997         if ( eq 
== 1 || eq 
== 2 ) ear 
+= pi
; 
 998         // coordinates of points 
 999         xsa 
= xCenter 
+ a 
* cos( sar 
); 
1000         if( sq 
== 0 || sq 
== 3 ) xsa 
-= decrX
; 
1001         ysa 
= yCenter 
+ b 
* sin( sar 
); 
1002         if( sq 
== 2 || sq 
== 3 ) ysa 
-= decrY
; 
1003         xea 
= xCenter 
+ a 
* cos( ear 
); 
1004         if( eq 
== 0 || eq 
== 3 ) xea 
-= decrX
; 
1005         yea 
= yCenter 
+ b 
* sin( ear 
); 
1006         if( eq 
== 2 || eq 
== 3 ) yea 
-= decrY
; 
1008     // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2 
1010     double c2 
= 2.0 / w
; 
1019     // Lists for quadrant 1 to 4 
1020     wxList pointsarray
[4]; 
1021     // Calculate points for first quadrant and set in all quadrants 
1022     for( x 
= 0; x 
<= a
; ++x 
) 
1027         bool bNewPoint 
= false; 
1028         while( y2 
> c1 
- c2 
* x2 
&& y 
> 0 ) 
1034         // old y now to big: set point with old y, old x 
1035         if( bNewPoint 
&& x
>1) 
1038             // remove points on the same line 
1039             pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter 
+ x1 
- decrX
, yCenter 
- y_old 
) ); 
1040             pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter 
- x1
, yCenter 
- y_old 
) ); 
1041             pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter 
- x1
, yCenter 
+ y_old 
- decrY 
) ); 
1042             pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter 
+ x1 
- decrX
, yCenter 
+ y_old 
- decrY 
) ); 
1044     } // calculate point 
1046     // Starting and/or ending points for the quadrants, first quadrant gets both. 
1047     pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter 
+ a 
- decrX
, yCenter 
) ); 
1048     pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter 
- b 
) ); 
1049     pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter 
- a
, yCenter 
) ); 
1050     pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter 
+ b 
- decrY 
) ); 
1051     pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter 
+ a 
- decrX
, yCenter 
) ); 
1053     // copy quadrants in original list 
1056         // Copy the right part of the points in the lists 
1057         // and delete the wxPoints, because they do not leave this method. 
1058         points
->Append( (wxObject
*) new wxPoint( xsa
, ysa 
) ); 
1060         bool bStarted 
= false; 
1061         bool bReady 
= false; 
1062         bool bForceTurn 
= ( sq 
== eq 
&& sa 
> ea 
); 
1065             for( wxNode 
*node 
= pointsarray
[q
].First(); node
; node 
= node
->Next() ) 
1067                 // once: go to starting point in start quadrant 
1070                       ( (wxPoint
*) node
->Data() )->x 
< xsa
+1 && q 
<= 1 
1072                       ( (wxPoint
*) node
->Data() )->x 
> xsa
-1 && q 
>= 2 
1079                 // copy point, if not at ending point 
1082                     if( q 
!= eq 
|| bForceTurn
 
1084                         ( (wxPoint
*) node
->Data() )->x 
> xea
+1 && q 
<= 1 
1086                         ( (wxPoint
*) node
->Data() )->x 
< xea
-1 && q 
>= 2 
1090                         wxPoint
* pPoint 
= new wxPoint( *((wxPoint
*) node
->Data() ) ); 
1091                         points
->Append( (wxObject
*) pPoint 
); 
1093                     else if( q 
== eq 
&& !bForceTurn 
|| ( (wxPoint
*) node
->Data() )->x 
== xea
) 
1103         } // while not bReady 
1104         points
->Append( (wxObject
*) new wxPoint( xea
, yea 
) ); 
1107         for( q 
= 0; q 
< 4; ++q 
) 
1109             for( wxNode 
*node 
= pointsarray
[q
].First(); node
; node 
= node
->Next() ) 
1111                 wxPoint 
*p 
= (wxPoint 
*)node
->Data(); 
1118         // copy whole ellipse, wxPoints will be deleted outside 
1119         for( wxNode 
*node 
= pointsarray
[0].First(); node
; node 
= node
->Next() ) 
1121             wxObject 
*p 
= node
->Data(); 
1122             points
->Append( p 
); 
1124         for( node 
= pointsarray
[1].First(); node
; node 
= node
->Next() ) 
1126             wxObject 
*p 
= node
->Data(); 
1127             points
->Append( p 
); 
1129         for( node 
= pointsarray
[2].First(); node
; node 
= node
->Next() ) 
1131             wxObject 
*p 
= node
->Data(); 
1132             points
->Append( p 
); 
1134         for( node 
= pointsarray
[3].First(); node
; node 
= node
->Next() ) 
1136             wxObject 
*p 
= node
->Data(); 
1137             points
->Append( p 
); 
1140 } // CalculateEllipticPoints