1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        common/dcbase.cpp 
   3 // Purpose:     generic methods of the wxDC Class 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) wxWindows team 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  17     #pragma implementation "dcbase.h" 
  20 // ---------------------------------------------------------------------------- 
  22 // ---------------------------------------------------------------------------- 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  35 // bool wxDCBase::sm_cacheing = FALSE; 
  37 // ============================================================================ 
  39 // ============================================================================ 
  41 // ---------------------------------------------------------------------------- 
  43 // ---------------------------------------------------------------------------- 
  45 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
  46                                wxCoord width
, wxCoord height
) 
  48     wxCHECK_RET( Ok(), wxT("invalid window dc") ); 
  50     wxCoord x2 
= x1 
+ width
, 
  53     // this is to yield width of 3 for width == height == 10 
  54     SetPen(wxPen(GetTextForeground(), (width 
+ height 
+ 1) / 7, wxSOLID
)); 
  56     // we're drawing a scaled version of wx/generic/tick.xpm here 
  57     wxCoord x3 
= x1 
+ (4*width
) / 10,   // x of the tick bottom 
  58             y3 
= y1 
+ height 
/ 2;       // y of the left tick branch 
  59     DoDrawLine(x1
, y3
, x3
, y2
); 
  60     DoDrawLine(x3
, y2
, x2
, y1
); 
  62     CalcBoundingBox(x1
, y1
); 
  63     CalcBoundingBox(x2
, y2
); 
  66 // ---------------------------------------------------------------------------- 
  68 // ---------------------------------------------------------------------------- 
  70 void wxDCBase::DrawLines(const wxList 
*list
, wxCoord xoffset
, wxCoord yoffset
) 
  72     int n 
= list
->Number(); 
  73     wxPoint 
*points 
= new wxPoint
[n
]; 
  76     for ( wxNode 
*node 
= list
->First(); node
; node 
= node
->Next(), i
++ ) 
  78         wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
  79         points
[i
].x 
= point
->x
; 
  80         points
[i
].y 
= point
->y
; 
  83     DoDrawLines(n
, points
, xoffset
, yoffset
); 
  89 void wxDCBase::DrawPolygon(const wxList 
*list
, 
  90                            wxCoord xoffset
, wxCoord yoffset
, 
  93     int n 
= list
->Number(); 
  94     wxPoint 
*points 
= new wxPoint
[n
]; 
  97     for ( wxNode 
*node 
= list
->First(); node
; node 
= node
->Next(), i
++ ) 
  99         wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
 100         points
[i
].x 
= point
->x
; 
 101         points
[i
].y 
= point
->y
; 
 104     DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
); 
 109 // ---------------------------------------------------------------------------- 
 111 // ---------------------------------------------------------------------------- 
 115 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) 
 116 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
) 
 120     wxPoint 
*point1 
= new wxPoint
; 
 121     point1
->x 
= x1
; point1
->y 
= y1
; 
 122     point_list
.Append((wxObject
*)point1
); 
 124     wxPoint 
*point2 
= new wxPoint
; 
 125     point2
->x 
= x2
; point2
->y 
= y2
; 
 126     point_list
.Append((wxObject
*)point2
); 
 128     wxPoint 
*point3 
= new wxPoint
; 
 129     point3
->x 
= x3
; point3
->y 
= y3
; 
 130     point_list
.Append((wxObject
*)point3
); 
 132     DrawSpline(&point_list
); 
 134     for( wxNode 
*node 
= point_list
.First(); node
; node 
= node
->Next() ) 
 136         wxPoint 
*p 
= (wxPoint 
*)node
->Data(); 
 141 void wxDCBase::DrawSpline(int n
, wxPoint points
[]) 
 144     for (int i 
=0; i 
< n
; i
++) 
 146         list
.Append((wxObject
*)&points
[i
]); 
 152 // ----------------------------------- spline code ---------------------------------------- 
 154 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, 
 155                          double a3
, double b3
, double a4
, double b4
); 
 156 void wx_clear_stack(); 
 157 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
, 
 158         double *y3
, double *x4
, double *y4
); 
 159 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, 
 160           double x4
, double y4
); 
 161 static bool wx_spline_add_point(double x
, double y
); 
 162 static void wx_spline_draw_point_array(wxDCBase 
*dc
); 
 164 wxList wx_spline_point_list
; 
 166 #define                half(z1, z2)        ((z1+z2)/2.0) 
 169 /* iterative version */ 
 171 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
, 
 174     register double  xmid
