build fix
[wxWidgets.git] / src / common / dcbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/dc.h"
28 #include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
29
30 #ifndef WX_PRECOMP
31 #include "wx/math.h"
32 #endif
33
34 // bool wxDCBase::sm_cacheing = false;
35
36 IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
37
38 // ============================================================================
39 // implementation
40 // ============================================================================
41
42 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
43 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
44
45 wxDCBase::wxDCBase()
46 : m_colour(wxColourDisplay())
47 , m_ok(true)
48 , m_clipping(false)
49 , m_isInteractive(0)
50 , m_isBBoxValid(false)
51 , m_logicalOriginX(0), m_logicalOriginY(0)
52 , m_deviceOriginX(0), m_deviceOriginY(0)
53 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
54 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
55 , m_userScaleX(1.0), m_userScaleY(1.0)
56 , m_scaleX(1.0), m_scaleY(1.0)
57 , m_signX(1), m_signY(1)
58 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
59 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
60 , m_logicalFunction(wxCOPY)
61 , m_backgroundMode(wxTRANSPARENT)
62 , m_mappingMode(wxMM_TEXT)
63 , m_pen()
64 , m_brush()
65 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
66 , m_textForegroundColour(*wxBLACK)
67 , m_textBackgroundColour(*wxWHITE)
68 , m_font()
69 #if wxUSE_PALETTE
70 , m_palette()
71 , m_hasCustomPalette(false)
72 #endif // wxUSE_PALETTE
73 {
74 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
75 (double)wxGetDisplaySizeMM().GetWidth();
76 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
77 (double)wxGetDisplaySizeMM().GetHeight();
78
79 ResetBoundingBox();
80 ResetClipping();
81 }
82
83 wxDCBase::~wxDCBase()
84 {
85 }
86
87 #if WXWIN_COMPATIBILITY_2_6
88 void wxDCBase::BeginDrawing()
89 {
90 }
91
92 void wxDCBase::EndDrawing()
93 {
94 }
95 #endif // WXWIN_COMPATIBILITY_2_6
96
97 #if WXWIN_COMPATIBILITY_2_8
98 // for compatibility with the old code when wxCoord was long everywhere
99 void wxDCBase::GetTextExtent(const wxString& string,
100 long *x, long *y,
101 long *descent,
102 long *externalLeading,
103 const wxFont *theFont) const
104 {
105 wxCoord x2, y2, descent2, externalLeading2;
106 DoGetTextExtent(string, &x2, &y2,
107 &descent2, &externalLeading2,
108 theFont);
109 if ( x )
110 *x = x2;
111 if ( y )
112 *y = y2;
113 if ( descent )
114 *descent = descent2;
115 if ( externalLeading )
116 *externalLeading = externalLeading2;
117 }
118
119 void wxDCBase::GetLogicalOrigin(long *x, long *y) const
120 {
121 wxCoord x2, y2;
122 DoGetLogicalOrigin(&x2, &y2);
123 if ( x )
124 *x = x2;
125 if ( y )
126 *y = y2;
127 }
128
129 void wxDCBase::GetDeviceOrigin(long *x, long *y) const
130 {
131 wxCoord x2, y2;
132 DoGetDeviceOrigin(&x2, &y2);
133 if ( x )
134 *x = x2;
135 if ( y )
136 *y = y2;
137 }
138
139 void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const
140 {
141 wxCoord xx,yy,ww,hh;
142 DoGetClippingBox(&xx, &yy, &ww, &hh);
143 if (x) *x = xx;
144 if (y) *y = yy;
145 if (w) *w = ww;
146 if (h) *h = hh;
147 }
148 #endif // WXWIN_COMPATIBILITY_2_8
149
150
151
152 // ----------------------------------------------------------------------------
153 // coordinate conversions and transforms
154 // ----------------------------------------------------------------------------
155
156 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
157 {
158 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
159 }
160
161 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
162 {
163 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
164 }
165
166 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
167 {
168 return wxRound((double)(x) / m_scaleX);
169 }
170
171 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
172 {
173 return wxRound((double)(y) / m_scaleY);
174 }
175
176 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
177 {
178 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
179 }
180
181 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
182 {
183 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
184 }
185
186 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
187 {
188 return wxRound((double)(x) * m_scaleX);
189 }
190
191 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
192 {
193 return wxRound((double)(y) * m_scaleY);
194 }
195
196 void wxDCBase::ComputeScaleAndOrigin()
197 {
198 m_scaleX = m_logicalScaleX * m_userScaleX;
199 m_scaleY = m_logicalScaleY * m_userScaleY;
200 }
201
202 void wxDCBase::SetMapMode( int mode )
203 {
204 switch (mode)
205 {
206 case wxMM_TWIPS:
207 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
208 break;
209 case wxMM_POINTS:
210 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
211 break;
212 case wxMM_METRIC:
213 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
214 break;
215 case wxMM_LOMETRIC:
216 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
217 break;
218 default:
219 case wxMM_TEXT:
220 SetLogicalScale( 1.0, 1.0 );
221 break;
222 }
223 m_mappingMode = mode;
224 }
225
226 void wxDCBase::SetUserScale( double x, double y )
227 {
228 // allow negative ? -> no
229 m_userScaleX = x;
230 m_userScaleY = y;
231 ComputeScaleAndOrigin();
232 }
233
234 void wxDCBase::SetLogicalScale( double x, double y )
235 {
236 // allow negative ?
237 m_logicalScaleX = x;
238 m_logicalScaleY = y;
239 ComputeScaleAndOrigin();
240 }
241
242 void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
243 {
244 m_logicalOriginX = x * m_signX;
245 m_logicalOriginY = y * m_signY;
246 ComputeScaleAndOrigin();
247 }
248
249 void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
250 {
251 m_deviceOriginX = x;
252 m_deviceOriginY = y;
253 ComputeScaleAndOrigin();
254 }
255
256 void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
257 {
258 m_deviceLocalOriginX = x;
259 m_deviceLocalOriginY = y;
260 ComputeScaleAndOrigin();
261 }
262
263 void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
264 {
265 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
266 m_signX = (xLeftRight ? 1 : -1);
267 m_signY = (yBottomUp ? -1 : 1);
268 ComputeScaleAndOrigin();
269 }
270
271 // ----------------------------------------------------------------------------
272 // special symbols
273 // ----------------------------------------------------------------------------
274
275 void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
276 wxCoord width, wxCoord height)
277 {
278 wxCHECK_RET( Ok(), wxT("invalid window dc") );
279
280 wxCoord x2 = x1 + width,
281 y2 = y1 + height;
282
283 // the pen width is calibrated to give 3 for width == height == 10
284 wxDCPenChanger pen((wxDC&)*this,
285 wxPen(GetTextForeground(), (width + height + 1)/7));
286
287 // we're drawing a scaled version of wx/generic/tick.xpm here
288 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
289 y3 = y1 + height / 2; // y of the left tick branch
290 DoDrawLine(x1, y3, x3, y2);
291 DoDrawLine(x3, y2, x2, y1);
292
293 CalcBoundingBox(x1, y1);
294 CalcBoundingBox(x2, y2);
295 }
296
297 // ----------------------------------------------------------------------------
298 // stubs for functions not implemented in all ports
299 // ----------------------------------------------------------------------------
300
301 bool
302 wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
303 wxCoord dstWidth, wxCoord dstHeight,
304 wxDC *source,
305 wxCoord xsrc, wxCoord ysrc,
306 wxCoord srcWidth, wxCoord srcHeight,
307 int rop,
308 bool useMask,
309 wxCoord xsrcMask,
310 wxCoord ysrcMask)
311 {
312 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
313 _T("invalid blit size") );
314
315 // emulate the stretching by modifying the DC scale
316 double xscale = (double)srcWidth/dstWidth,
317 yscale = (double)srcHeight/dstHeight;
318
319 double xscaleOld, yscaleOld;
320 GetUserScale(&xscaleOld, &yscaleOld);
321 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
322
323 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
324 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
325 source,
326 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
327
328 SetUserScale(xscaleOld, yscaleOld);
329
330 return rc;
331 }
332
333 // ----------------------------------------------------------------------------
334 // line/polygons
335 // ----------------------------------------------------------------------------
336
337 void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
338 {
339 int n = list->GetCount();
340 wxPoint *points = new wxPoint[n];
341
342 int i = 0;
343 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
344 {
345 wxPoint *point = (wxPoint *)node->GetData();
346 points[i].x = point->x;
347 points[i].y = point->y;
348 }
349
350 DoDrawLines(n, points, xoffset, yoffset);
351
352 delete [] points;
353 }
354
355
356 void wxDCBase::DrawPolygon(const wxList *list,
357 wxCoord xoffset, wxCoord yoffset,
358 int fillStyle)
359 {
360 int n = list->GetCount();
361 wxPoint *points = new wxPoint[n];
362
363 int i = 0;
364 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
365 {
366 wxPoint *point = (wxPoint *)node->GetData();
367 points[i].x = point->x;
368 points[i].y = point->y;
369 }
370
371 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
372
373 delete [] points;
374 }
375
376 void
377 wxDCBase::DoDrawPolyPolygon(int n,
378 int count[],
379 wxPoint points[],
380 wxCoord xoffset, wxCoord yoffset,
381 int fillStyle)
382 {
383 if ( n == 1 )
384 {
385 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
386 return;
387 }
388
389 int i, j, lastOfs;
390 wxPoint* pts;
391 wxPen pen;
392
393 for (i = j = lastOfs = 0; i < n; i++)
394 {
395 lastOfs = j;
396 j += count[i];
397 }
398 pts = new wxPoint[j+n-1];
399 for (i = 0; i < j; i++)
400 pts[i] = points[i];
401 for (i = 2; i <= n; i++)
402 {
403 lastOfs -= count[n-i];
404 pts[j++] = pts[lastOfs];
405 }
406
407 pen = GetPen();
408 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
409 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
410 SetPen(pen);
411 for (i = j = 0; i < n; i++)
412 {
413 DoDrawLines(count[i], pts+j, xoffset, yoffset);
414 j += count[i];
415 }
416 delete[] pts;
417 }
418
419 // ----------------------------------------------------------------------------
420 // splines
421 // ----------------------------------------------------------------------------
422
423 #if wxUSE_SPLINES
424
425 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
426 void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
427 {
428 wxList point_list;
429
430 wxPoint *point1 = new wxPoint;
431 point1->x = x1; point1->y = y1;
432 point_list.Append((wxObject*)point1);
433
434 wxPoint *point2 = new wxPoint;
435 point2->x = x2; point2->y = y2;
436 point_list.Append((wxObject*)point2);
437
438 wxPoint *point3 = new wxPoint;
439 point3->x = x3; point3->y = y3;
440 point_list.Append((wxObject*)point3);
441
442 DrawSpline(&point_list);
443
444 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
445 {
446 wxPoint *p = (wxPoint *)node->GetData();
447 delete p;
448 }
449 }
450
451 void wxDCBase::DrawSpline(int n, wxPoint points[])
452 {
453 wxList list;
454 for (int i =0; i < n; i++)
455 {
456 list.Append((wxObject*)&points[i]);
457 }
458
459 DrawSpline(&list);
460 }
461
462 // ----------------------------------- spline code ----------------------------------------
463
464 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
465 double a3, double b3, double a4, double b4);
466 void wx_clear_stack();
467 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
468 double *y3, double *x4, double *y4);
469 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
470 double x4, double y4);
471 static bool wx_spline_add_point(double x, double y);
472 static void wx_spline_draw_point_array(wxDCBase *dc);
473
474 wxList wx_spline_point_list;
475
476 #define half(z1, z2) ((z1+z2)/2.0)
477 #define THRESHOLD 5
478
479 /* iterative version */
480
481 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
482 double b4)
483 {
484 register double xmid, ymid;
485 double x1, y1, x2, y2, x3, y3, x4, y4;
486
487 wx_clear_stack();
488 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
489
490 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
491 xmid = (double)half(x2, x3);
492 ymid = (double)half(y2, y3);
493 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
494 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
495 wx_spline_add_point( x1, y1 );
496 wx_spline_add_point( xmid, ymid );
497 } else {
498 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
499 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
500 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
501 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
502 }
503 }
504 }
505
506 /* utilities used by spline drawing routines */
507
508 typedef struct wx_spline_stack_struct {
509 double x1, y1, x2, y2, x3, y3, x4, y4;
510 } Stack;
511
512 #define SPLINE_STACK_DEPTH 20
513 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
514 static Stack *wx_stack_top;
515 static int wx_stack_count;
516
517 void wx_clear_stack()
518 {
519 wx_stack_top = wx_spline_stack;
520 wx_stack_count = 0;
521 }
522
523 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
524 {
525 wx_stack_top->x1 = x1;
526 wx_stack_top->y1 = y1;
527 wx_stack_top->x2 = x2;
528 wx_stack_top->y2 = y2;
529 wx_stack_top->x3 = x3;
530 wx_stack_top->y3 = y3;
531 wx_stack_top->x4 = x4;
532 wx_stack_top->y4 = y4;
533 wx_stack_top++;
534 wx_stack_count++;
535 }
536
537 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
538 double *x3, double *y3, double *x4, double *y4)
539 {
540 if (wx_stack_count == 0)
541 return (0);
542 wx_stack_top--;
543 wx_stack_count--;
544 *x1 = wx_stack_top->x1;
545 *y1 = wx_stack_top->y1;
546 *x2 = wx_stack_top->x2;
547 *y2 = wx_stack_top->y2;
548 *x3 = wx_stack_top->x3;
549 *y3 = wx_stack_top->y3;
550 *x4 = wx_stack_top->x4;
551 *y4 = wx_stack_top->y4;
552 return (1);
553 }
554
555 static bool wx_spline_add_point(double x, double y)
556 {
557 wxPoint *point = new wxPoint ;
558 point->x = (int) x;
559 point->y = (int) y;
560 wx_spline_point_list.Append((wxObject*)point);
561 return true;
562 }
563
564 static void wx_spline_draw_point_array(wxDCBase *dc)
565 {
566 dc->DrawLines(&wx_spline_point_list, 0, 0 );
567 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
568 while (node)
569 {
570 wxPoint *point = (wxPoint *)node->GetData();
571 delete point;
572 wx_spline_point_list.Erase(node);
573 node = wx_spline_point_list.GetFirst();
574 }
575 }
576
577 void wxDCBase::DoDrawSpline( wxList *points )
578 {
579 wxCHECK_RET( Ok(), wxT("invalid window dc") );
580
581 wxPoint *p;
582 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
583 double x1, y1, x2, y2;
584
585 wxList::compatibility_iterator node = points->GetFirst();
586 if (!node)
587 // empty list
588 return;
589
590 p = (wxPoint *)node->GetData();
591
592 x1 = p->x;
593 y1 = p->y;
594
595 node = node->GetNext();
596 p = (wxPoint *)node->GetData();
597
598 x2 = p->x;
599 y2 = p->y;
600 cx1 = (double)((x1 + x2) / 2);
601 cy1 = (double)((y1 + y2) / 2);
602 cx2 = (double)((cx1 + x2) / 2);
603 cy2 = (double)((cy1 + y2) / 2);
604
605 wx_spline_add_point(x1, y1);
606
607 while ((node = node->GetNext())
608 #if !wxUSE_STL
609 != NULL
610 #endif // !wxUSE_STL
611 )
612 {
613 p = (wxPoint *)node->GetData();
614 x1 = x2;
615 y1 = y2;
616 x2 = p->x;
617 y2 = p->y;
618 cx4 = (double)(x1 + x2) / 2;
619 cy4 = (double)(y1 + y2) / 2;
620 cx3 = (double)(x1 + cx4) / 2;
621 cy3 = (double)(y1 + cy4) / 2;
622
623 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
624
625 cx1 = cx4;
626 cy1 = cy4;
627 cx2 = (double)(cx1 + x2) / 2;
628 cy2 = (double)(cy1 + y2) / 2;
629 }
630
631 wx_spline_add_point( cx1, cy1 );
632 wx_spline_add_point( x2, y2 );
633
634 wx_spline_draw_point_array( this );
635 }
636
637 #endif // wxUSE_SPLINES
638
639 // ----------------------------------------------------------------------------
640 // Partial Text Extents
641 // ----------------------------------------------------------------------------
642
643
644 // Each element of the widths array will be the width of the string up to and
645 // including the corresponding character in text. This is the generic
646 // implementation, the port-specific classes should do this with native APIs
647 // if available and if faster. Note: pango_layout_index_to_pos is much slower
648 // than calling GetTextExtent!!
649
650 #define FWC_SIZE 256
651
652 class FontWidthCache
653 {
654 public:
655 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
656 ~FontWidthCache() { delete []m_widths; }
657
658 void Reset()
659 {
660 if (!m_widths)
661 m_widths = new int[FWC_SIZE];
662
663 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
664 }
665
666 wxFont m_font;
667 double m_scaleX;
668 int *m_widths;
669 };
670
671 static FontWidthCache s_fontWidthCache;
672
673 bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
674 {
675 int totalWidth = 0;
676
677 const size_t len = text.length();
678 widths.Empty();
679 widths.Add(0, len);
680
681 // reset the cache if font or horizontal scale have changed
682 if ( !s_fontWidthCache.m_widths ||
683 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
684 (s_fontWidthCache.m_font != GetFont()) )
685 {
686 s_fontWidthCache.Reset();
687 s_fontWidthCache.m_font = GetFont();
688 s_fontWidthCache.m_scaleX = m_scaleX;
689 }
690
691 // Calculate the position of each character based on the widths of
692 // the previous characters
693 int w, h;
694 for ( size_t i = 0; i < len; i++ )
695 {
696 const wxChar c = text[i];
697 unsigned int c_int = (unsigned int)c;
698
699 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
700 {
701 w = s_fontWidthCache.m_widths[c_int];
702 }
703 else
704 {
705 GetTextExtent(c, &w, &h);
706 if (c_int < FWC_SIZE)
707 s_fontWidthCache.m_widths[c_int] = w;
708 }
709
710 totalWidth += w;
711 widths[i] = totalWidth;
712 }
713
714 return true;
715 }
716
717
718 // ----------------------------------------------------------------------------
719 // enhanced text drawing
720 // ----------------------------------------------------------------------------
721
722 void wxDCBase::GetMultiLineTextExtent(const wxString& text,
723 wxCoord *x,
724 wxCoord *y,
725 wxCoord *h,
726 const wxFont *font) const
727 {
728 wxCoord widthTextMax = 0, widthLine,
729 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
730
731 wxString curLine;
732 for ( const wxChar *pc = text; ; pc++ )
733 {
734 if ( *pc == _T('\n') || *pc == _T('\0') )
735 {
736 if ( curLine.empty() )
737 {
738 // we can't use GetTextExtent - it will return 0 for both width
739 // and height and an empty line should count in height
740 // calculation
741
742 // assume that this line has the same height as the previous
743 // one
744 if ( !heightLineDefault )
745 heightLineDefault = heightLine;
746
747 if ( !heightLineDefault )
748 {
749 // but we don't know it yet - choose something reasonable
750 GetTextExtent(_T("W"), NULL, &heightLineDefault,
751 NULL, NULL, font);
752 }
753
754 heightTextTotal += heightLineDefault;
755 }
756 else
757 {
758 GetTextExtent(curLine, &widthLine, &heightLine,
759 NULL, NULL, font);
760 if ( widthLine > widthTextMax )
761 widthTextMax = widthLine;
762 heightTextTotal += heightLine;
763 }
764
765 if ( *pc == _T('\n') )
766 {
767 curLine.clear();
768 }
769 else
770 {
771 // the end of string
772 break;
773 }
774 }
775 else
776 {
777 curLine += *pc;
778 }
779 }
780
781 if ( x )
782 *x = widthTextMax;
783 if ( y )
784 *y = heightTextTotal;
785 if ( h )
786 *h = heightLine;
787 }
788
789 void wxDCBase::DrawLabel(const wxString& text,
790 const wxBitmap& bitmap,
791 const wxRect& rect,
792 int alignment,
793 int indexAccel,
794 wxRect *rectBounding)
795 {
796 // find the text position
797 wxCoord widthText, heightText, heightLine;
798 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
799
800 wxCoord width, height;
801 if ( bitmap.Ok() )
802 {
803 width = widthText + bitmap.GetWidth();
804 height = bitmap.GetHeight();
805 }
806 else // no bitmap
807 {
808 width = widthText;
809 height = heightText;
810 }
811
812 wxCoord x, y;
813 if ( alignment & wxALIGN_RIGHT )
814 {
815 x = rect.GetRight() - width;
816 }
817 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
818 {
819 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
820 }
821 else // alignment & wxALIGN_LEFT
822 {
823 x = rect.GetLeft();
824 }
825
826 if ( alignment & wxALIGN_BOTTOM )
827 {
828 y = rect.GetBottom() - height;
829 }
830 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
831 {
832 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
833 }
834 else // alignment & wxALIGN_TOP
835 {
836 y = rect.GetTop();
837 }
838
839 // draw the bitmap first
840 wxCoord x0 = x,
841 y0 = y,
842 width0 = width;
843 if ( bitmap.Ok() )
844 {
845 DrawBitmap(bitmap, x, y, true /* use mask */);
846
847 wxCoord offset = bitmap.GetWidth() + 4;
848 x += offset;
849 width -= offset;
850
851 y += (height - heightText) / 2;
852 }
853
854 // we will draw the underscore under the accel char later
855 wxCoord startUnderscore = 0,
856 endUnderscore = 0,
857 yUnderscore = 0;
858
859 // split the string into lines and draw each of them separately
860 wxString curLine;
861 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
862 {
863 if ( *pc == _T('\n') || pc == text.end() )
864 {
865 int xRealStart = x; // init it here to avoid compielr warnings
866
867 if ( !curLine.empty() )
868 {
869 // NB: can't test for !(alignment & wxALIGN_LEFT) because
870 // wxALIGN_LEFT is 0
871 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
872 {
873 wxCoord widthLine;
874 GetTextExtent(curLine, &widthLine, NULL);
875
876 if ( alignment & wxALIGN_RIGHT )
877 {
878 xRealStart += width - widthLine;
879 }
880 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
881 {
882 xRealStart += (width - widthLine) / 2;
883 }
884 }
885 //else: left aligned, nothing to do
886
887 DrawText(curLine, xRealStart, y);
888 }
889
890 y += heightLine;
891
892 // do we have underscore in this line? we can check yUnderscore
893 // because it is set below to just y + heightLine if we do
894 if ( y == yUnderscore )
895 {
896 // adjust the horz positions to account for the shift
897 startUnderscore += xRealStart;
898 endUnderscore += xRealStart;
899 }
900
901 if ( pc == text.end() )
902 break;
903
904 curLine.clear();
905 }
906 else // not end of line
907 {
908 if ( pc - text.begin() == indexAccel )
909 {
910 // remeber to draw underscore here
911 GetTextExtent(curLine, &startUnderscore, NULL);
912 curLine += *pc;
913 GetTextExtent(curLine, &endUnderscore, NULL);
914
915 yUnderscore = y + heightLine;
916 }
917 else
918 {
919 curLine += *pc;
920 }
921 }
922 }
923
924 // draw the underscore if found
925 if ( startUnderscore != endUnderscore )
926 {
927 // it should be of the same colour as text
928 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
929
930 yUnderscore--;
931
932 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
933 }
934
935 // return bounding rect if requested
936 if ( rectBounding )
937 {
938 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
939 }
940
941 CalcBoundingBox(x0, y0);
942 CalcBoundingBox(x0 + width0, y0 + height);
943 }
944
945
946 void wxDCBase::DoGradientFillLinear(const wxRect& rect,
947 const wxColour& initialColour,
948 const wxColour& destColour,
949 wxDirection nDirection)
950 {
951 // save old pen
952 wxPen oldPen = m_pen;
953 wxBrush oldBrush = m_brush;
954
955 wxUint8 nR1 = initialColour.Red();
956 wxUint8 nG1 = initialColour.Green();
957 wxUint8 nB1 = initialColour.Blue();
958 wxUint8 nR2 = destColour.Red();
959 wxUint8 nG2 = destColour.Green();
960 wxUint8 nB2 = destColour.Blue();
961 wxUint8 nR, nG, nB;
962
963 if ( nDirection == wxEAST || nDirection == wxWEST )
964 {
965 wxInt32 x = rect.GetWidth();
966 wxInt32 w = x; // width of area to shade
967 wxInt32 xDelta = w/256; // height of one shade bend
968 if (xDelta < 1)
969 xDelta = 1;
970
971 while (x >= xDelta)
972 {
973 x -= xDelta;
974 if (nR1 > nR2)
975 nR = nR1 - (nR1-nR2)*(w-x)/w;
976 else
977 nR = nR1 + (nR2-nR1)*(w-x)/w;
978
979 if (nG1 > nG2)
980 nG = nG1 - (nG1-nG2)*(w-x)/w;
981 else
982 nG = nG1 + (nG2-nG1)*(w-x)/w;
983
984 if (nB1 > nB2)
985 nB = nB1 - (nB1-nB2)*(w-x)/w;
986 else
987 nB = nB1 + (nB2-nB1)*(w-x)/w;
988
989 wxColour colour(nR,nG,nB);
990 SetPen(wxPen(colour, 1, wxSOLID));
991 SetBrush(wxBrush(colour));
992 if(nDirection == wxEAST)
993 DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(),
994 xDelta, rect.GetHeight());
995 else //nDirection == wxWEST
996 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
997 xDelta, rect.GetHeight());
998 }
999 }
1000 else // nDirection == wxNORTH || nDirection == wxSOUTH
1001 {
1002 wxInt32 y = rect.GetHeight();
1003 wxInt32 w = y; // height of area to shade
1004 wxInt32 yDelta = w/255; // height of one shade bend
1005 if (yDelta < 1)
1006 yDelta = 1;
1007
1008 while (y > 0)
1009 {
1010 y -= yDelta;
1011 if (nR1 > nR2)
1012 nR = nR1 - (nR1-nR2)*(w-y)/w;
1013 else
1014 nR = nR1 + (nR2-nR1)*(w-y)/w;
1015
1016 if (nG1 > nG2)
1017 nG = nG1 - (nG1-nG2)*(w-y)/w;
1018 else
1019 nG = nG1 + (nG2-nG1)*(w-y)/w;
1020
1021 if (nB1 > nB2)
1022 nB = nB1 - (nB1-nB2)*(w-y)/w;
1023 else
1024 nB = nB1 + (nB2-nB1)*(w-y)/w;
1025
1026 wxColour colour(nR,nG,nB);
1027 SetPen(wxPen(colour, 1, wxSOLID));
1028 SetBrush(wxBrush(colour));
1029 if(nDirection == wxNORTH)
1030 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1031 rect.GetWidth(), yDelta);
1032 else //nDirection == wxSOUTH
1033 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta,
1034 rect.GetWidth(), yDelta);
1035 }
1036 }
1037
1038 SetPen(oldPen);
1039 SetBrush(oldBrush);
1040 }
1041
1042 void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
1043 const wxColour& initialColour,
1044 const wxColour& destColour,
1045 const wxPoint& circleCenter)
1046 {
1047 //save the old pen color
1048 wxColour oldPenColour = m_pen.GetColour();
1049
1050 wxUint8 nR1 = destColour.Red();
1051 wxUint8 nG1 = destColour.Green();
1052 wxUint8 nB1 = destColour.Blue();
1053 wxUint8 nR2 = initialColour.Red();
1054 wxUint8 nG2 = initialColour.Green();
1055 wxUint8 nB2 = initialColour.Blue();
1056 wxUint8 nR, nG, nB;
1057
1058
1059 //Radius
1060 wxInt32 cx = rect.GetWidth() / 2;
1061 wxInt32 cy = rect.GetHeight() / 2;
1062 wxInt32 nRadius;
1063 if (cx < cy)
1064 nRadius = cx;
1065 else
1066 nRadius = cy;
1067
1068 //Offset of circle
1069 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1070 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1071
1072 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1073 {
1074 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1075 {
1076 //get color difference
1077 wxInt32 nGradient = ((nRadius -
1078 (wxInt32)sqrt(
1079 pow((double)(x - cx - nCircleOffX), 2) +
1080 pow((double)(y - cy - nCircleOffY), 2)
1081 )) * 100) / nRadius;
1082
1083 //normalize Gradient
1084 if (nGradient < 0 )
1085 nGradient = 0;
1086
1087 //get dest colors
1088 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1089 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1090 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1091
1092 //set the pixel
1093 m_pen.SetColour(wxColour(nR,nG,nB));
1094 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
1095 }
1096 }
1097 //return old pen color
1098 m_pen.SetColour(oldPenColour);
1099 }
1100
1101 /*
1102 Notes for wxWidgets DrawEllipticArcRot(...)
1103
1104 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1105 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1106 which are also new.
1107
1108 All methods are generic, so they can be implemented in wxDCBase.
1109 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1110 methods like (WinCE) wxDC::DoDrawArc(...).
1111
1112 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1113 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1114 parts) or every column (in steep parts) only one pixel is calculated.
1115 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1116 starting angle is not equal to the ending angle. The calculation of the
1117 pixels is done using simple arithmetic only and should perform not too
1118 bad even on devices without floating point processor. I didn't test this yet.
1119
1120 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1121 For instance: an ellipse rotated 180 degrees is drawn
1122 slightly different from the original.
1123
1124 The points are then moved to an array and used to draw a polyline and/or polygon
1125 (with center added, the pie).
1126 The result looks quite similar to the native ellipse, only e few pixels differ.
1127
1128 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1129 slower as DrawEllipse(...), which calls the native API.
1130 An rotated ellipse outside the clipping region takes nearly the same time,
1131 while an native ellipse outside takes nearly no time to draw.
1132
1133 If you draw an arc with this new method, you will see the starting and ending angles
1134 are calculated properly.
1135 If you use DrawEllipticArc(...), you will see they are only correct for circles
1136 and not properly calculated for ellipses.
1137
1138 Peter Lenhard
1139 p.lenhard@t-online.de
1140 */
1141
1142 #ifdef __WXWINCE__
1143 void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
1144 wxCoord w, wxCoord h,
1145 double sa, double ea, double angle )
1146 {
1147 wxList list;
1148
1149 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
1150 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
1151
1152 // Add center (for polygon/pie)
1153 list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) );
1154
1155 // copy list into array and delete list elements
1156 int n = list.GetCount();
1157 wxPoint *points = new wxPoint[n];
1158 int i = 0;
1159 wxNode* node = 0;
1160 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
1161 {
1162 wxPoint *point = (wxPoint *)node->GetData();
1163 points[i].x = point->x;
1164 points[i].y = point->y;
1165 delete point;
1166 }
1167
1168 // first draw the pie without pen, if necessary
1169 if( GetBrush() != *wxTRANSPARENT_BRUSH )
1170 {
1171 wxPen tempPen( GetPen() );
1172 SetPen( *wxTRANSPARENT_PEN );
1173 DoDrawPolygon( n, points, 0, 0 );
1174 SetPen( tempPen );
1175 }
1176
1177 // then draw the arc without brush, if necessary
1178 if( GetPen() != *wxTRANSPARENT_PEN )
1179 {
1180 // without center
1181 DoDrawLines( n-1, points, 0, 0 );
1182 }
1183
1184 delete [] points;
1185
1186 } // DrawEllipticArcRot
1187
1188 void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
1189 {
1190 if( angle != 0.0 )
1191 {
1192 double pi(M_PI);
1193 double dSinA = -sin(angle*2.0*pi/360.0);
1194 double dCosA = cos(angle*2.0*pi/360.0);
1195 for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() )
1196 {
1197 wxPoint* point = (wxPoint*)node->GetData();
1198
1199 // transform coordinates, if necessary
1200 if( center.x ) point->x -= center.x;
1201 if( center.y ) point->y -= center.y;
1202
1203 // calculate rotation, rounding simply by implicit cast to integer
1204 int xTemp = point->x * dCosA - point->y * dSinA;
1205 point->y = point->x * dSinA + point->y * dCosA;
1206 point->x = xTemp;
1207
1208 // back transform coordinates, if necessary
1209 if( center.x ) point->x += center.x;
1210 if( center.y ) point->y += center.y;
1211 }
1212 }
1213 }
1214
1215 void wxDCBase::CalculateEllipticPoints( wxList* points,
1216 wxCoord xStart, wxCoord yStart,
1217 wxCoord w, wxCoord h,
1218 double sa, double ea )
1219 {
1220 double pi = M_PI;
1221 double sar = 0;
1222 double ear = 0;
1223 int xsa = 0;
1224 int ysa = 0;
1225 int xea = 0;
1226 int yea = 0;
1227 int sq = 0;
1228 int eq = 0;
1229 bool bUseAngles = false;
1230 if( w<0 ) w = -w;
1231 if( h<0 ) h = -h;
1232 // half-axes
1233 wxCoord a = w/2;
1234 wxCoord b = h/2;
1235 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1236 int decrX = 0;
1237 if( 2*a == w ) decrX = 1;
1238 int decrY = 0;
1239 if( 2*b == h ) decrY = 1;
1240 // center
1241 wxCoord xCenter = xStart + a;
1242 wxCoord yCenter = yStart + b;
1243 // calculate data for start and end, if necessary
1244 if( sa != ea )
1245 {
1246 bUseAngles = true;
1247 // normalisation of angles
1248 while( sa<0 ) sa += 360;
1249 while( ea<0 ) ea += 360;
1250 while( sa>=360 ) sa -= 360;
1251 while( ea>=360 ) ea -= 360;
1252 // calculate quadrant numbers
1253 if( sa > 270 ) sq = 3;
1254 else if( sa > 180 ) sq = 2;
1255 else if( sa > 90 ) sq = 1;
1256 if( ea > 270 ) eq = 3;
1257 else if( ea > 180 ) eq = 2;
1258 else if( ea > 90 ) eq = 1;
1259 sar = sa * pi / 180.0;
1260 ear = ea * pi / 180.0;
1261 // correct angle circle -> ellipse
1262 sar = atan( -a/(double)b * tan( sar ) );
1263 if ( sq == 1 || sq == 2 ) sar += pi;
1264 ear = atan( -a/(double)b * tan( ear ) );
1265 if ( eq == 1 || eq == 2 ) ear += pi;
1266 // coordinates of points
1267 xsa = xCenter + a * cos( sar );
1268 if( sq == 0 || sq == 3 ) xsa -= decrX;
1269 ysa = yCenter + b * sin( sar );
1270 if( sq == 2 || sq == 3 ) ysa -= decrY;
1271 xea = xCenter + a * cos( ear );
1272 if( eq == 0 || eq == 3 ) xea -= decrX;
1273 yea = yCenter + b * sin( ear );
1274 if( eq == 2 || eq == 3 ) yea -= decrY;
1275 } // if iUseAngles
1276 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1277 double c1 = b * b;
1278 double c2 = 2.0 / w;
1279 c2 *= c2;
1280 c2 *= c1;
1281 wxCoord x = 0;
1282 wxCoord y = b;
1283 long x2 = 1;
1284 long y2 = y*y;
1285 long y2_old = 0;
1286 long y_old = 0;
1287 // Lists for quadrant 1 to 4
1288 wxList pointsarray[4];
1289 // Calculate points for first quadrant and set in all quadrants
1290 for( x = 0; x <= a; ++x )
1291 {
1292 x2 = x2+x+x-1;
1293 y2_old = y2;
1294 y_old = y;
1295 bool bNewPoint = false;
1296 while( y2 > c1 - c2 * x2 && y > 0 )
1297 {
1298 bNewPoint = true;
1299 y2 = y2-y-y+1;
1300 --y;
1301 }
1302 // old y now to big: set point with old y, old x
1303 if( bNewPoint && x>1)
1304 {
1305 int x1 = x - 1;
1306 // remove points on the same line
1307 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
1308 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) );
1309 pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
1310 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
1311 } // set point
1312 } // calculate point
1313
1314 // Starting and/or ending points for the quadrants, first quadrant gets both.
1315 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
1316 pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) );
1317 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) );
1318 pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) );
1319 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
1320
1321 // copy quadrants in original list
1322 if( bUseAngles )
1323 {
1324 // Copy the right part of the points in the lists
1325 // and delete the wxPoints, because they do not leave this method.
1326 points->Append( (wxObject*) new wxPoint( xsa, ysa ) );
1327 int q = sq;
1328 bool bStarted = false;
1329 bool bReady = false;
1330 bool bForceTurn = ( sq == eq && sa > ea );
1331 while( !bReady )
1332 {
1333 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1334 {
1335 // once: go to starting point in start quadrant
1336 if( !bStarted &&
1337 (
1338 ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1
1339 ||
1340 ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2
1341 )
1342 )
1343 {
1344 bStarted = true;
1345 }
1346
1347 // copy point, if not at ending point
1348 if( bStarted )
1349 {
1350 if( q != eq || bForceTurn
1351 ||
1352 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
1353 ||
1354 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
1355 )
1356 {
1357 // copy point
1358 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) );
1359 points->Append( (wxObject*) pPoint );
1360 }
1361 else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea)
1362 {
1363 bReady = true;
1364 }
1365 }
1366 } // for node
1367 ++q;
1368 if( q > 3 ) q = 0;
1369 bForceTurn = false;
1370 bStarted = true;
1371 } // while not bReady
1372 points->Append( (wxObject*) new wxPoint( xea, yea ) );
1373
1374 // delete points
1375 for( q = 0; q < 4; ++q )
1376 {
1377 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1378 {
1379 wxPoint *p = (wxPoint *)node->GetData();
1380 delete p;
1381 }
1382 }
1383 }
1384 else
1385 {
1386 wxNode* node;
1387 // copy whole ellipse, wxPoints will be deleted outside
1388 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
1389 {
1390 wxObject *p = node->GetData();
1391 points->Append( p );
1392 }
1393 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
1394 {
1395 wxObject *p = node->GetData();
1396 points->Append( p );
1397 }
1398 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
1399 {
1400 wxObject *p = node->GetData();
1401 points->Append( p );
1402 }
1403 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
1404 {
1405 wxObject *p = node->GetData();
1406 points->Append( p );
1407 }
1408 } // not iUseAngles
1409 } // CalculateEllipticPoints
1410
1411 #endif // __WXWINCE__