1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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" 
  28 #include "wx/dcclient.h" 
  29 #include "wx/dcmemory.h" 
  30 #include "wx/dcscreen.h" 
  31 #include "wx/dcprint.h" 
  32 #include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS 
  33 #include "wx/prntbase.h" 
  42 #include "wx/msw/dcclient.h" 
  43 #include "wx/msw/dcmemory.h" 
  44 #include "wx/msw/dcscreen.h" 
  48 #include "wx/gtk/dcclient.h" 
  49 #include "wx/gtk/dcmemory.h" 
  50 #include "wx/gtk/dcscreen.h" 
  54 #include "wx/mac/dcclient.h" 
  55 #include "wx/mac/dcmemory.h" 
  56 #include "wx/mac/dcscreen.h" 
  60 #include "wx/x11/dcclient.h" 
  61 #include "wx/x11/dcmemory.h" 
  62 #include "wx/x11/dcscreen.h" 
  65 //---------------------------------------------------------------------------- 
  67 //---------------------------------------------------------------------------- 
  69 wxDCFactory 
*wxDCFactory::m_factory 
= NULL
; 
  71 void wxDCFactory::SetDCFactory( wxDCFactory 
*factory 
) 
  73     if (wxDCFactory::m_factory
) 
  74         delete wxDCFactory::m_factory
; 
  76     wxDCFactory::m_factory 
= factory
; 
  79 wxDCFactory 
*wxDCFactory::GetFactory() 
  81     if (!wxDCFactory::m_factory
) 
  82         wxDCFactory::m_factory 
= new wxNativeDCFactory
; 
  84     return wxDCFactory::m_factory
; 
  87 //----------------------------------------------------------------------------- 
  89 //----------------------------------------------------------------------------- 
  91 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC 
*owner 
) 
  93     return new wxWindowDCImpl( owner 
); 
  96 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC 
*owner
, wxWindow 
*window 
) 
  98     return new wxWindowDCImpl( owner
, window 
); 
 101 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC 
*owner 
) 
 103     return new wxClientDCImpl( owner 
); 
 106 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC 
*owner
, wxWindow 
*window 
) 
 108     return new wxClientDCImpl( owner
, window 
); 
 111 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC 
*owner 
) 
 113     return new wxPaintDCImpl( owner 
); 
 116 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC 
*owner
, wxWindow 
*window 
) 
 118     return new wxPaintDCImpl( owner
, window 
); 
 121 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC 
*owner 
) 
 123     return new wxMemoryDCImpl( owner 
); 
 126 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC 
*owner
, wxBitmap 
&bitmap 
) 
 128     return new wxMemoryDCImpl( owner
, bitmap 
); 
 131 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC 
*owner
, wxDC 
*dc 
) 
 133     return new wxMemoryDCImpl( owner
, dc 
); 
 136 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC 
*owner 
) 
 138     return new wxScreenDCImpl( owner 
); 
 141 wxDCImpl 
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC 
*owner
, const wxPrintData 
&data 
) 
 143     wxPrintFactory 
*factory 
= wxPrintFactory::GetFactory(); 
 144     return factory
->CreatePrinterDCImpl( owner
, data 
); 
 147 //----------------------------------------------------------------------------- 
 149 //----------------------------------------------------------------------------- 
 151 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
) 
 153 wxWindowDC::wxWindowDC() 
 157 wxWindowDC::wxWindowDC( wxWindow 
*win 
) 
 159     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 160     m_pimpl 
= factory
->CreateWindowDC( this, win 
); 
 163 //----------------------------------------------------------------------------- 
 165 //----------------------------------------------------------------------------- 
 167 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxWindowDC
) 
 169 wxClientDC::wxClientDC() 
 173 wxClientDC::wxClientDC( wxWindow 
*win 
) 
 175     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 176     m_pimpl 
= factory
->CreateClientDC( this, win 
); 
 179 //----------------------------------------------------------------------------- 
 181 //----------------------------------------------------------------------------- 
 183 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
) 
 185 wxMemoryDC::wxMemoryDC() 
 187     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 188     m_pimpl 
= factory
->CreateMemoryDC( this ); 
 191 wxMemoryDC::wxMemoryDC( wxBitmap
& bitmap 
) 
 193     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 194     m_pimpl 
= factory
->CreateMemoryDC( this, bitmap 
); 
 197 wxMemoryDC::wxMemoryDC( wxDC 
*dc 
) 
 199     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 200     m_pimpl 
= factory
->CreateMemoryDC( this, dc 
); 
 203 void wxMemoryDC::SelectObject(wxBitmap
& bmp
) 
 205     // make sure that the given wxBitmap is not sharing its data with other 
 206     // wxBitmap instances as its contents will be modified by any drawing 
 207     // operation done on this DC 
 211     GetImpl()->DoSelect(bmp
); 
 214 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
) 
 216     GetImpl()->DoSelect(bmp
); 
 219 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const 
 221     return GetImpl()->GetSelectedBitmap(); 
 224 wxBitmap
& wxMemoryDC::GetSelectedBitmap() 
 226     return GetImpl()->GetSelectedBitmap(); 
 230 //----------------------------------------------------------------------------- 
 232 //----------------------------------------------------------------------------- 
 234 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxClientDC
) 
 236 wxPaintDC::wxPaintDC() 
 240 wxPaintDC::wxPaintDC( wxWindow 
*win 
) 
 242     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 243     m_pimpl 
= factory
->CreatePaintDC( this, win 
); 
 246 //----------------------------------------------------------------------------- 
 248 //----------------------------------------------------------------------------- 
 250 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
) 
 252 wxScreenDC::wxScreenDC() 
 254     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 255     m_pimpl 
= factory
->CreateScreenDC( this ); 
 258 //----------------------------------------------------------------------------- 
 260 //----------------------------------------------------------------------------- 
 262 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
) 
 264 wxPrinterDC::wxPrinterDC() 
 266     wxPrintData data
;  // Does this make sense? 
 267     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 268     m_pimpl 
= factory
->CreatePrinterDC( this, data 
); 
 271 wxPrinterDC::wxPrinterDC( const wxPrintData 
&data 
) 
 273     wxDCFactory 
*factory 
= wxDCFactory::GetFactory(); 
 274     m_pimpl 
= factory
->CreatePrinterDC( this, data 
); 
 277 wxPrinterDC::~wxPrinterDC() 
 281 wxRect 
wxPrinterDC::GetPaperRect() 
 283     return GetImpl()->GetPaperRect(); 
 286 int wxPrinterDC::GetResolution() 
 288     return GetImpl()->GetResolution(); 
 292 //----------------------------------------------------------------------------- 
 294 //----------------------------------------------------------------------------- 
 296 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
) 
 298 wxDCImpl::wxDCImpl( wxDC 
*owner 
) 
 300         , m_colour(wxColourDisplay()) 
 304         , m_isBBoxValid(false) 
 305         , m_logicalOriginX(0), m_logicalOriginY(0) 
 306         , m_deviceOriginX(0), m_deviceOriginY(0) 
 307         , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0) 
 308         , m_logicalScaleX(1.0), m_logicalScaleY(1.0) 
 309         , m_userScaleX(1.0), m_userScaleY(1.0) 
 310         , m_scaleX(1.0), m_scaleY(1.0) 
 311         , m_signX(1), m_signY(1) 
 312         , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0) 
 313         , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0) 
 314         , m_logicalFunction(wxCOPY
) 
 315         , m_backgroundMode(wxTRANSPARENT
) 
 316         , m_mappingMode(wxMM_TEXT
) 
 319         , m_backgroundBrush(*wxTRANSPARENT_BRUSH
) 
 320         , m_textForegroundColour(*wxBLACK
) 
 321         , m_textBackgroundColour(*wxWHITE
) 
 325         , m_hasCustomPalette(false) 
 326 #endif // wxUSE_PALETTE 
 330     m_mm_to_pix_x 
= (double)wxGetDisplaySize().GetWidth() / 
 331                     (double)wxGetDisplaySizeMM().GetWidth(); 
 332     m_mm_to_pix_y 
= (double)wxGetDisplaySize().GetHeight() / 
 333                     (double)wxGetDisplaySizeMM().GetHeight(); 
 339 wxDCImpl::~wxDCImpl() 
 343 // ---------------------------------------------------------------------------- 
 344 // coordinate conversions and transforms 
 345 // ---------------------------------------------------------------------------- 
 347 wxCoord 
wxDCImpl::DeviceToLogicalX(wxCoord x
) const 
 349     return wxRound((double)(x 
- m_deviceOriginX 
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX 
+ m_logicalOriginX
; 
 352 wxCoord 
wxDCImpl::DeviceToLogicalY(wxCoord y
) const 
 354     return wxRound((double)(y 
- m_deviceOriginY 
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY 
+ m_logicalOriginY
; 
 357 wxCoord 
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const 
 359     return wxRound((double)(x
) / m_scaleX
); 
 362 wxCoord 
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const 
 364     return wxRound((double)(y
) / m_scaleY
); 
 367 wxCoord 
wxDCImpl::LogicalToDeviceX(wxCoord x
) const 
 369     return wxRound((double)(x 
- m_logicalOriginX
) * m_scaleX
) * m_signX 
+ m_deviceOriginX 
* m_signY 
+ m_deviceLocalOriginX
; 
 372 wxCoord 
wxDCImpl::LogicalToDeviceY(wxCoord y
) const 
 374     return wxRound((double)(y 
- m_logicalOriginY
) * m_scaleY
) * m_signY 
+ m_deviceOriginY 
* m_signY 
+ m_deviceLocalOriginY
; 
 377 wxCoord 
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const 
 379     return wxRound((double)(x
) * m_scaleX
); 
 382 wxCoord 
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const 
 384     return wxRound((double)(y
) * m_scaleY
); 
 387 void wxDCImpl::ComputeScaleAndOrigin() 
 389     m_scaleX 
= m_logicalScaleX 
* m_userScaleX
; 
 390     m_scaleY 
= m_logicalScaleY 
* m_userScaleY
; 
 393 void wxDCImpl::SetMapMode( int mode 
) 
 398           SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y 
); 
 401           SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y 
); 
 404           SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y 
); 
 407           SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 ); 
 411           SetLogicalScale( 1.0, 1.0 ); 
 414     m_mappingMode 