, ymid
; 
 175     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
 178     wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
); 
 180     while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) { 
 181         xmid 
= (double)half(x2
, x3
); 
 182         ymid 
= (double)half(y2
, y3
); 
 183         if (fabs(x1 
- xmid
) < THRESHOLD 
&& fabs(y1 
- ymid
) < THRESHOLD 
&& 
 184             fabs(xmid 
- x4
) < THRESHOLD 
&& fabs(ymid 
- y4
) < THRESHOLD
) { 
 185             wx_spline_add_point( x1
, y1 
); 
 186             wx_spline_add_point( xmid
, ymid 
); 
 188             wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
), 
 189                  (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
); 
 190             wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
), 
 191                  (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
); 
 196 /* utilities used by spline drawing routines */ 
 198 typedef struct wx_spline_stack_struct 
{ 
 199     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
 202 #define         SPLINE_STACK_DEPTH             20 
 203 static Stack    wx_spline_stack
[SPLINE_STACK_DEPTH
]; 
 204 static Stack   
*wx_stack_top
; 
 205 static int      wx_stack_count
; 
 207 void wx_clear_stack() 
 209     wx_stack_top 
= wx_spline_stack
; 
 213 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
) 
 215     wx_stack_top
->x1 
= x1
; 
 216     wx_stack_top
->y1 
= y1
; 
 217     wx_stack_top
->x2 
= x2
; 
 218     wx_stack_top
->y2 
= y2
; 
 219     wx_stack_top
->x3 
= x3
; 
 220     wx_stack_top
->y3 
= y3
; 
 221     wx_stack_top
->x4 
= x4
; 
 222     wx_stack_top
->y4 
= y4
; 
 227 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, 
 228                   double *x3
, double *y3
, double *x4
, double *y4
) 
 230     if (wx_stack_count 
== 0) 
 234     *x1 
= wx_stack_top
->x1
; 
 235     *y1 
= wx_stack_top
->y1
; 
 236     *x2 
= wx_stack_top
->x2
; 
 237     *y2 
= wx_stack_top
->y2
; 
 238     *x3 
= wx_stack_top
->x3
; 
 239     *y3 
= wx_stack_top
->y3
; 
 240     *x4 
= wx_stack_top
->x4
; 
 241     *y4 
= wx_stack_top
->y4
; 
 245 static bool wx_spline_add_point(double x
, double y
) 
 247   wxPoint 
*point 
= new wxPoint 
; 
 250   wx_spline_point_list
.Append((wxObject
*)point
); 
 254 static void wx_spline_draw_point_array(wxDCBase 
*dc
) 
 256   dc
->DrawLines(&wx_spline_point_list
, 0, 0 ); 
 257   wxNode 
*node 
= wx_spline_point_list
.First(); 
 260     wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
 263     node 
= wx_spline_point_list
.First(); 
 267 void wxDCBase::DoDrawSpline( wxList 
*points 
) 
 269     wxCHECK_RET( Ok(), wxT("invalid window dc") ); 
 272     double           cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
; 
 273     double           x1
, y1
, x2
, y2
; 
 275     wxNode 
*node 
= points
->First(); 
 276     p 
= (wxPoint 
*)node
->Data(); 
 282     p 
= (wxPoint 
*)node
->Data(); 
 286     cx1 
= (double)((x1 
+ x2
) / 2); 
 287     cy1 
= (double)((y1 
+ y2
) / 2); 
 288     cx2 
= (double)((cx1 
+ x2
) / 2); 
 289     cy2 
= (double)((cy1 
+ y2
) / 2); 
 291     wx_spline_add_point(x1
, y1
); 
 293     while ((node 
= node
->Next()) != NULL
) 
 295         p 
= (wxPoint 
*)node
->Data(); 
 300         cx4 
= (double)(x1 
+ x2
) / 2; 
 301         cy4 
= (double)(y1 
+ y2
) / 2; 
 302         cx3 
= (double)(x1 
+ cx4
) / 2; 
 303         cy3 
= (double)(y1 
+ cy4
) / 2; 
 305         wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
); 
 309         cx2 
= (double)(cx1 
+ x2
) / 2; 
 310         cy2 
= (double)(cy1 
+ y2
) / 2; 
 313     wx_spline_add_point( cx1
, cy1 
); 
 314     wx_spline_add_point( x2
, y2 
); 
 316     wx_spline_draw_point_array( this ); 
 319 #endif // wxUSE_SPLINES 
 321 // ---------------------------------------------------------------------------- 
 322 // enhanced text drawing 
 323 // ---------------------------------------------------------------------------- 
 325 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
, 
 331     wxCoord widthTextMax 
= 0, widthLine
, 
 332             heightTextTotal 
