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 // ============================================================================
37 // ============================================================================
39 // ----------------------------------------------------------------------------
41 // ----------------------------------------------------------------------------
43 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
44 wxCoord width
, wxCoord height
)
46 wxCHECK_RET( Ok(), wxT("invalid window dc") );
48 wxCoord x2
= x1
+ width
,
51 // this is to yield width of 3 for width == height == 10
52 SetPen(wxPen(GetTextForeground(), (width
+ height
+ 1) / 7, wxSOLID
));
54 // we're drawing a scaled version of wx/generic/tick.xpm here
55 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
56 y3
= y1
+ height
/ 2; // y of the left tick branch
57 DoDrawLine(x1
, y3
, x3
, y2
);
58 DoDrawLine(x3
, y2
, x2
, y1
);
60 CalcBoundingBox(x1
, y1
);
61 CalcBoundingBox(x2
, y2
);
64 // ----------------------------------------------------------------------------
66 // ----------------------------------------------------------------------------
68 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
70 int n
= list
->Number();
71 wxPoint
*points
= new wxPoint
[n
];
74 for ( wxNode
*node
= list
->First(); node
; node
= node
->Next(), i
++ )
76 wxPoint
*point
= (wxPoint
*)node
->Data();
77 points
[i
].x
= point
->x
;
78 points
[i
].y
= point
->y
;
81 DoDrawLines(n
, points
, xoffset
, yoffset
);
87 void wxDCBase::DrawPolygon(const wxList
*list
,
88 wxCoord xoffset
, wxCoord yoffset
,
91 int n
= list
->Number();
92 wxPoint
*points
= new wxPoint
[n
];
95 for ( wxNode
*node
= list
->First(); node
; node
= node
->Next(), i
++ )
97 wxPoint
*point
= (wxPoint
*)node
->Data();
98 points
[i
].x
= point
->x
;
99 points
[i
].y
= point
->y
;
102 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
107 // ----------------------------------------------------------------------------
109 // ----------------------------------------------------------------------------
113 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
114 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
118 wxPoint
*point1
= new wxPoint
;
119 point1
->x
= x1
; point1
->y
= y1
;
120 point_list
.Append((wxObject
*)point1
);
122 wxPoint
*point2
= new wxPoint
;
123 point2
->x
= x2
; point2
->y
= y2
;
124 point_list
.Append((wxObject
*)point2
);
126 wxPoint
*point3
= new wxPoint
;
127 point3
->x
= x3
; point3
->y
= y3
;
128 point_list
.Append((wxObject
*)point3
);
130 DrawSpline(&point_list
);
132 for( wxNode
*node
= point_list
.First(); node
; node
= node
->Next() )
134 wxPoint
*p
= (wxPoint
*)node
->Data();
139 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
142 for (int i
=0; i
< n
; i
++)
144 list
.Append((wxObject
*)&points
[i
]);
150 // ----------------------------------- spline code ----------------------------------------
152 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
153 double a3
, double b3
, double a4
, double b4
);
154 void wx_clear_stack();
155 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
156 double *y3
, double *x4
, double *y4
);
157 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
158 double x4
, double y4
);
159 static bool wx_spline_add_point(double x
, double y
);
160 static void wx_spline_draw_point_array(wxDCBase
*dc
);
162 wxList wx_spline_point_list
;
164 #define half(z1, z2) ((z1+z2)/2.0)
167 /* iterative version */
169 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
172 register double xmid
, ymid
;
173 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
176 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
178 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
179 xmid
= (double)half(x2
, x3
);
180 ymid
= (double)half(y2
, y3
);
181 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
182 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
183 wx_spline_add_point( x1
, y1
);
184 wx_spline_add_point( xmid
, ymid
);
186 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
187 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
188 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
189 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
194 /* utilities used by spline drawing routines */
196 typedef struct wx_spline_stack_struct
{
197 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
200 #define SPLINE_STACK_DEPTH 20
201 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
202 static Stack
*wx_stack_top
;
203 static int wx_stack_count
;
205 void wx_clear_stack()
207 wx_stack_top
= wx_spline_stack
;
211 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
213 wx_stack_top
->x1
= x1
;
214 wx_stack_top
->y1
= y1
;
215 wx_stack_top
->x2
= x2
;
216 wx_stack_top
->y2
= y2
;
217 wx_stack_top
->x3
= x3
;
218 wx_stack_top
->y3
= y3
;
219 wx_stack_top
->x4
= x4
;
220 wx_stack_top
->y4
= y4
;
225 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
226 double *x3
, double *y3
, double *x4
, double *y4
)
228 if (wx_stack_count
== 0)
232 *x1
= wx_stack_top
->x1
;
233 *y1
= wx_stack_top
->y1
;
234 *x2
= wx_stack_top
->x2
;
235 *y2
= wx_stack_top
->y2
;
236 *x3
= wx_stack_top
->x3
;
237 *y3
= wx_stack_top
->y3
;
238 *x4
= wx_stack_top
->x4
;
239 *y4
= wx_stack_top
->y4
;
243 static bool wx_spline_add_point(double x
, double y
)
245 wxPoint
*point
= new wxPoint
;
248 wx_spline_point_list
.Append((wxObject
*)point
);
252 static void wx_spline_draw_point_array(wxDCBase
*dc
)
254 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
255 wxNode
*node
= wx_spline_point_list
.First();
258 wxPoint
*point
= (wxPoint
*)node
->Data();
261 node
= wx_spline_point_list
.First();
265 void wxDCBase::DoDrawSpline( wxList
*points
)
267 wxCHECK_RET( Ok(), wxT("invalid window dc") );
270 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
271 double x1
, y1
, x2
, y2
;
273 wxNode
*node
= points
->First();
274 p
= (wxPoint
*)node
->Data();
280 p
= (wxPoint
*)node
->Data();
284 cx1
= (double)((x1
+ x2
) / 2);
285 cy1
= (double)((y1
+ y2
) / 2);
286 cx2
= (double)((cx1
+ x2
) / 2);
287 cy2
= (double)((cy1
+ y2
) / 2);
289 wx_spline_add_point(x1
, y1
);
291 while ((node
= node
->Next()) != NULL
)
293 p
= (wxPoint
*)node
->Data();
298 cx4
= (double)(x1
+ x2
) / 2;
299 cy4
= (double)(y1
+ y2
) / 2;
300 cx3
= (double)(x1
+ cx4
) / 2;
301 cy3
= (double)(y1
+ cy4
) / 2;
303 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
307 cx2
= (double)(cx1
+ x2
) / 2;
308 cy2
= (double)(cy1
+ y2
) / 2;
311 wx_spline_add_point( cx1
, cy1
);
312 wx_spline_add_point( x2
, y2
);
314 wx_spline_draw_point_array( this );
317 #endif // wxUSE_SPLINES
319 // ----------------------------------------------------------------------------
320 // enhanced text drawing
321 // ----------------------------------------------------------------------------
323 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
329 int widthTextMax
= 0, widthLine
,
330 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
333 for ( const wxChar
*pc
= text
; ; pc
++ )
335 if ( *pc
== _T('\n') || *pc
== _T('\0') )
337 if ( curLine
.empty() )
339 // we can't use GetTextExtent - it will return 0 for both width
340 // and height and an empty line should count in height
343 // assume that this line has the same height as the previous
345 if ( !heightLineDefault
)
346 heightLineDefault
= heightLine
;
348 if ( !heightLineDefault
)
350 // but we don't know it yet - choose something reasonable
351 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
355 heightTextTotal
+= heightLineDefault
;
359 GetTextExtent(curLine
, &widthLine
, &heightLine
,
361 if ( widthLine
> widthTextMax
)
362 widthTextMax
= widthLine
;
363 heightTextTotal
+= heightLine
;
366 if ( *pc
== _T('\n') )
385 *y
= heightTextTotal
;
390 void wxDCBase::DrawLabel(const wxString
& text
,
391 const wxBitmap
& bitmap
,
395 wxRect
*rectBounding
)
397 // find the text position
398 wxCoord widthText
, heightText
, heightLine
;
399 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
401 wxCoord width
, height
;
404 width
= widthText
+ bitmap
.GetWidth();
405 height
= bitmap
.GetHeight();
414 if ( alignment
& wxALIGN_RIGHT
)
416 x
= rect
.GetRight() - width
;
418 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
420 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
422 else // alignment & wxALIGN_LEFT
427 if ( alignment
& wxALIGN_BOTTOM
)
429 y
= rect
.GetBottom() - height
;
431 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
433 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
435 else // alignment & wxALIGN_TOP
440 // draw the bitmap first
446 DrawBitmap(bitmap
, x
, y
, TRUE
/* use mask */);
448 wxCoord offset
= bitmap
.GetWidth() + 4;
452 y
+= (height
- heightText
) / 2;
455 // we will draw the underscore under the accel char later
456 wxCoord startUnderscore
= 0,
460 // split the string into lines and draw each of them separately
462 for ( const wxChar
*pc
= text
; ; pc
++ )
464 if ( *pc
== _T('\n') || *pc
== _T('\0') )
466 int xRealStart
= x
; // init it here to avoid compielr warnings
468 if ( !curLine
.empty() )
470 // NB: can't test for !(alignment & wxALIGN_LEFT) because
472 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
475 GetTextExtent(curLine
, &widthLine
, NULL
);
477 if ( alignment
& wxALIGN_RIGHT
)
479 xRealStart
+= width
- widthLine
;
481 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
483 xRealStart
+= (width
- widthLine
) / 2;
486 //else: left aligned, nothing to do
488 DrawText(curLine
, xRealStart
, y
);
493 // do we have underscore in this line? we can check yUnderscore
494 // because it is set below to just y + heightLine if we do
495 if ( y
== yUnderscore
)
497 // adjust the horz positions to account for the shift
498 startUnderscore
+= xRealStart
;
499 endUnderscore
+= xRealStart
;
502 if ( *pc
== _T('\0') )
507 else // not end of line
509 if ( pc
- text
.c_str() == indexAccel
)
511 // remeber to draw underscore here
512 GetTextExtent(curLine
, &startUnderscore
, NULL
);
514 GetTextExtent(curLine
, &endUnderscore
, NULL
);
516 yUnderscore
= y
+ heightLine
;
525 // draw the underscore if found
526 if ( startUnderscore
!= endUnderscore
)
528 // it should be of the same colour as text
529 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
533 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
536 // return bounding rect if requested
539 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
542 CalcBoundingBox(x0
, y0
);
543 CalcBoundingBox(x0
+ width0
, y0
+ height
);