]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcbase.cpp
post wxUniv merge fixes
[wxWidgets.git] / src / common / dcbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 05/25/99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWindows team
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 #ifdef __GNUG__
17 #pragma implementation "dcbase.h"
18 #endif
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #include "wx/dc.h"
32
33 #include <math.h>
34
35 // ============================================================================
36 // implementation
37 // ============================================================================
38
39 // ----------------------------------------------------------------------------
40 // special symbols
41 // ----------------------------------------------------------------------------
42
43 void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
44 wxCoord width, wxCoord height)
45 {
46 wxCHECK_RET( Ok(), wxT("invalid window dc") );
47
48 wxCoord x2 = x1 + width,
49 y2 = y1 + height;
50
51 // this is to yield width of 3 for width == height == 10
52 SetPen(wxPen(GetTextForeground(), (width + height + 1) / 7, wxSOLID));
53
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);
59
60 CalcBoundingBox(x1, y1);
61 CalcBoundingBox(x2, y2);
62 }
63
64 // ----------------------------------------------------------------------------
65 // line/polygons
66 // ----------------------------------------------------------------------------
67
68 void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
69 {
70 int n = list->Number();
71 wxPoint *points = new wxPoint[n];
72
73 int i = 0;
74 for ( wxNode *node = list->First(); node; node = node->Next(), i++ )
75 {
76 wxPoint *point = (wxPoint *)node->Data();
77 points[i].x = point->x;
78 points[i].y = point->y;
79 }
80
81 DoDrawLines(n, points, xoffset, yoffset);
82
83 delete [] points;
84 }
85
86
87 void wxDCBase::DrawPolygon(const wxList *list,
88 wxCoord xoffset, wxCoord yoffset,
89 int fillStyle)
90 {
91 int n = list->Number();
92 wxPoint *points = new wxPoint[n];
93
94 int i = 0;
95 for ( wxNode *node = list->First(); node; node = node->Next(), i++ )
96 {
97 wxPoint *point = (wxPoint *)node->Data();
98 points[i].x = point->x;
99 points[i].y = point->y;
100 }
101
102 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
103
104 delete [] points;
105 }
106
107 // ----------------------------------------------------------------------------
108 // splines
109 // ----------------------------------------------------------------------------
110
111 #if wxUSE_SPLINES
112
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)
115 {
116 wxList point_list;
117
118 wxPoint *point1 = new wxPoint;
119 point1->x = x1; point1->y = y1;
120 point_list.Append((wxObject*)point1);
121
122 wxPoint *point2 = new wxPoint;
123 point2->x = x2; point2->y = y2;
124 point_list.Append((wxObject*)point2);
125
126 wxPoint *point3 = new wxPoint;
127 point3->x = x3; point3->y = y3;
128 point_list.Append((wxObject*)point3);
129
130 DrawSpline(&point_list);
131
132 for( wxNode *node = point_list.First(); node; node = node->Next() )
133 {
134 wxPoint *p = (wxPoint *)node->Data();
135 delete p;
136 }
137 }
138
139 void wxDCBase::DrawSpline(int n, wxPoint points[])
140 {
141 wxList list;
142 for (int i =0; i < n; i++)
143 {
144 list.Append((wxObject*)&points[i]);
145 }
146
147 DrawSpline(&list);
148 }
149
150 // ----------------------------------- spline code ----------------------------------------
151
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);
161
162 wxList wx_spline_point_list;
163
164 #define half(z1, z2) ((z1+z2)/2.0)
165 #define THRESHOLD 5
166
167 /* iterative version */
168
169 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
170 double b4)
171 {
172 register double xmid, ymid;
173 double x1, y1, x2, y2, x3, y3, x4, y4;
174
175 wx_clear_stack();
176 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
177
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 );
185 } else {
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);
190 }
191 }
192 }
193
194 /* utilities used by spline drawing routines */
195
196 typedef struct wx_spline_stack_struct {
197 double x1, y1, x2, y2, x3, y3, x4, y4;
198 } Stack;
199
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;
204
205 void wx_clear_stack()
206 {
207 wx_stack_top = wx_spline_stack;
208 wx_stack_count = 0;
209 }
210
211 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
212 {
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;
221 wx_stack_top++;
222 wx_stack_count++;
223 }
224
225 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
226 double *x3, double *y3, double *x4, double *y4)
227 {
228 if (wx_stack_count == 0)
229 return (0);
230 wx_stack_top--;
231 wx_stack_count--;
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;
240 return (1);
241 }
242
243 static bool wx_spline_add_point(double x, double y)
244 {
245 wxPoint *point = new wxPoint ;
246 point->x = (int) x;
247 point->y = (int) y;
248 wx_spline_point_list.Append((wxObject*)point);
249 return TRUE;
250 }
251
252 static void wx_spline_draw_point_array(wxDCBase *dc)
253 {
254 dc->DrawLines(&wx_spline_point_list, 0, 0 );
255 wxNode *node = wx_spline_point_list.First();
256 while (node)
257 {
258 wxPoint *point = (wxPoint *)node->Data();
259 delete point;
260 delete node;
261 node = wx_spline_point_list.First();
262 }
263 }
264
265 void wxDCBase::DoDrawSpline( wxList *points )
266 {
267 wxCHECK_RET( Ok(), wxT("invalid window dc") );
268
269 wxPoint *p;
270 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
271 double x1, y1, x2, y2;
272
273 wxNode *node = points->First();
274 p = (wxPoint *)node->Data();
275
276 x1 = p->x;
277 y1 = p->y;
278
279 node = node->Next();
280 p = (wxPoint *)node->Data();
281
282 x2 = p->x;
283 y2 = p->y;
284 cx1 = (double)((x1 + x2) / 2);
285 cy1 = (double)((y1 + y2) / 2);
286 cx2 = (double)((cx1 + x2) / 2);
287 cy2 = (double)((cy1 + y2) / 2);
288
289 wx_spline_add_point(x1, y1);
290
291 while ((node = node->Next()) != NULL)
292 {
293 p = (wxPoint *)node->Data();
294 x1 = x2;
295 y1 = y2;
296 x2 = p->x;
297 y2 = p->y;
298 cx4 = (double)(x1 + x2) / 2;
299 cy4 = (double)(y1 + y2) / 2;
300 cx3 = (double)(x1 + cx4) / 2;
301 cy3 = (double)(y1 + cy4) / 2;
302
303 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
304
305 cx1 = cx4;
306 cy1 = cy4;
307 cx2 = (double)(cx1 + x2) / 2;
308 cy2 = (double)(cy1 + y2) / 2;
309 }
310
311 wx_spline_add_point( cx1, cy1 );
312 wx_spline_add_point( x2, y2 );
313
314 wx_spline_draw_point_array( this );
315 }
316
317 #endif // wxUSE_SPLINES
318
319 // ----------------------------------------------------------------------------
320 // enhanced text drawing
321 // ----------------------------------------------------------------------------
322
323 void wxDCBase::GetMultiLineTextExtent(const wxString& text,
324 wxCoord *x,
325 wxCoord *y,
326 wxCoord *h,
327 wxFont *font)
328 {
329 int widthTextMax = 0, widthLine,
330 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
331
332 wxString curLine;
333 for ( const wxChar *pc = text; ; pc++ )
334 {
335 if ( *pc == _T('\n') || *pc == _T('\0') )
336 {
337 if ( curLine.empty() )
338 {
339 // we can't use GetTextExtent - it will return 0 for both width
340 // and height and an empty line should count in height
341 // calculation
342
343 // assume that this line has the same height as the previous
344 // one
345 if ( !heightLineDefault )
346 heightLineDefault = heightLine;
347
348 if ( !heightLineDefault )
349 {
350 // but we don't know it yet - choose something reasonable
351 GetTextExtent(_T("W"), NULL, &heightLineDefault,
352 NULL, NULL, font);
353 }
354
355 heightTextTotal += heightLineDefault;
356 }
357 else
358 {
359 GetTextExtent(curLine, &widthLine, &heightLine,
360 NULL, NULL, font);
361 if ( widthLine > widthTextMax )
362 widthTextMax = widthLine;
363 heightTextTotal += heightLine;
364 }
365
366 if ( *pc == _T('\n') )
367 {
368 curLine.clear();
369 }
370 else
371 {
372 // the end of string
373 break;
374 }
375 }
376 else
377 {
378 curLine += *pc;
379 }
380 }
381
382 if ( x )
383 *x = widthTextMax;
384 if ( y )
385 *y = heightTextTotal;
386 if ( h )
387 *h = heightLine;
388 }
389
390 void wxDCBase::DrawLabel(const wxString& text,
391 const wxBitmap& bitmap,
392 const wxRect& rect,
393 int alignment,
394 int indexAccel,
395 wxRect *rectBounding)
396 {
397 // find the text position
398 wxCoord widthText, heightText, heightLine;
399 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
400
401 wxCoord width, height;
402 if ( bitmap.Ok() )
403 {
404 width = widthText + bitmap.GetWidth();
405 height = bitmap.GetHeight();
406 }
407 else // no bitmap
408 {
409 width = widthText;
410 height = heightText;
411 }
412
413 wxCoord x, y;
414 if ( alignment & wxALIGN_RIGHT )
415 {
416 x = rect.GetRight() - width;
417 }
418 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
419 {
420 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
421 }
422 else // alignment & wxALIGN_LEFT
423 {
424 x = rect.GetLeft();
425 }
426
427 if ( alignment & wxALIGN_BOTTOM )
428 {
429 y = rect.GetBottom() - height;
430 }
431 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
432 {
433 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
434 }
435 else // alignment & wxALIGN_TOP
436 {
437 y = rect.GetTop();
438 }
439
440 // draw the bitmap first
441 wxCoord x0 = x,
442 y0 = y,
443 width0 = width;
444 if ( bitmap.Ok() )
445 {
446 DrawBitmap(bitmap, x, y, TRUE /* use mask */);
447
448 wxCoord offset = bitmap.GetWidth() + 4;
449 x += offset;
450 width -= offset;
451
452 y += (height - heightText) / 2;
453 }
454
455 // we will draw the underscore under the accel char later
456 wxCoord startUnderscore = 0,
457 endUnderscore = 0,
458 yUnderscore = 0;
459
460 // split the string into lines and draw each of them separately
461 wxString curLine;
462 for ( const wxChar *pc = text; ; pc++ )
463 {
464 if ( *pc == _T('\n') || *pc == _T('\0') )
465 {
466 int xRealStart = x; // init it here to avoid compielr warnings
467
468 if ( !curLine.empty() )
469 {
470 // NB: can't test for !(alignment & wxALIGN_LEFT) because
471 // wxALIGN_LEFT is 0
472 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
473 {
474 wxCoord widthLine;
475 GetTextExtent(curLine, &widthLine, NULL);
476
477 if ( alignment & wxALIGN_RIGHT )
478 {
479 xRealStart += width - widthLine;
480 }
481 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
482 {
483 xRealStart += (width - widthLine) / 2;
484 }
485 }
486 //else: left aligned, nothing to do
487
488 DrawText(curLine, xRealStart, y);
489 }
490
491 y += heightLine;
492
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 )
496 {
497 // adjust the horz positions to account for the shift
498 startUnderscore += xRealStart;
499 endUnderscore += xRealStart;
500 }
501
502 if ( *pc == _T('\0') )
503 break;
504
505 curLine.clear();
506 }
507 else // not end of line
508 {
509 if ( pc - text == indexAccel )
510 {
511 // remeber to draw underscore here
512 GetTextExtent(curLine, &startUnderscore, NULL);
513 curLine += *pc;
514 GetTextExtent(curLine, &endUnderscore, NULL);
515
516 yUnderscore = y + heightLine;
517 }
518 else
519 {
520 curLine += *pc;
521 }
522 }
523 }
524
525 // draw the underscore if found
526 if ( startUnderscore != endUnderscore )
527 {
528 // it should be of the same colour as text
529 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
530
531 yUnderscore--;
532
533 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
534 }
535
536 // return bounding rect if requested
537 if ( rectBounding )
538 {
539 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
540 }
541
542 CalcBoundingBox(x0, y0);
543 CalcBoundingBox(x0 + width0, y0 + height);
544 }