= mode
; 
 417 void wxDCImpl::SetUserScale( double x
, double y 
) 
 419     // allow negative ? -> no 
 422     ComputeScaleAndOrigin(); 
 425 void wxDCImpl::SetLogicalScale( double x
, double y 
) 
 430     ComputeScaleAndOrigin(); 
 433 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y 
) 
 435     m_logicalOriginX 
= x 
* m_signX
; 
 436     m_logicalOriginY 
= y 
* m_signY
; 
 437     ComputeScaleAndOrigin(); 
 440 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y 
) 
 444     ComputeScaleAndOrigin(); 
 447 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y 
) 
 449     m_deviceLocalOriginX 
= x
; 
 450     m_deviceLocalOriginY 
= y
; 
 451     ComputeScaleAndOrigin(); 
 454 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp 
) 
 456     // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there 
 457     // wxWidgets 2.9: no longer override it 
 458     m_signX 
= (xLeftRight 
?  1 : -1); 
 459     m_signY 
= (yBottomUp  
? -1 :  1); 
 460     ComputeScaleAndOrigin(); 
 464 // Each element of the widths array will be the width of the string up to and 
 465 // including the corresponding character in text.  This is the generic 
 466 // implementation, the port-specific classes should do this with native APIs 
 467 // if available and if faster.  Note: pango_layout_index_to_pos is much slower 
 468 // than calling GetTextExtent!! 
 475     FontWidthCache() : m_scaleX(1), m_widths(NULL
) { } 
 476     ~FontWidthCache() { delete []m_widths
; } 
 481             m_widths 
= new int[FWC_SIZE
]; 
 483         memset(m_widths
, 0, sizeof(int)*FWC_SIZE
); 
 491 static FontWidthCache s_fontWidthCache
; 
 493 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const 
 497     const size_t len 
= text
.length(); 
 501     // reset the cache if font or horizontal scale have changed 
 502     if ( !s_fontWidthCache
.m_widths 
|| 
 503          !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) || 
 504          (s_fontWidthCache
.m_font 
!= GetFont()) ) 
 506         s_fontWidthCache
.Reset(); 
 507         s_fontWidthCache
.m_font 
= GetFont(); 
 508         s_fontWidthCache
.m_scaleX 
= m_scaleX
; 
 511     // Calculate the position of each character based on the widths of 
 512     // the previous characters 
 514     for ( size_t i 
= 0; i 
< len
; i
++ ) 
 516         const wxChar c 
= text
[i
]; 
 517         unsigned int c_int 
= (unsigned int)c
; 
 519         if ((c_int 
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0)) 
 521             w 
= s_fontWidthCache
.m_widths
[c_int
]; 
 525             DoGetTextExtent(c
, &w
, &h
); 
 526             if (c_int 
< FWC_SIZE
) 
 527                 s_fontWidthCache
.m_widths
[c_int
] = w
; 
 531         widths
[i
] = totalWidth
; 
 537 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
, 
 541                                       const wxFont 
*font
) const 
 543     wxCoord widthTextMax 
= 0, widthLine
, 
 544             heightTextTotal 
= 0, heightLineDefault 
= 0, heightLine 
= 0; 
 547     for ( wxString::const_iterator pc 
= text
.begin(); ; ++pc 
) 
 549         if ( pc 
== text
.end() || *pc 
== _T('\n') ) 
 551             if ( curLine
.empty() ) 
 553                 // we can't use GetTextExtent - it will return 0 for both width 
 554                 // and height and an empty line should count in height 
 557                 // assume that this line has the same height as the previous 
 559                 if ( !heightLineDefault 
) 
 560                     heightLineDefault 
= heightLine
; 
 562                 if ( !heightLineDefault 
) 
 564                     // but we don't know it yet - choose something reasonable 
 565                     DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
, 
 569                 heightTextTotal 
+= heightLineDefault
; 
 573                 DoGetTextExtent(curLine
, &widthLine
, &heightLine
, 
 575                 if ( widthLine 
> widthTextMax 
) 
 576                     widthTextMax 
= widthLine
; 
 577                 heightTextTotal 
+= heightLine
; 
 580             if ( pc 
== text
.end() ) 
 598         *y 
= heightTextTotal
; 
 603 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
 604                                wxCoord width
, wxCoord height
) 
 606     wxCHECK_RET( IsOk(), wxT("invalid window dc") ); 
 608     wxCoord x2 
= x1 
+ width
, 
 611     // the pen width is calibrated to give 3 for width == height == 10 
 612     wxDCPenChanger 
pen( *m_owner
, wxPen(GetTextForeground(), (width 
+ height 
+ 1)/7)); 
 614     // we're drawing a scaled version of wx/generic/tick.xpm here 
 615     wxCoord x3 
= x1 
+ (4*width
) / 10,   // x of the tick bottom 
 616             y3 
= y1 
+ height 
/ 2;       // y of the left tick branch 
 617     DoDrawLine(x1
, y3
, x3
, y2
); 
 618     DoDrawLine(x3
, y2
, x2
, y1
); 
 620     CalcBoundingBox(x1
, y1
); 
 621     CalcBoundingBox(x2
, y2
); 
 625 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
, 
 626                         wxCoord dstWidth
, wxCoord dstHeight
, 
 628                         wxCoord xsrc
, wxCoord ysrc
, 
 629                         wxCoord srcWidth
, wxCoord srcHeight
, 
 635     wxCHECK_MSG( srcWidth 
&& srcHeight 
&& dstWidth 
&& dstHeight
, false, 
 636                  _T("invalid blit size") ); 
 638     // emulate the stretching by modifying the DC scale 
 639     double xscale 
= (double)srcWidth
/dstWidth
, 
 640            yscale 
= (double)srcHeight
/dstHeight
; 
 642     double xscaleOld
, yscaleOld
; 
 643     GetUserScale(&xscaleOld
, &yscaleOld
); 
 644     SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
); 
 646     bool rc 
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
), 
 647                      wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
), 
 649                      xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
); 
 651     SetUserScale(xscaleOld
, yscaleOld
); 
 656 void wxDCImpl::DrawLines(const wxPointList 
*list
, wxCoord xoffset
, wxCoord yoffset
) 
 658     int n 
= list
->GetCount(); 
 659     wxPoint 
*points 
= new wxPoint
[n
]; 
 662     for ( wxPointList::compatibility_iterator node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
 664         wxPoint 
*point 
= node
->GetData(); 
 665         points
[i
].x 
= point
->x
; 
 666         points
[i
].y 
= point
->y
; 
 669     DoDrawLines(n
, points
, xoffset
, yoffset
); 
 674 void wxDCImpl::DrawPolygon(const wxPointList 
*list
, 
 675                            wxCoord xoffset
, wxCoord yoffset
, 
 678     int n 
= list
->GetCount(); 
 679     wxPoint 
*points 
= new wxPoint
[n
]; 
 682     for ( wxPointList::compatibility_iterator node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
 684         wxPoint 
*point 
= node
->GetData(); 
 685         points
[i
].x 
= point
->x
; 
 686         points
[i
].y 
= point
->y
; 
 689     DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
); 
 695 wxDCImpl::DoDrawPolyPolygon(int n
, 
 698                             wxCoord xoffset
, wxCoord yoffset
, 
 703         DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
); 
 711     for (i 
= j 
= lastOfs 
= 0; i 
< n
; i
++) 
 716     pts 
= new wxPoint
[j
+n
-1]; 
 717     for (i 
= 0; i 
< j
; i
++) 
 719     for (i 
= 2; i 
<= n
; i
++) 
 721         lastOfs 
-= count
[n
-i
]; 
 722         pts
[j
++] = pts
[lastOfs
]; 
 726     SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
)); 
 727     DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
); 
 729     for (i 
= j 
= 0; i 
< n
; i
++) 
 731         DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
); 
 739 void wxDCImpl::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
) 
 741     wxPointList point_list
; 
 743     wxPoint 
*point1 
= new wxPoint
; 
 744     point1
->x 
= x1
; point1
->y 
= y1
; 
 745     point_list
.Append( point1 
); 
 747     wxPoint 
*point2 
= new wxPoint
; 
 748     point2
->x 
= x2
; point2
->y 
= y2
; 
 749     point_list
.Append( point2 
); 
 751     wxPoint 
*point3 
= new wxPoint
; 
 752     point3
->x 
= x3
; point3
->y 
= y3
; 
 753     point_list
.Append( point3 
); 
 755     DoDrawSpline(&point_list
); 
 757     for( wxPointList::compatibility_iterator node 
= point_list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 759         wxPoint 
*p 
= node
->GetData(); 
 764 void wxDCImpl::DoDrawSpline(int n
, wxPoint points
[]) 
 767     for (int i 
=0; i 
< n
; i
++) 
 768         list
.Append( &points
[i
] ); 
 773 // ----------------------------------- spline code ---------------------------------------- 
 775 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, 
 776                          double a3
, double b3
, double a4
, double b4
); 
 777 void wx_clear_stack(); 
 778 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
, 
 779         double *y3
, double *x4
, double *y4
); 
 780 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, 
 781           double x4
