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 licence
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
->GetCount();
73 wxPoint
*points
= new wxPoint
[n
];
76 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
78 wxPoint
*point
= (wxPoint
*)node
->GetData();
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
->GetCount();
94 wxPoint
*points
= new wxPoint
[n
];
97 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
99 wxPoint
*point
= (wxPoint
*)node
->GetData();
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( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
136 wxPoint
*p
= (wxPoint
*)node
->GetData();
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 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
260 wxPoint
*point
= (wxPoint
*)node
->GetData();
262 wx_spline_point_list
.Erase(node
);
263 node
= wx_spline_point_list
.GetFirst();
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 wxList::compatibility_iterator node
= points
->GetFirst();
276 p
= (wxPoint
*)node
->GetData();
281 node
= node
->GetNext();
282 p
= (wxPoint
*)node
->GetData();
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
->GetNext())
299 p
= (wxPoint
*)node
->GetData();
304 cx4
= (double)(x1
+ x2
) / 2;
305 cy4
= (double)(y1
+ y2
) / 2;
306 cx3
= (double)(x1
+ cx4
) / 2;
307 cy3
= (double)(y1
+ cy4
) / 2;
309 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
313 cx2
= (double)(cx1
+ x2
) / 2;
314 cy2
= (double)(cy1
+ y2
) / 2;
317 wx_spline_add_point( cx1
, cy1
);
318 wx_spline_add_point( x2
, y2
);
320 wx_spline_draw_point_array( this );
323 #endif // wxUSE_SPLINES
325 // ----------------------------------------------------------------------------
326 // enhanced text drawing
327 // ----------------------------------------------------------------------------
329 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
335 wxCoord widthTextMax
= 0, widthLine
,
336 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
339 for ( const wxChar
*pc
= text
; ; pc
++ )
341 if ( *pc
== _T('\n') || *pc
== _T('\0') )
343 if ( curLine
.empty() )
345 // we can't use GetTextExtent - it will return 0 for both width
346 // and height and an empty line should count in height
349 // assume that this line has the same height as the previous
351 if ( !heightLineDefault
)
352 heightLineDefault
= heightLine
;
354 if ( !heightLineDefault
)
356 // but we don't know it yet - choose something reasonable
357 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
361 heightTextTotal
+= heightLineDefault
;
365 GetTextExtent(curLine
, &widthLine
, &heightLine
,
367 if ( widthLine
> widthTextMax
)
368 widthTextMax
= widthLine
;
369 heightTextTotal
+= heightLine
;
372 if ( *pc
== _T('\n') )
391 *y
= heightTextTotal
;
396 void wxDCBase::DrawLabel(const wxString
& text
,
397 const wxBitmap
& bitmap
,
401 wxRect
*rectBounding
)
403 // find the text position
404 wxCoord widthText
, heightText
, heightLine
;
405 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
407 wxCoord width
, height
;
410 width
= widthText
+ bitmap
.GetWidth();
411 height
= bitmap
.GetHeight();
420 if ( alignment
& wxALIGN_RIGHT
)
422 x
= rect
.GetRight() - width
;
424 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
426 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
428 else // alignment & wxALIGN_LEFT
433 if ( alignment
& wxALIGN_BOTTOM
)
435 y
= rect
.GetBottom() - height
;
437 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
439 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
441 else // alignment & wxALIGN_TOP
446 // draw the bitmap first
452 DrawBitmap(bitmap
, x
, y
, TRUE
/* use mask */);
454 wxCoord offset
= bitmap
.GetWidth() + 4;
458 y
+= (height
- heightText
) / 2;
461 // we will draw the underscore under the accel char later
462 wxCoord startUnderscore
= 0,
466 // split the string into lines and draw each of them separately
468 for ( const wxChar
*pc
= text
; ; pc
++ )
470 if ( *pc
== _T('\n') || *pc
== _T('\0') )
472 int xRealStart
= x
; // init it here to avoid compielr warnings
474 if ( !curLine
.empty() )
476 // NB: can't test for !(alignment & wxALIGN_LEFT) because
478 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
481 GetTextExtent(curLine
, &widthLine
, NULL
);
483 if ( alignment
& wxALIGN_RIGHT
)
485 xRealStart
+= width
- widthLine
;
487 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
489 xRealStart
+= (width
- widthLine
) / 2;
492 //else: left aligned, nothing to do
494 DrawText(curLine
, xRealStart
, y
);
499 // do we have underscore in this line? we can check yUnderscore
500 // because it is set below to just y + heightLine if we do
501 if ( y
== yUnderscore
)
503 // adjust the horz positions to account for the shift
504 startUnderscore
+= xRealStart
;
505 endUnderscore
+= xRealStart
;
508 if ( *pc
== _T('\0') )
513 else // not end of line
515 if ( pc
- text
.c_str() == indexAccel
)
517 // remeber to draw underscore here
518 GetTextExtent(curLine
, &startUnderscore
, NULL
);
520 GetTextExtent(curLine
, &endUnderscore
, NULL
);
522 yUnderscore
= y
+ heightLine
;
531 // draw the underscore if found
532 if ( startUnderscore
!= endUnderscore
)
534 // it should be of the same colour as text
535 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
539 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
542 // return bounding rect if requested
545 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
548 CalcBoundingBox(x0
, y0
);
549 CalcBoundingBox(x0
+ width0
, y0
+ height
);