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
);