, double y4
); 
 782 static bool wx_spline_add_point(double x
, double y
); 
 783 static void wx_spline_draw_point_array(wxDC 
*dc
); 
 785 wxPointList wx_spline_point_list
; 
 787 #define                half(z1, z2)        ((z1+z2)/2.0) 
 790 /* iterative version */ 
 792 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
, 
 795     register double  xmid
, ymid
; 
 796     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
 799     wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
); 
 801     while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) { 
 802         xmid 
= (double)half(x2
, x3
); 
 803         ymid 
= (double)half(y2
, y3
); 
 804         if (fabs(x1 
- xmid
) < THRESHOLD 
&& fabs(y1 
- ymid
) < THRESHOLD 
&& 
 805             fabs(xmid 
- x4
) < THRESHOLD 
&& fabs(ymid 
- y4
) < THRESHOLD
) { 
 806             wx_spline_add_point( x1
, y1 
); 
 807             wx_spline_add_point( xmid
, ymid 
); 
 809             wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
), 
 810                  (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
); 
 811             wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
), 
 812                  (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
); 
 817 /* utilities used by spline drawing routines */ 
 819 typedef struct wx_spline_stack_struct 
{ 
 820     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
 823 #define         SPLINE_STACK_DEPTH             20 
 824 static Stack    wx_spline_stack
[SPLINE_STACK_DEPTH
]; 
 825 static Stack   
*wx_stack_top
; 
 826 static int      wx_stack_count
; 
 828 void wx_clear_stack() 
 830     wx_stack_top 
= wx_spline_stack
; 
 834 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
) 
 836     wx_stack_top
->x1 
= x1
; 
 837     wx_stack_top
->y1 
= y1
; 
 838     wx_stack_top
->x2 
= x2
; 
 839     wx_stack_top
->y2 
= y2
; 
 840     wx_stack_top
->x3 
= x3
; 
 841     wx_stack_top
->y3 
= y3
; 
 842     wx_stack_top
->x4 
= x4
; 
 843     wx_stack_top
->y4 
= y4
; 
 848 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, 
 849                   double *x3
, double *y3
, double *x4
, double *y4
) 
 851     if (wx_stack_count 
== 0) 
 855     *x1 
= wx_stack_top
->x1
; 
 856     *y1 
= wx_stack_top
->y1
; 
 857     *x2 
= wx_stack_top
->x2
; 
 858     *y2 
= wx_stack_top
->y2
; 
 859     *x3 
= wx_stack_top
->x3
; 
 860     *y3 
= wx_stack_top
->y3
; 
 861     *x4 
= wx_stack_top
->x4
; 
 862     *y4 
= wx_stack_top
->y4
; 
 866 static bool wx_spline_add_point(double x
, double y
) 
 868     wxPoint 
*point 
= new wxPoint( wxRound(x
), wxRound(y
) ); 
 869     wx_spline_point_list
.Append(point 
); 
 873 static void wx_spline_draw_point_array(wxDC 
*dc
) 
 875     dc
->DrawLines(&wx_spline_point_list
, 0, 0 ); 
 876     wxPointList::compatibility_iterator node 
= wx_spline_point_list
.GetFirst(); 
 879         wxPoint 
*point 
= node
->GetData(); 
 881         wx_spline_point_list
.Erase(node
); 
 882         node 
= wx_spline_point_list
.GetFirst(); 
 886 void wxDCImpl::DoDrawSpline( const wxPointList 
*points 
) 
 888     wxCHECK_RET( IsOk(), wxT("invalid window dc") ); 
 891     double           cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
; 
 892     double           x1
, y1
, x2
, y2
; 
 894     wxPointList::compatibility_iterator node 
= points
->GetFirst(); 
 899     p 
= (wxPoint 
*)node
->GetData(); 
 904     node 
= node
->GetNext(); 
 909     cx1 
= (double)((x1 
+ x2
) / 2); 
 910     cy1 
= (double)((y1 
+ y2
) / 2); 
 911     cx2 
= (double)((cx1 
+ x2
) / 2); 
 912     cy2 
= (double)((cy1 
+ y2
) / 2); 
 914     wx_spline_add_point(x1
, y1
); 
 916     while ((node 
= node
->GetNext()) 
 927         cx4 
= (double)(x1 
+ x2
) / 2; 
 928         cy4 
= (double)(y1 
+ y2
) / 2; 
 929         cx3 
= (double)(x1 
+ cx4
) / 2; 
 930         cy3 
= (double)(y1 
+ cy4
) / 2; 
 932         wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
); 
 936         cx2 
= (double)(cx1 
+ x2
) / 2; 
 937         cy2 
= (double)(cy1 
+ y2
) / 2; 
 940     wx_spline_add_point( cx1
, cy1 
); 
 941     wx_spline_add_point( x2
, y2 
); 
 943     wx_spline_draw_point_array( m_owner 
); 
 946 #endif // wxUSE_SPLINES 
 950 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
, 
 951                                     const wxColour
& initialColour
, 
 952                                     const wxColour
& destColour
, 
 953                                     wxDirection nDirection
) 
 956     wxPen oldPen 
= m_pen
; 
 957     wxBrush oldBrush 
= m_brush
; 
 959     wxUint8 nR1 
= initialColour
.Red(); 
 960     wxUint8 nG1 
= initialColour
.Green(); 
 961     wxUint8 nB1 
= initialColour
.Blue(); 
 962     wxUint8 nR2 
= destColour
.Red(); 
 963     wxUint8 nG2 
= destColour
.Green(); 
 964     wxUint8 nB2 
= destColour
.Blue(); 
 967     if ( nDirection 
== wxEAST 
|| nDirection 
== wxWEST 
) 
 969         wxInt32 x 
= rect
.GetWidth(); 
 970         wxInt32 w 
= x
;              // width of area to shade 
 971         wxInt32 xDelta 
= w
/256;     // height of one shade bend 
 979                 nR 
= nR1 
- (nR1
-nR2
)*(w
-x
)/w
; 
 981                 nR 
= nR1 
+ (nR2
-nR1
)*(w
-x
)/w
; 
 984                 nG 
= nG1 
- (nG1
-nG2
)*(w
-x
)/w
; 
 986                 nG 
= nG1 
+ (nG2
-nG1
)*(w
-x
)/w
; 
 989                 nB 
= nB1 
- (nB1
-nB2
)*(w
-x
)/w
; 
 991                 nB 
= nB1 
+ (nB2
-nB1
)*(w
-x
)/w
; 
 993             wxColour 
colour(nR
,nG
,nB
); 
 994             SetPen(wxPen(colour
, 1, wxSOLID
)); 
 995             SetBrush(wxBrush(colour
)); 
 996             if(nDirection 
== wxEAST
) 
 997                 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(), 
 998                         xDelta
, rect
.GetHeight()); 
 999             else //nDirection == wxWEST 
