]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcbase.cpp
wxCocoa: Added preliminary Blit support
[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 licence
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 // bool wxDCBase::sm_cacheing = FALSE;
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // ----------------------------------------------------------------------------
42 // special symbols
43 // ----------------------------------------------------------------------------
44
45 void 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
66 // ----------------------------------------------------------------------------
67 // line/polygons
68 // ----------------------------------------------------------------------------
69
70 void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
71 {
72 int n = list->GetCount();
73 wxPoint *points = new wxPoint[n];
74
75 int i = 0;
76 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
77 {
78 wxPoint *point = (wxPoint *)node->GetData();
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
89 void wxDCBase::DrawPolygon(const wxList *list,
90 wxCoord xoffset, wxCoord yoffset,
91 int fillStyle)
92 {
93 int n = list->GetCount();
94 wxPoint *points = new wxPoint[n];
95
96 int i = 0;
97 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
98 {
99 wxPoint *point = (wxPoint *)node->GetData();
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
109 // ----------------------------------------------------------------------------
110 // splines
111 // ----------------------------------------------------------------------------
112
113 #if wxUSE_SPLINES
114
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)
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
134 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
135 {
136 wxPoint *p = (wxPoint *)node->GetData();
137 delete p;
138 }
139 }
140
141 void 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
152 // ----------------------------------- spline code ----------------------------------------
153
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);
163
164 wxList wx_spline_point_list;
165
166 #define half(z1, z2) ((z1+z2)/2.0)
167 #define THRESHOLD 5
168
169 /* iterative version */
170
171 void 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
198 typedef struct wx_spline_stack_struct {
199 double x1, y1, x2, y2, x3, y3, x4, y4;
200 } Stack;
201
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;
206
207 void wx_clear_stack()
208 {
209 wx_stack_top = wx_spline_stack;
210 wx_stack_count = 0;
211 }
212
213 void 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
227 int 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
245 static 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
254 static void wx_spline_draw_point_array(wxDCBase *dc)
255 {
256 dc->DrawLines(&wx_spline_point_list, 0, 0 );
257 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
258 while (node)
259 {
260 wxPoint *point = (wxPoint *)node->GetData();
261 delete point;
262 wx_spline_point_list.Erase(node);
263 node = wx_spline_point_list.GetFirst();
264 }
265 }
266
267 void 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
275 wxList::compatibility_iterator node = points->GetFirst();
276 p = (wxPoint *)node->GetData();
277
278 x1 = p->x;
279 y1 = p->y;
280
281 node = node->GetNext();
282 p = (wxPoint *)node->GetData();
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
293 while ((node = node->GetNext())
294 #if !wxUSE_STL
295 != NULL
296 #endif // !wxUSE_STL
297 )
298 {
299 p = (wxPoint *)node->GetData();
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
323 #endif // wxUSE_SPLINES
324
325 // ----------------------------------------------------------------------------
326 // enhanced text drawing
327 // ----------------------------------------------------------------------------
328
329 void wxDCBase::GetMultiLineTextExtent(const wxString& text,
330 wxCoord *x,
331 wxCoord *y,
332 wxCoord *h,
333 wxFont *font)
334 {
335 wxCoord widthTextMax = 0, widthLine,
336 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
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
396 void 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 {
515 if ( pc - text.c_str() == indexAccel )
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 }