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