1000                 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(), 
1001                         xDelta
, rect
.GetHeight()); 
1004     else  // nDirection == wxNORTH || nDirection == wxSOUTH 
1006         wxInt32 y 
= rect
.GetHeight(); 
1007         wxInt32 w 
= y
;              // height of area to shade 
1008         wxInt32 yDelta 
= w
/255;     // height of one shade bend 
1016                 nR 
= nR1 
- (nR1
-nR2
)*(w
-y
)/w
; 
1018                 nR 
= nR1 
+ (nR2
-nR1
)*(w
-y
)/w
; 
1021                 nG 
= nG1 
- (nG1
-nG2
)*(w
-y
)/w
; 
1023                 nG 
= nG1 
+ (nG2
-nG1
)*(w
-y
)/w
; 
1026                 nB 
= nB1 
- (nB1
-nB2
)*(w
-y
)/w
; 
1028                 nB 
= nB1 
+ (nB2
-nB1
)*(w
-y
)/w
; 
1030             wxColour 
colour(nR
,nG
,nB
); 
1031             SetPen(wxPen(colour
, 1, wxSOLID
)); 
1032             SetBrush(wxBrush(colour
)); 
1033             if(nDirection 
== wxNORTH
) 
1034                 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
, 
1035                         rect
.GetWidth(), yDelta
); 
1036             else //nDirection == wxSOUTH 
1037                 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1, 
1038                         rect
.GetWidth(), yDelta
); 
1046 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
, 
1047                                       const wxColour
& initialColour
, 
1048                                       const wxColour
& destColour
, 
1049                                       const wxPoint
& circleCenter
) 
1051     //save the old pen color 
1052     wxColour oldPenColour 
= m_pen
.GetColour(); 
1054     wxUint8 nR1 
= destColour
.Red(); 
1055     wxUint8 nG1 
= destColour
.Green(); 
1056     wxUint8 nB1 
= destColour
.Blue(); 
1057     wxUint8 nR2 
= initialColour
.Red(); 
1058     wxUint8 nG2 
= initialColour
.Green(); 
1059     wxUint8 nB2 
= initialColour
.Blue(); 
1064     wxInt32 cx 
= rect
.GetWidth() / 2; 
1065     wxInt32 cy 
= rect
.GetHeight() / 2; 
1073     wxInt32 nCircleOffX 
= circleCenter
.x 
- (rect
.GetWidth() / 2); 
1074     wxInt32 nCircleOffY 
= circleCenter
.y 
- (rect
.GetHeight() / 2); 
1076     for ( wxInt32 x 
= 0; x 
< rect
.GetWidth(); x
++ ) 
1078         for ( wxInt32 y 
= 0; y 
< rect
.GetHeight(); y
++ ) 
1080             //get color difference 
1081             wxInt32 nGradient 
= ((nRadius 
- 
1083                                     pow((double)(x 
- cx 
- nCircleOffX
), 2) + 
1084                                     pow((double)(y 
- cy 
- nCircleOffY
), 2) 
1085                                   )) * 100) / nRadius
; 
1087             //normalize Gradient 
1092             nR 
= (wxUint8
)(nR1 
+ ((nR2 
- nR1
) * nGradient 
/ 100)); 
1093             nG 
= (wxUint8
)(nG1 
+ ((nG2 
- nG1
) * nGradient 
/ 100)); 
1094             nB 
= (wxUint8
)(nB1 
+ ((nB2 
- nB1
) * nGradient 
/ 100)); 
1097             m_pen
.SetColour(wxColour(nR
,nG
,nB
)); 
1098             DoDrawPoint(x 
+ rect
.GetLeft(), y 
+ rect
.GetTop()); 
1101     //return old pen color 
1102     m_pen
.SetColour(oldPenColour
); 
1105 //----------------------------------------------------------------------------- 
1107 //----------------------------------------------------------------------------- 
1109 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
) 
1111 void wxDC::DrawLabel(const wxString
& text
, 
1112                          const wxBitmap
& bitmap
, 
1116                          wxRect 
*rectBounding
) 
1118     // find the text position 
1119     wxCoord widthText
, heightText
, heightLine
; 
1120     GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
); 
1122     wxCoord width
, height
; 
1125         width 
= widthText 
+ bitmap
.GetWidth(); 
1126         height 
= bitmap
.GetHeight(); 
1131         height 
= heightText
; 
1135     if ( alignment 
& wxALIGN_RIGHT 
) 
1137         x 
= rect
.GetRight() - width
; 
1139     else if ( alignment 
& wxALIGN_CENTRE_HORIZONTAL 
) 
1141         x 
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2; 
1143     else // alignment & wxALIGN_LEFT 
1148     if ( alignment 
& wxALIGN_BOTTOM 
) 
1150         y 
= rect
.GetBottom() - height
; 
1152     else if ( alignment 
& wxALIGN_CENTRE_VERTICAL 
) 
1154         y 
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2; 
1156     else // alignment & wxALIGN_TOP 
1161     // draw the bitmap first 
1167         DrawBitmap(bitmap
, x
, y
, true /* use mask */); 
1169         wxCoord offset 
= bitmap
.GetWidth() + 4; 
1173         y 
+= (height 
- heightText
) / 2; 
1176     // we will draw the underscore under the accel char later 
1177     wxCoord startUnderscore 
= 0, 
1181     // split the string into lines and draw each of them separately 
1183     for ( wxString::const_iterator pc 
= text
.begin(); ; ++pc 
) 
1185         if ( *pc 
== _T('\n') || pc 
== text
.end() ) 
1187             int xRealStart 
= x
; // init it here to avoid compielr warnings 
1189             if ( !curLine
.empty() ) 
1191                 // NB: can't test for !(alignment & wxALIGN_LEFT) because 
1192                 //     wxALIGN_LEFT is 0 
1193                 if ( alignment 
& (wxALIGN_RIGHT 
| wxALIGN_CENTRE_HORIZONTAL
) ) 
1196                     GetTextExtent(curLine
, &widthLine
, NULL
); 
1198                     if ( alignment 
& wxALIGN_RIGHT 
) 
1200                         xRealStart 
+= width 
- widthLine
; 
1202                     else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) 
1204                         xRealStart 
+= (width 
- widthLine
) / 2; 
1207                 //else: left aligned, nothing to do 
1209                 DrawText(curLine
, xRealStart
, y
); 
1214             // do we have underscore in this line? we can check yUnderscore 
1215             // because it is set below to just y + heightLine if we do 
1216             if ( y 
== yUnderscore 
) 
1218                 // adjust the horz positions to account for the shift 
1219                 startUnderscore 
+= xRealStart
; 
1220                 endUnderscore 
+= xRealStart
; 
1223             if ( pc 
== text
.end() ) 
1228         else // not end of line 
1230             if ( pc 
- text
.begin() == indexAccel 
) 
1232                 // remeber to draw underscore here 
1233                 GetTextExtent(curLine
, &startUnderscore
, NULL
); 
1235                 GetTextExtent(curLine
, &endUnderscore
, NULL
); 
1237                 yUnderscore 
= y 
+ heightLine
; 
1246     // draw the underscore if found 
1247     if ( startUnderscore 
!= endUnderscore 
) 
1249         // it should be of the same colour as text 
1250         SetPen(wxPen(GetTextForeground(), 0, wxSOLID
)); 
1254         DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
); 
1257     // return bounding rect if requested 
1260         *rectBounding 
= wxRect(x
, y 
- heightText
, widthText
, heightText
); 
1263     CalcBoundingBox(x0
, y0
); 
1264     CalcBoundingBox(x0 
+ width0
, y0 
+ height
); 
1267 #if WXWIN_COMPATIBILITY_2_8 
1268     // for compatibility with the old code when wxCoord was long everywhere 
1269 void wxDC::GetTextExtent(const wxString
& string
, 
1272                        long *externalLeading
, 
1273                        const wxFont 
*theFont
) const 
1275         wxCoord x2
, y2
, descent2
, externalLeading2
; 
1276         m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
, 
1277                         &descent2
, &externalLeading2
, 
1284             *descent 
= descent2
; 
1285         if ( externalLeading 
) 
1286             *externalLeading 
= externalLeading2
; 
1289 void wxDC::GetLogicalOrigin(long *x
, long *y
) const  
1292         m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
); 
1299 void wxDC::GetDeviceOrigin(long *x
, long *y
) const  
1302         m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
); 
1309 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const  
1311         wxCoord xx
,yy
,ww
,hh
; 
1312         m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
); 
1319 #endif  // WXWIN_COMPATIBILITY_2_8 
1322 #else  // wxUSE_NEW_DC 
1325 // bool wxDCBase::sm_cacheing = false; 
1327 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
) 
1329 // ============================================================================ 
1331 // ============================================================================ 
1333 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
) 
1334 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
) 
1336 wxDCBase::wxDCBase() 
1337         : m_colour(wxColourDisplay()) 
1340         , m_isInteractive(0) 
1341         , m_isBBoxValid(false) 
1342         , m_logicalOriginX(0), m_logicalOriginY(0) 
1343         , m_deviceOriginX(0), m_deviceOriginY(0) 
1344         , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0) 
1345         , m_logicalScaleX(1.0), m_logicalScaleY(1.0) 
1346         , m_userScaleX(1.0), m_userScaleY(1.0) 
1347         , m_scaleX(1.0), m_scaleY(1.0) 
1348         , m_signX(1), m_signY(1) 
1349         , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0) 
1350         , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0) 
1351         , m_logicalFunction(wxCOPY
) 
1352         , m_backgroundMode(wxTRANSPARENT
) 
1353         , m_mappingMode(wxMM_TEXT
) 
1356         , m_backgroundBrush(*wxTRANSPARENT_BRUSH
) 
1357         , m_textForegroundColour(*wxBLACK
) 
1358         , m_textBackgroundColour(*wxWHITE
) 
1362         , m_hasCustomPalette(false) 
1363 #endif // wxUSE_PALETTE 
1365     m_mm_to_pix_x 
= (double)wxGetDisplaySize().GetWidth() / 
1366                     (double)wxGetDisplaySizeMM().GetWidth(); 
1367     m_mm_to_pix_y 
= (double)wxGetDisplaySize().GetHeight() / 
1368                     (double)wxGetDisplaySizeMM().GetHeight(); 
1374 wxDCBase::~wxDCBase() 
1378 #if WXWIN_COMPATIBILITY_2_6 
1379 void wxDCBase::BeginDrawing() 
1383 void wxDCBase::EndDrawing() 
1386 #endif // WXWIN_COMPATIBILITY_2_6 
1388 #if WXWIN_COMPATIBILITY_2_8 
1389     // for compatibility with the old code when wxCoord was long everywhere 
1390 void wxDCBase::GetTextExtent(const wxString
& string
, 
1393                        long *externalLeading
, 
1394                        const wxFont 
*theFont
) const 
1396         wxCoord x2
, y2
, descent2
, externalLeading2
; 
1397         DoGetTextExtent(string
, &x2
, &y2
, 
1398                         &descent2
, &externalLeading2
, 
1405             *descent 
= descent2
; 
1406         if ( externalLeading 
) 
1407             *externalLeading 
= externalLeading2
; 
1410 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const  
1413         DoGetLogicalOrigin(&x2
, &y2
); 
1420 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const  
1423         DoGetDeviceOrigin(&x2
, &y2
); 
1430 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const  
1432         wxCoord xx
,yy
,ww
,hh
; 
1433         DoGetClippingBox(&xx
, &yy
, &ww
, &hh
); 
1439 #endif  // WXWIN_COMPATIBILITY_2_8 
1443 // ---------------------------------------------------------------------------- 
1444 // coordinate conversions and transforms 
1445 // ---------------------------------------------------------------------------- 
1447 wxCoord 
wxDCBase::DeviceToLogicalX(wxCoord x
) const 
1449     return wxRound((double)(x 
- m_deviceOriginX 
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX 
+ m_logicalOriginX
; 
1452 wxCoord 
wxDCBase::DeviceToLogicalY(wxCoord y
) const 
1454     return wxRound((double)(y 
- m_deviceOriginY 
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY 
+ m_logicalOriginY
; 
1457 wxCoord 
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const 
1459     return wxRound((double)(x
) / m_scaleX
); 
1462 wxCoord 
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const 
1464     return wxRound((double)(y
) / m_scaleY
); 
1467 wxCoord 
wxDCBase::LogicalToDeviceX(wxCoord x
) const 
1469     return wxRound((double)(x 
- m_logicalOriginX
) * m_scaleX
) * m_signX 
+ m_deviceOriginX 
+ m_deviceLocalOriginX
; 
1472 wxCoord 
wxDCBase::LogicalToDeviceY(wxCoord y
) const 
1474     return wxRound((double)(y 
- m_logicalOriginY
) * m_scaleY
) * m_signY 
+ m_deviceOriginY 
+ m_deviceLocalOriginY
; 
1477 wxCoord 
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const 
1479     return wxRound((double)(x
) * m_scaleX
); 
1482 wxCoord 
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const 
1484     return wxRound((double)(y
) * m_scaleY
); 
1487 void wxDCBase::ComputeScaleAndOrigin() 
1489     m_scaleX 
= m_logicalScaleX 
* m_userScaleX
; 
1490     m_scaleY 
= m_logicalScaleY 
* m_userScaleY
; 
1493 void wxDCBase::SetMapMode( int mode 
) 
1498           SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y 
); 
1501           SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y 
); 
1504           SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y 
); 
1507           SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 ); 
1511           SetLogicalScale( 1.0, 1.0 ); 
1514     m_mappingMode 
= mode
; 
1517 void wxDCBase::SetUserScale( double x
, double y 
) 
1519     // allow negative ? -> no 
1522     ComputeScaleAndOrigin(); 
1525 void wxDCBase::SetLogicalScale( double x
, double y 
) 
1528     m_logicalScaleX 
= x
; 
1529     m_logicalScaleY 
= y
; 
1530     ComputeScaleAndOrigin(); 
1533 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y 
) 
1535     m_logicalOriginX 
= x 
* m_signX
; 
1536     m_logicalOriginY 
= y 
* m_signY
; 
1537     ComputeScaleAndOrigin(); 
1540 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y 
) 
1542     m_deviceOriginX 
= x
; 
1543     m_deviceOriginY 
= y
; 
1544     ComputeScaleAndOrigin(); 
1547 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y 
) 
1549     m_deviceLocalOriginX 
= x
; 
1550     m_deviceLocalOriginY 
= y
; 
1551     ComputeScaleAndOrigin(); 
1554 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp 
) 
1556     // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there 
1557     // wxWidgets 2.9: no longer override it 
1558     m_signX 
= (xLeftRight 
?  1 : -1); 
1559     m_signY 
= (yBottomUp  
? -1 :  1); 
1560     ComputeScaleAndOrigin(); 
1563 // ---------------------------------------------------------------------------- 
1565 // ---------------------------------------------------------------------------- 
1567 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
1568                                wxCoord width
, wxCoord height
) 
1570     wxCHECK_RET( Ok(), wxT("invalid window dc") ); 
1572     wxCoord x2 
= x1 
+ width
, 
1575     // the pen width is calibrated to give 3 for width == height == 10 
1576     wxDCPenChanger 
pen((wxDC
&)*this, 
1577                         wxPen(GetTextForeground(), (width 
+ height 
+ 1)/7)); 
1579     // we're drawing a scaled version of wx/generic/tick.xpm here 
1580     wxCoord x3 
= x1 
+ (4*width
) / 10,   // x of the tick bottom 
1581             y3 
= y1 
+ height 
/ 2;       // y of the left tick branch 
1582     DoDrawLine(x1
, y3
, x3
, y2
); 
1583     DoDrawLine(x3
, y2
, x2
, y1
); 
1585     CalcBoundingBox(x1
, y1
); 
1586     CalcBoundingBox(x2
, y2
); 
1589 // ---------------------------------------------------------------------------- 
1590 // stubs for functions not implemented in all ports 
1591 // ---------------------------------------------------------------------------- 
1594 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
, 
1595                         wxCoord dstWidth
, wxCoord dstHeight
, 
1597                         wxCoord xsrc
, wxCoord ysrc
, 
1598                         wxCoord srcWidth
, wxCoord srcHeight
, 
1604     wxCHECK_MSG( srcWidth 
&& srcHeight 
&& dstWidth 
&& dstHeight
, false, 
1605                  _T("invalid blit size") ); 
1607     // emulate the stretching by modifying the DC scale 
1608     double xscale 
= (double)srcWidth
/dstWidth
, 
1609            yscale 
= (double)srcHeight
/dstHeight
; 
1611     double xscaleOld
, yscaleOld
; 
1612     GetUserScale(&xscaleOld
, &yscaleOld
); 
1613     SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
); 
1615     bool rc 
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
), 
1616                      wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
), 
1618                      xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
); 
1620     SetUserScale(xscaleOld
, yscaleOld
); 
1625 // ---------------------------------------------------------------------------- 
1627 // ---------------------------------------------------------------------------- 
1629 void wxDCBase::DrawLines(const wxPointList 
*list
, wxCoord xoffset
, wxCoord yoffset
) 
1631     unsigned int n 
= list
->GetCount(); 
1632     wxPoint 
*points 
= new wxPoint
[n
]; 
1635     wxPointList::compatibility_iterator node
; 
1636     for ( node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
1638         wxPoint 
*point 
= node
->GetData(); 
1639         points
[i
].x 
= point
->x
; 
1640         points
[i
].y 
= point
->y
; 
1643     DoDrawLines(n
, points
, xoffset
, yoffset
); 
1648 #if WXWIN_COMPATIBILITY_2_8 
1649 void wxDCBase::DrawLines(const wxList 
*list
, wxCoord xoffset
, wxCoord yoffset 
) 
1651     unsigned int n 
= list
->GetCount(); 
1652     wxPoint 
*points 
= new wxPoint
[n
]; 
1655     wxObjectList::compatibility_iterator node
; 
1656     for ( node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
1658         wxPoint 
*point 
= (wxPoint
*) node
->GetData(); 
1659         points
[i
].x 
= point
->x
; 
1660         points
[i
].y 
= point
->y
; 
1663     DoDrawLines(n
, points
, xoffset
, yoffset
); 
1667 #endif  // WXWIN_COMPATIBILITY_2_8 
1670 void wxDCBase::DrawPolygon(const wxPointList 
*list
, 
1671                            wxCoord xoffset
, wxCoord yoffset
, 
1674     unsigned int n 
= list
->GetCount(); 
1675     wxPoint 
*points 
= new wxPoint
[n
]; 
1678     wxPointList::compatibility_iterator node
; 
1679     for ( node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
1681         wxPoint 
*point 
= node
->GetData(); 
1682         points
[i
].x 
= point
->x
; 
1683         points
[i
].y 
= point
->y
; 
1686     DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
); 
1692 #if WXWIN_COMPATIBILITY_2_8 
1693 void wxDCBase::DrawPolygon(const wxList 
*list
, 
1694                      wxCoord xoffset
, wxCoord yoffset
, 
1697     unsigned int n 
= list
->GetCount(); 
1698     wxPoint 
*points 
= new wxPoint
[n
]; 
1701     wxObjectList::compatibility_iterator node
; 
1702     for ( node 
= list
->GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
1704         wxPoint 
*point 
= (wxPoint
*) node
->GetData(); 
1705         points
[i
].x 
= point
->x
; 
1706         points
[i
].y 
= point
->y
; 
1709     DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
); 
1713 #endif  // WXWIN_COMPATIBILITY_2_8 
1716 wxDCBase::DoDrawPolyPolygon(int n
, 
1719                             wxCoord xoffset
, wxCoord yoffset
, 
1724         DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
); 
1732     for (i 
= j 
= lastOfs 
= 0; i 
< n
; i
++) 
1737     pts 
= new wxPoint
[j
+n
-1]; 
1738     for (i 
= 0; i 
< j
; i
++) 
1740     for (i 
= 2; i 
<= n
; i
++) 
1742         lastOfs 
-= count
[n
-i
]; 
1743         pts
[j
++] = pts
[lastOfs
]; 
1747     SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
)); 
1748     DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
); 
1750     for (i 
= j 
= 0; i 
< n
; i
++) 
1752         DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
); 
1758 // ---------------------------------------------------------------------------- 
1760 // ---------------------------------------------------------------------------- 
1764 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
) 
1766     wxPointList point_list
; 
1768     wxPoint 
*point1 
= new wxPoint
; 
1769     point1
->x 
= x1
; point1
->y 
= y1
; 
1770     point_list
.Append( point1 
); 
1772     wxPoint 
*point2 
= new wxPoint
; 
1773     point2
->x 
= x2
; point2
->y 
= y2
; 
1774     point_list
.Append( point2 
); 
1776     wxPoint 
*point3 
= new wxPoint
; 
1777     point3
->x 
= x3
; point3
->y 
= y3
; 
1778     point_list
.Append( point3 
); 
1780     DrawSpline(&point_list
); 
1782     for( wxPointList::compatibility_iterator node 
= point_list
.GetFirst(); node
; node 
= node
->GetNext() ) 
1784         wxPoint 
*p 
= node
->GetData(); 
1789 void wxDCBase::DrawSpline(int n
, wxPoint points
[]) 
1792     for (int i 
=0; i 
< n
; i
++) 
1793         list
.Append( &points
[i
] ); 
1798 // ----------------------------------- spline code ---------------------------------------- 
1800 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, 
1801                          double a3
, double b3
, double a4
, double b4
); 
1802 void wx_clear_stack(); 
1803 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
, 
1804         double *y3
, double *x4
, double *y4
); 
1805 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, 
1806           double x4
, double y4
); 
1807 static bool wx_spline_add_point(double x
, double y
); 
1808 static void wx_spline_draw_point_array(wxDCBase 
*dc
); 
1810 wxPointList wx_spline_point_list
; 
1812 #define                half(z1, z2)        ((z1+z2)/2.0) 
1815 /* iterative version */ 
1817 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
, 
1820     register double  xmid
, ymid
; 
1821     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1824     wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
); 
1826     while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) { 
1827         xmid 
= (double)half(x2
, x3
); 
1828         ymid 
= (double)half(y2
, y3
); 
1829         if (fabs(x1 
- xmid
) < THRESHOLD 
&& fabs(y1 
- ymid
) < THRESHOLD 
&& 
1830             fabs(xmid 
- x4
) < THRESHOLD 
&& fabs(ymid 
- y4
) < THRESHOLD
) { 
1831             wx_spline_add_point( x1
, y1 
); 
1832             wx_spline_add_point( xmid
, ymid 
); 
1834             wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
), 
1835                  (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
); 
1836             wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
), 
1837                  (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
); 
1842 /* utilities used by spline drawing routines */ 
1844 typedef struct wx_spline_stack_struct 
{ 
1845     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1848 #define         SPLINE_STACK_DEPTH             20 
1849 static Stack    wx_spline_stack
[SPLINE_STACK_DEPTH
]; 
1850 static Stack   
*wx_stack_top
; 
1851 static int      wx_stack_count
; 
1853 void wx_clear_stack() 
1855     wx_stack_top 
= wx_spline_stack
; 
1859 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
) 
1861     wx_stack_top
->x1 
= x1
; 
1862     wx_stack_top
->y1 
= y1
; 
1863     wx_stack_top
->x2 
= x2
; 
1864     wx_stack_top
->y2 
= y2
; 
1865     wx_stack_top
->x3 
= x3
; 
1866     wx_stack_top
->y3 
= y3
; 
1867     wx_stack_top
->x4 
= x4
; 
1868     wx_stack_top
->y4 
= y4
; 
1873 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, 
1874                   double *x3
, double *y3
, double *x4
, double *y4
) 
1876     if (wx_stack_count 
== 0) 
1880     *x1 
= wx_stack_top
->x1
; 
1881     *y1 
= wx_stack_top
->y1
; 
1882     *x2 
= wx_stack_top
->x2
; 
1883     *y2 
= wx_stack_top
->y2
; 
1884     *x3 
= wx_stack_top
->x3
; 
1885     *y3 
= wx_stack_top
->y3
; 
1886     *x4 
= wx_stack_top
->x4
; 
1887     *y4 
= wx_stack_top
->y4
; 
1891 static bool wx_spline_add_point(double x
, double y
) 
1893     wxPoint 
*point 
= new wxPoint( wxRound(x
), wxRound(y
) ); 
1894     wx_spline_point_list
.Append( point 
); 
1898 static void wx_spline_draw_point_array(wxDCBase 
*dc
) 
1900     dc
->DrawLines(&wx_spline_point_list
, 0, 0 ); 
1901     wxPointList::compatibility_iterator node 
= wx_spline_point_list
.GetFirst(); 
1904         wxPoint 
*point 
= node
->GetData(); 
1906         wx_spline_point_list
.Erase(node
); 
1907         node 
= wx_spline_point_list
.GetFirst(); 
1911 #if WXWIN_COMPATIBILITY_2_8 
1912 void wxDCBase::DrawSpline(const wxList 
*points
) 
1915     wxObjectList::compatibility_iterator node 
= points
->GetFirst(); 
1918         list
.Append( (wxPoint
*) node
->GetData() ); 
1919         node 
= node
->GetNext(); 
1921     DoDrawSpline( &list 
); 
1923 #endif  // WXWIN_COMPATIBILITY_2_8 
1925 void wxDCBase::DoDrawSpline( const wxPointList 
*points 
) 
1927     wxCHECK_RET( Ok(), wxT("invalid window dc") ); 
1930     double           cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
; 
1931     double           x1
, y1
, x2
, y2
; 
1933     wxPointList::compatibility_iterator node 
= points
->GetFirst(); 
1938     p 
= node
->GetData(); 
1943     node 
= node
->GetNext(); 
1944     p 
= node
->GetData(); 
1948     cx1 
= (double)((x1 
+ x2
) / 2); 
1949     cy1 
= (double)((y1 
+ y2
) / 2); 
1950     cx2 
= (double)((cx1 
+ x2
) / 2); 
1951     cy2 
= (double)((cy1 
+ y2
) / 2); 
1953     wx_spline_add_point(x1
, y1
); 
1955     while ((node 
= node
->GetNext()) 
1958 #endif // !wxUSE_STL 
1961         p 
= node
->GetData(); 
1966         cx4 
= (double)(x1 
+ x2
) / 2; 
1967         cy4 
= (double)(y1 
+ y2
) / 2; 
1968         cx3 
= (double)(x1 
+ cx4
) / 2; 
1969         cy3 
= (double)(y1 
+ cy4
) / 2; 
1971         wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
); 
1975         cx2 
= (double)(cx1 
+ x2
) / 2; 
1976         cy2 
= (double)(cy1 
+ y2
) / 2; 
1979     wx_spline_add_point( cx1
, cy1 
); 
1980     wx_spline_add_point( x2
, y2 
); 
1982     wx_spline_draw_point_array( this ); 
1985 #endif // wxUSE_SPLINES 
1987 // ---------------------------------------------------------------------------- 
1988 // Partial Text Extents 
1989 // ---------------------------------------------------------------------------- 
1992 // Each element of the widths array will be the width of the string up to and 
1993 // including the corresponding character in text.  This is the generic 
1994 // implementation, the port-specific classes should do this with native APIs 
1995 // if available and if faster.  Note: pango_layout_index_to_pos is much slower 
1996 // than calling GetTextExtent!! 
1998 #define FWC_SIZE 256 
2000 class FontWidthCache
 
