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