= 0, heightLineDefault 
= 0, heightLine 
= 0; 
 335     for ( const wxChar 
*pc 
= text
; ; pc
++ ) 
 337         if ( *pc 
== _T('\n') || *pc 
== _T('\0') ) 
 339             if ( curLine
.empty() ) 
 341                 // we can't use GetTextExtent - it will return 0 for both width 
 342                 // and height and an empty line should count in height 
 345                 // assume that this line has the same height as the previous 
 347                 if ( !heightLineDefault 
) 
 348                     heightLineDefault 
= heightLine
; 
 350                 if ( !heightLineDefault 
) 
 352                     // but we don't know it yet - choose something reasonable 
 353                     GetTextExtent(_T("W"), NULL
, &heightLineDefault
, 
 357                 heightTextTotal 
+= heightLineDefault
; 
 361                 GetTextExtent(curLine
, &widthLine
, &heightLine
, 
 363                 if ( widthLine 
> widthTextMax 
) 
 364                     widthTextMax 
= widthLine
; 
 365                 heightTextTotal 
+= heightLine
; 
 368             if ( *pc 
== _T('\n') ) 
 387         *y 
= heightTextTotal
; 
 392 void wxDCBase::DrawLabel(const wxString
& text
, 
 393                          const wxBitmap
& bitmap
, 
 397                          wxRect 
*rectBounding
) 
 399     // find the text position 
 400     wxCoord widthText
, heightText
, heightLine
; 
 401     GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
); 
 403     wxCoord width
, height
; 
 406         width 
= widthText 
+ bitmap
.GetWidth(); 
 407         height 
= bitmap
.GetHeight(); 
 416     if ( alignment 
& wxALIGN_RIGHT 
) 
 418         x 
= rect
.GetRight() - width
; 
 420     else if ( alignment 
& wxALIGN_CENTRE_HORIZONTAL 
) 
 422         x 
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2; 
 424     else // alignment & wxALIGN_LEFT 
 429     if ( alignment 
& wxALIGN_BOTTOM 
) 
 431         y 
= rect
.GetBottom() - height
; 
 433     else if ( alignment 
& wxALIGN_CENTRE_VERTICAL 
) 
 435         y 
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2; 
 437     else // alignment & wxALIGN_TOP 
 442     // draw the bitmap first 
 448         DrawBitmap(bitmap
, x
, y
, TRUE 
/* use mask */); 
 450         wxCoord offset 
= bitmap
.GetWidth() + 4; 
 454         y 
+= (height 
- heightText
) / 2; 
 457     // we will draw the underscore under the accel char later 
 458     wxCoord startUnderscore 
= 0, 
 462     // split the string into lines and draw each of them separately 
 464     for ( const wxChar 
*pc 
= text
; ; pc
++ ) 
 466         if ( *pc 
== _T('\n') || *pc 
== _T('\0') ) 
 468             int xRealStart 
= x
; // init it here to avoid compielr warnings 
 470             if ( !curLine
.empty() ) 
 472                 // NB: can't test for !(alignment & wxALIGN_LEFT) because 
 474                 if ( alignment 
& (wxALIGN_RIGHT 
| wxALIGN_CENTRE_HORIZONTAL
) ) 
 477                     GetTextExtent(curLine
, &widthLine
, NULL
); 
 479                     if ( alignment 
& wxALIGN_RIGHT 
) 
 481                         xRealStart 
+= width 
- widthLine
; 
 483                     else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) 
 485                         xRealStart 
+= (width 
- widthLine
) / 2; 
 488                 //else: left aligned, nothing to do 
 490                 DrawText(curLine
, xRealStart
, y
); 
 495             // do we have underscore in this line? we can check yUnderscore 
 496             // because it is set below to just y + heightLine if we do 
 497             if ( y 
== yUnderscore 
) 
 499                 // adjust the horz positions to account for the shift 
 500                 startUnderscore 
+= xRealStart
; 
 501                 endUnderscore 
+= xRealStart
; 
 504             if ( *pc 
== _T('\0') ) 
 509         else // not end of line 
 511             if ( pc 
- text
.c_str() == indexAccel 
) 
 513                 // remeber to draw underscore here 
 514                 GetTextExtent(curLine
, &startUnderscore
, NULL
); 
 516                 GetTextExtent(curLine
, &endUnderscore
, NULL
); 
 518                 yUnderscore 
= y 
+ heightLine
; 
 527     // draw the underscore if found 
 528     if ( startUnderscore 
!= endUnderscore 
) 
 530         // it should be of the same colour as text 
 531         SetPen(wxPen(GetTextForeground(), 0, wxSOLID
)); 
 535         DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
); 
 538     // return bounding rect if requested 
 541         *rectBounding 
= wxRect(x
, y 
- heightText
, widthText
, heightText
); 
 544     CalcBoundingBox(x0
, y0
); 
 545     CalcBoundingBox(x0 
+ width0
, y0 
+ height
);