2003     FontWidthCache() : m_scaleX(1), m_widths(NULL
) { } 
2004     ~FontWidthCache() { delete []m_widths
; } 
2009             m_widths 
= new int[FWC_SIZE
]; 
2011         memset(m_widths
, 0, sizeof(int)*FWC_SIZE
); 
2019 static FontWidthCache s_fontWidthCache
; 
2021 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const 
2025     const size_t len 
= text
.length(); 
2029     // reset the cache if font or horizontal scale have changed 
2030     if ( !s_fontWidthCache
.m_widths 
|| 
2031          !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) || 
2032          (s_fontWidthCache
.m_font 
!= GetFont()) ) 
2034         s_fontWidthCache
.Reset(); 
2035         s_fontWidthCache
.m_font 
= GetFont(); 
2036         s_fontWidthCache
.m_scaleX 
= m_scaleX
; 
2039     // Calculate the position of each character based on the widths of 
2040     // the previous characters 
2042     for ( size_t i 
= 0; i 
< len
; i
++ ) 
2044         const wxChar c 
= text
[i
]; 
2045         unsigned int c_int 
= (unsigned int)c
; 
2047         if ((c_int 
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0)) 
2049             w 
= s_fontWidthCache
.m_widths
[c_int
]; 
2053             GetTextExtent(c
, &w
, &h
); 
2054             if (c_int 
< FWC_SIZE
) 
2055                 s_fontWidthCache
.m_widths
[c_int
] = w
; 
2059         widths
[i
] = totalWidth
; 
2066 // ---------------------------------------------------------------------------- 
2067 // enhanced text drawing 
2068 // ---------------------------------------------------------------------------- 
2070 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
, 
2074                                       const wxFont 
*font
) const 
2076     wxCoord widthTextMax 
= 0, widthLine
, 
2077             heightTextTotal 
= 0, heightLineDefault 
= 0, heightLine 
= 0; 
2080     for ( wxString::const_iterator pc 
= text
.begin(); ; ++pc 
) 
2082         if ( pc 
== text
.end() || *pc 
== _T('\n') ) 
2084             if ( curLine
.empty() ) 
2086                 // we can't use GetTextExtent - it will return 0 for both width 
2087                 // and height and an empty line should count in height 
2090                 // assume that this line has the same height as the previous 
2092                 if ( !heightLineDefault 
) 
2093                     heightLineDefault 
= heightLine
; 
2095                 if ( !heightLineDefault 
) 
2097                     // but we don't know it yet - choose something reasonable 
2098                     GetTextExtent(_T("W"), NULL
, &heightLineDefault
, 
2102                 heightTextTotal 
+= heightLineDefault
; 
2106                 GetTextExtent(curLine
, &widthLine
, &heightLine
, 
2108                 if ( widthLine 
> widthTextMax 
) 
2109                     widthTextMax 
= widthLine
; 
2110                 heightTextTotal 
+= heightLine
; 
2113             if ( pc 
== text
.end() ) 
2131         *y 
= heightTextTotal
; 
2136 void wxDCBase::DrawLabel(const wxString
& text
, 
2137                          const wxBitmap
& bitmap
, 
2141                          wxRect 
*rectBounding
) 
2143     // find the text position 
2144     wxCoord widthText
, heightText
, heightLine
; 
2145     GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
); 
2147     wxCoord width
, height
; 
2150         width 
= widthText 
+ bitmap
.GetWidth(); 
2151         height 
= bitmap
.GetHeight(); 
2156         height 
= heightText
; 
2160     if ( alignment 
& wxALIGN_RIGHT 
) 
2162         x 
= rect
.GetRight() - width
; 
2164     else if ( alignment 
& wxALIGN_CENTRE_HORIZONTAL 
) 
2166         x 
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2; 
2168     else // alignment & wxALIGN_LEFT 
2173     if ( alignment 
& wxALIGN_BOTTOM 
) 
2175         y 
= rect
.GetBottom() - height
; 
2177     else if ( alignment 
& wxALIGN_CENTRE_VERTICAL 
) 
2179         y 
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2; 
2181     else // alignment & wxALIGN_TOP 
2186     // draw the bitmap first 
2192         DrawBitmap(bitmap
, x
, y
, true /* use mask */); 
2194         wxCoord offset 
= bitmap
.GetWidth() + 4; 
2198         y 
+= (height 
- heightText
) / 2; 
2201     // we will draw the underscore under the accel char later 
2202     wxCoord startUnderscore 
= 0, 
2206     // split the string into lines and draw each of them separately 
2208     for ( wxString::const_iterator pc 
= text
.begin(); ; ++pc 
) 
2210         if ( pc 
== text
.end() || *pc 
== _T('\n') ) 
2212             int xRealStart 
= x
; // init it here to avoid compielr warnings 
2214             if ( !curLine
.empty() ) 
2216                 // NB: can't test for !(alignment & wxALIGN_LEFT) because 
2217                 //     wxALIGN_LEFT is 0 
2218                 if ( alignment 
& (wxALIGN_RIGHT 
| wxALIGN_CENTRE_HORIZONTAL
) ) 
2221                     GetTextExtent(curLine
, &widthLine
, NULL
); 
2223                     if ( alignment 
& wxALIGN_RIGHT 
) 
2225                         xRealStart 
+= width 
- widthLine
; 
2227                     else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) 
2229                         xRealStart 
+= (width 
- widthLine
) / 2; 
2232                 //else: left aligned, nothing to do 
2234                 DrawText(curLine
, xRealStart
, y
); 
2239             // do we have underscore in this line? we can check yUnderscore 
2240             // because it is set below to just y + heightLine if we do 
2241             if ( y 
== yUnderscore 
) 
2243                 // adjust the horz positions to account for the shift 
2244                 startUnderscore 
+= xRealStart
; 
2245                 endUnderscore 
+= xRealStart
; 
2248             if ( pc 
== text
.end() ) 
2253         else // not end of line 
2255             if ( pc 
- text
.begin() == indexAccel 
) 
2257                 // remeber to draw underscore here 
2258                 GetTextExtent(curLine
, &startUnderscore
, NULL
); 
2260                 GetTextExtent(curLine
, &endUnderscore
, NULL
); 
2262                 yUnderscore 
= y 
+ heightLine
; 
2271     // draw the underscore if found 
2272     if ( startUnderscore 
!= endUnderscore 
) 
2274         // it should be of the same colour as text 
2275         SetPen(wxPen(GetTextForeground(), 0, wxSOLID
)); 
2279         DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
); 
2282     // return bounding rect if requested 
2285         *rectBounding 
= wxRect(x
, y 
- heightText
, widthText
, heightText
); 
2288     CalcBoundingBox(x0
, y0
); 
2289     CalcBoundingBox(x0 
+ width0
, y0 
+ height
); 
2293 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
, 
2294                                     const wxColour
& initialColour
, 
2295                                     const wxColour
& destColour
, 
2296                                     wxDirection nDirection
) 
2299     wxPen oldPen 
= m_pen
; 
2300     wxBrush oldBrush 
= m_brush
; 
2302     wxUint8 nR1 
= initialColour
.Red(); 
2303     wxUint8 nG1 
= initialColour
.Green(); 
2304     wxUint8 nB1 
= initialColour
.Blue(); 
2305     wxUint8 nR2 
= destColour
.Red(); 
2306     wxUint8 nG2 
= destColour
.Green(); 
2307     wxUint8 nB2 
= destColour
.Blue(); 
2310     if ( nDirection 
== wxEAST 
|| nDirection 
== wxWEST 
) 
2312         wxInt32 x 
= rect
.GetWidth(); 
2313         wxInt32 w 
= x
;              // width of area to shade 
2314         wxInt32 xDelta 
= w
/256;     // height of one shade bend 
2322                 nR 
= nR1 
- (nR1
-nR2
)*(w
-x
)/w
; 
2324                 nR 
= nR1 
+ (nR2
-nR1
)*(w
-x
)/w
; 
2327                 nG 
= nG1 
- (nG1
-nG2
)*(w
-x
)/w
; 
2329                 nG 
= nG1 
+ (nG2
-nG1
)*(w
-x
)/w
; 
2332                 nB 
= nB1 
- (nB1
-nB2
)*(w
-x
)/w
; 
2334                 nB 
= nB1 
+ (nB2
-nB1
)*(w
-x
)/w
; 
2336             wxColour 
colour(nR
,nG
,nB
); 
2337             SetPen(wxPen(colour
, 1, wxSOLID
)); 
2338             SetBrush(wxBrush(colour
)); 
2339             if(nDirection 
== wxEAST
) 
2340                 DrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(), 
2341                         xDelta
, rect
.GetHeight()); 
2342             else //nDirection == wxWEST 
2343                 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(), 
2344                         xDelta
, rect
.GetHeight()); 
2347     else  // nDirection == wxNORTH || nDirection == wxSOUTH 
2349         wxInt32 y 
= rect
.GetHeight(); 
2350         wxInt32 w 
= y
;              // height of area to shade 
2351         wxInt32 yDelta 
= w
/255;     // height of one shade bend 
2359                 nR 
= nR1 
- (nR1
-nR2
)*(w
-y
)/w
; 
2361                 nR 
= nR1 
+ (nR2
-nR1
)*(w
-y
)/w
; 
2364                 nG 
= nG1 
- (nG1
-nG2
)*(w
-y
)/w
; 
2366                 nG 
= nG1 
+ (nG2
-nG1
)*(w
-y
)/w
; 
2369                 nB 
= nB1 
- (nB1
-nB2
)*(w
-y
)/w
; 
2371                 nB 
= nB1 
+ (nB2
-nB1
)*(w
-y
)/w
; 
2373             wxColour 
colour(nR
,nG
,nB
); 
2374             SetPen(wxPen(colour
, 1, wxSOLID
)); 
2375             SetBrush(wxBrush(colour
)); 
2376             if(nDirection 
== wxNORTH
) 
2377                 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
, 
2378                         rect
.GetWidth(), yDelta
); 
2379             else //nDirection == wxSOUTH 
2380                 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1, 
2381                         rect
.GetWidth(), yDelta
); 
2389 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
, 
2390                                       const wxColour
& initialColour
, 
2391                                       const wxColour
& destColour
, 
2392                                       const wxPoint
& circleCenter
) 
2394     //save the old pen color 
2395     wxColour oldPenColour 
= m_pen
.GetColour(); 
2397     wxUint8 nR1 
= destColour
.Red(); 
2398     wxUint8 nG1 
= destColour
.Green(); 
2399     wxUint8 nB1 
= destColour
.Blue(); 
2400     wxUint8 nR2 
= initialColour
.Red(); 
2401     wxUint8 nG2 
= initialColour
.Green(); 
2402     wxUint8 nB2 
= initialColour
.Blue(); 
2407     wxInt32 cx 
= rect
.GetWidth() / 2; 
2408     wxInt32 cy 
= rect
.GetHeight() / 2; 
2416     wxInt32 nCircleOffX 
= circleCenter
.x 
- (rect
.GetWidth() / 2); 
2417     wxInt32 nCircleOffY 
= circleCenter
.y 
- (rect
.GetHeight() / 2); 
2419     for ( wxInt32 x 
= 0; x 
< rect
.GetWidth(); x
++ ) 
2421         for ( wxInt32 y 
= 0; y 
< rect
.GetHeight(); y
++ ) 
2423             //get color difference 
2424             wxInt32 nGradient 
= ((nRadius 
- 
2426                                     pow((double)(x 
- cx 
- nCircleOffX
), 2) + 
2427                                     pow((double)(y 
- cy 
- nCircleOffY
), 2) 
2428                                   )) * 100) / nRadius
; 
2430             //normalize Gradient 
2435             nR 
= (wxUint8
)(nR1 
+ ((nR2 
- nR1
) * nGradient 
/ 100)); 
2436             nG 
= (wxUint8
)(nG1 
+ ((nG2 
- nG1
) * nGradient 
/ 100)); 
2437             nB 
= (wxUint8
)(nB1 
+ ((nB2 
- nB1
) * nGradient 
/ 100)); 
2440             m_pen
.SetColour(wxColour(nR
,nG
,nB
)); 
2441             DrawPoint(wxPoint(x 
+ rect
.GetLeft(), y 
+ rect
.GetTop())); 
2444     //return old pen color 
2445     m_pen
.SetColour(oldPenColour
); 
2449 Notes for wxWidgets DrawEllipticArcRot(...) 
2451 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse. 
2452 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...), 
2455 All methods are generic, so they can be implemented in wxDCBase. 
2456 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper 
2457 methods like (WinCE) wxDC::DoDrawArc(...). 
2459 CalculateEllipticPoints(...) fills a given list of wxPoints with some points 
2460 of an elliptic arc. The algorithm is pixel-based: In every row (in flat 
2461 parts) or every column (in steep parts) only one pixel is calculated. 
2462 Trigonometric calculation (sin, cos, tan, atan) is only done if the 
2463 starting angle is not equal to the ending angle. The calculation of the 
2464 pixels is done using simple arithmetic only and should perform not too 
2465 bad even on devices without floating point processor. I didn't test this yet. 
2467 Rotate(...) rotates a list of point pixel-based, you will see rounding errors. 
2468 For instance: an ellipse rotated 180 degrees is drawn 
2469 slightly different from the original. 
2471 The points are then moved to an array and used to draw a polyline and/or polygon 
2472 (with center added, the pie). 
2473 The result looks quite similar to the native ellipse, only e few pixels differ. 
2475 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times 
2476 slower as DrawEllipse(...), which calls the native API. 
2477 An rotated ellipse outside the clipping region takes nearly the same time, 
2478 while an native ellipse outside takes nearly no time to draw. 
2480 If you draw an arc with this new method, you will see the starting and ending angles 
2481 are calculated properly. 
2482 If you use DrawEllipticArc(...), you will see they are only correct for circles 
2483 and not properly calculated for ellipses. 
2486 p.lenhard@t-online.de 
2490 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
, 
2491                                      wxCoord w
, wxCoord h
, 
2492                                      double sa
, double ea
, double angle 
) 
2496     CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea 
); 
2497     Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) ); 
2499     // Add center (for polygon/pie) 
2500     list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) ); 
2502     // copy list into array and delete list elements 
2503     int n 
= list
.GetCount(); 
2504     wxPoint 
*points 
= new wxPoint
[n
]; 
2506     wxPointList::compatibility_iterator node
; 
2507     for ( node 
= list
.GetFirst(); node
; node 
= node
->GetNext(), i
++ ) 
2509         wxPoint 
*point 
= node
->GetData(); 
2510         points
[i
].x 
= point
->x
; 
2511         points
[i
].y 
= point
->y
; 
2515     // first draw the pie without pen, if necessary 
2516     if( GetBrush() != *wxTRANSPARENT_BRUSH 
) 
2518         wxPen 
tempPen( GetPen() ); 
2519         SetPen( *wxTRANSPARENT_PEN 
); 
2520         DoDrawPolygon( n
, points
, 0, 0 ); 
2524     // then draw the arc without brush, if necessary 
2525     if( GetPen() != *wxTRANSPARENT_PEN 
) 
2528         DoDrawLines( n
-1, points
, 0, 0 ); 
2533 } // DrawEllipticArcRot 
2535 void wxDCBase::Rotate( wxPointList
* points
, double angle
, wxPoint center 
) 
2540         double dSinA 
= -sin(angle
*2.0*pi
/360.0); 
2541         double dCosA 
= cos(angle
*2.0*pi
/360.0); 
2542         wxPointList::compatibility_iterator node
; 
2543         for ( node 
= points
->GetFirst(); node
; node 
= node
->GetNext() ) 
2545             wxPoint
* point 
= node
->GetData(); 
2547             // transform coordinates, if necessary 
2548             if( center
.x 
) point
->x 
-= center
.x
; 
2549             if( center
.y 
) point
->y 
-= center
.y
; 
2551             // calculate rotation, rounding simply by implicit cast to integer 
2552             int xTemp 
= point
->x 
* dCosA 
- point
->y 
* dSinA
; 
2553             point
->y 
= point
->x 
* dSinA 
+ point
->y 
* dCosA
; 
2556             // back transform coordinates, if necessary 
2557             if( center
.x 
) point
->x 
+= center
.x
; 
2558             if( center
.y 
) point
->y 
+= center
.y
; 
2563 void wxDCBase::CalculateEllipticPoints( wxPointList
* points
, 
2564                                         wxCoord xStart
, wxCoord yStart
, 
2565                                         wxCoord w
, wxCoord h
, 
2566                                         double sa
, double ea 
) 
2577     bool bUseAngles 
= false; 
2583     // decrement 1 pixel if ellipse is smaller than 2*a, 2*b 
2585     if( 2*a 
== w 
) decrX 
= 1; 
2587     if( 2*b 
== h 
) decrY 
= 1; 
2589     wxCoord xCenter 
= xStart 
+ a
; 
2590     wxCoord yCenter 
= yStart 
+ b
; 
2591     // calculate data for start and end, if necessary 
2595         // normalisation of angles 
2596         while( sa
<0 ) sa 
+= 360; 
2597         while( ea
<0 ) ea 
+= 360; 
2598         while( sa
>=360 ) sa 
-= 360; 
2599         while( ea
>=360 ) ea 
-= 360; 
2600         // calculate quadrant numbers 
2601         if( sa 
> 270 ) sq 
= 3; 
2602         else if( sa 
> 180 ) sq 
= 2; 
2603         else if( sa 
> 90 ) sq 
= 1; 
2604         if( ea 
> 270 ) eq 
= 3; 
2605         else if( ea 
> 180 ) eq 
= 2; 
2606         else if( ea 
> 90 ) eq 
= 1; 
2607         sar 
= sa 
* pi 
/ 180.0; 
2608         ear 
= ea 
* pi 
/ 180.0; 
2609         // correct angle circle -> ellipse 
2610         sar 
= atan( -a
/(double)b 
* tan( sar 
) ); 
2611         if ( sq 
== 1 || sq 
== 2 ) sar 
+= pi
; 
2612         ear 
= atan( -a
/(double)b 
* tan( ear 
) ); 
2613         if ( eq 
== 1 || eq 
== 2 ) ear 
+= pi
; 
2614         // coordinates of points 
2615         xsa 
= xCenter 
+ a 
* cos( sar 
); 
2616         if( sq 
== 0 || sq 
== 3 ) xsa 
-= decrX
; 
2617         ysa 
= yCenter 
+ b 
* sin( sar 
); 
2618         if( sq 
== 2 || sq 
== 3 ) ysa 
-= decrY
; 
2619         xea 
= xCenter 
+ a 
* cos( ear 
); 
2620         if( eq 
== 0 || eq 
== 3 ) xea 
-= decrX
; 
2621         yea 
= yCenter 
+ b 
* sin( ear 
); 
2622         if( eq 
== 2 || eq 
== 3 ) yea 
-= decrY
; 
2624     // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2 
2626     double c2 
= 2.0 / w
; 
2635     // Lists for quadrant 1 to 4 
2636     wxPointList pointsarray
[4]; 
2637     // Calculate points for first quadrant and set in all quadrants 
2638     for( x 
= 0; x 
<= a
; ++x 
) 
2643         bool bNewPoint 
= false; 
2644         while( y2 
> c1 
- c2 
* x2 
&& y 
> 0 ) 
2650         // old y now to big: set point with old y, old x 
2651         if( bNewPoint 
&& x
>1) 
2654             // remove points on the same line 
2655             pointsarray
[0].Insert( new wxPoint( xCenter 
+ x1 
- decrX
, yCenter 
- y_old 
) ); 
2656             pointsarray
[1].Append( new wxPoint( xCenter 
- x1
, yCenter 
- y_old 
) ); 
2657             pointsarray
[2].Insert( new wxPoint( xCenter 
- x1
, yCenter 
+ y_old 
- decrY 
) ); 
2658             pointsarray
[3].Append( new wxPoint( xCenter 
+ x1 
- decrX
, yCenter 
+ y_old 
- decrY 
) ); 
2660     } // calculate point 
2662     // Starting and/or ending points for the quadrants, first quadrant gets both. 
2663     pointsarray
[0].Insert( new wxPoint( xCenter 
+ a 
- decrX
, yCenter 
) ); 
2664     pointsarray
[0].Append( new wxPoint( xCenter
, yCenter 
- b 
) ); 
2665     pointsarray
[1].Append( new wxPoint( xCenter 
- a
, yCenter 
) ); 
2666     pointsarray
[2].Append( new wxPoint( xCenter
, yCenter 
+ b 
- decrY 
) ); 
2667     pointsarray
[3].Append( new wxPoint( xCenter 
+ a 
- decrX
, yCenter 
) ); 
2669     // copy quadrants in original list 
2672         // Copy the right part of the points in the lists 
2673         // and delete the wxPoints, because they do not leave this method. 
2674         points
->Append( new wxPoint( xsa
, ysa 
) ); 
2676         bool bStarted 
= false; 
2677         bool bReady 
= false; 
2678         bool bForceTurn 
= ( sq 
== eq 
&& sa 
> ea 
); 
2681             wxPointList::compatibility_iterator node
; 
2682             for( node 
= pointsarray
[q
].GetFirst(); node
; node 
= node
->GetNext() ) 
2684                 // once: go to starting point in start quadrant 
2687                       node
->GetData()->x 
< xsa
+1 && q 
<= 1 
2689                       node
->GetData()->x 
> xsa
-1 && q 
>= 2 
2696                 // copy point, if not at ending point 
2699                     if( q 
!= eq 
|| bForceTurn
 
2701                         ( (wxPoint
*) node
->GetData() )->x 
> xea
+1 && q 
<= 1 
2703                         ( (wxPoint
*) node
->GetData() )->x 
< xea
-1 && q 
>= 2 
2707                         wxPoint
* pPoint 
= new wxPoint( *(node
->GetData()) ); 
2708                         points
->Append( pPoint 
); 
2710                     else if( q 
== eq 
&& !bForceTurn 
|| node
->GetData()->x 
== xea
) 
2720         } // while not bReady 
2721         points
->Append( new wxPoint( xea
, yea 
) ); 
2724         for( q 
= 0; q 
< 4; ++q 
) 
2726             wxPointList::compatibility_iterator node
; 
2727             for( node 
= pointsarray
[q
].GetFirst(); node
; node 
= node
->GetNext() ) 
2729                 wxPoint 
*p 
= node
->GetData(); 
2736         wxPointList::compatibility_iterator node
; 
2737         // copy whole ellipse, wxPoints will be deleted outside 
2738         for( node 
= pointsarray
[0].GetFirst(); node
; node 
= node
->GetNext() ) 
2740             wxPoint 
*p 
= node
->GetData(); 
2741             points
->Append( p 
); 
2743         for( node 
= pointsarray
[1].GetFirst(); node
; node 
= node
->GetNext() ) 
2745             wxPoint 
*p 
= node
->GetData(); 
2746             points
->Append( p 
); 
2748         for( node 
= pointsarray
[2].GetFirst(); node
; node 
= node
->GetNext() ) 
2750             wxPoint 
*p 
= node
->GetData(); 
2751             points
->Append( p 
); 
2753         for( node 
= pointsarray
[3].GetFirst(); node
; node 
= node
->GetNext() ) 
2755             wxPoint 
*p 
= node
->GetData(); 
2756             points
->Append( p 
); 
2759 } // CalculateEllipticPoints 
2761 #endif // __WXWINCE__ 
2763 #endif  // wxUSE_NEW_DC