]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
re-renamed DoCreate() to XmDoCreateTLW() to avoid virtual function hiding in other...
[wxWidgets.git] / src / common / dcbase.cpp
CommitLineData
dbe94982 1/////////////////////////////////////////////////////////////////////////////
1e6feb95
VZ
2// Name: common/dcbase.cpp
3// Purpose: generic methods of the wxDC Class
4// Author: Vadim Zeitlin
dbe94982
BM
5// Modified by:
6// Created: 05/25/99
7// RCS-ID: $Id$
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
BM
27#include "wx/dc.h"
28
68379eaf 29// bool wxDCBase::sm_cacheing = false;
0cbff120 30
1e6feb95
VZ
31// ============================================================================
32// implementation
33// ============================================================================
34
35// ----------------------------------------------------------------------------
36// special symbols
37// ----------------------------------------------------------------------------
38
cd9da200
VZ
39void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
40 wxCoord width, wxCoord height)
41{
42 wxCHECK_RET( Ok(), wxT("invalid window dc") );
43
44 wxCoord x2 = x1 + width,
45 y2 = y1 + height;
46
47 // this is to yield width of 3 for width == height == 10
48 SetPen(wxPen(GetTextForeground(), (width + height + 1) / 7, wxSOLID));
49
50 // we're drawing a scaled version of wx/generic/tick.xpm here
51 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
52 y3 = y1 + height / 2; // y of the left tick branch
53 DoDrawLine(x1, y3, x3, y2);
54 DoDrawLine(x3, y2, x2, y1);
55
56 CalcBoundingBox(x1, y1);
57 CalcBoundingBox(x2, y2);
58}
59
1e6feb95
VZ
60// ----------------------------------------------------------------------------
61// line/polygons
62// ----------------------------------------------------------------------------
63
72cdf4c9 64void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
dbe94982 65{
b1d4dd7a 66 int n = list->GetCount();
dbe94982
BM
67 wxPoint *points = new wxPoint[n];
68
69 int i = 0;
222ed1d6 70 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 71 {
b1d4dd7a 72 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
73 points[i].x = point->x;
74 points[i].y = point->y;
75 }
76
77 DoDrawLines(n, points, xoffset, yoffset);
78
79 delete [] points;
80}
81
82
83void wxDCBase::DrawPolygon(const wxList *list,
72cdf4c9 84 wxCoord xoffset, wxCoord yoffset,
dbe94982
BM
85 int fillStyle)
86{
b1d4dd7a 87 int n = list->GetCount();
dbe94982
BM
88 wxPoint *points = new wxPoint[n];
89
90 int i = 0;
222ed1d6 91 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 92 {
b1d4dd7a 93 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
94 points[i].x = point->x;
95 points[i].y = point->y;
96 }
97
98 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
99
100 delete [] points;
101}
102
63b9e659
VZ
103void
104wxDCBase::DoDrawPolyPolygon(int n,
793db755 105 int count[],
63b9e659
VZ
106 wxPoint points[],
107 wxCoord xoffset, wxCoord yoffset,
108 int fillStyle)
109{
110 if ( n == 1 )
111 {
793db755 112 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
63b9e659
VZ
113 return;
114 }
115
116 int i, j, lastOfs;
117 wxPoint* pts;
118 wxPen pen;
119
120 for (i = j = lastOfs = 0; i < n; i++)
121 {
122 lastOfs = j;
793db755 123 j += count[i];
63b9e659
VZ
124 }
125 pts = new wxPoint[j+n-1];
126 for (i = 0; i < j; i++)
127 pts[i] = points[i];
128 for (i = 2; i <= n; i++)
129 {
793db755 130 lastOfs -= count[n-i];
63b9e659
VZ
131 pts[j++] = pts[lastOfs];
132 }
133
134 pen = GetPen();
135 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
136 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
137 SetPen(pen);
138 for (i = j = 0; i < n; i++)
139 {
793db755
VZ
140 DoDrawLines(count[i], pts+j, xoffset, yoffset);
141 j += count[i];
63b9e659 142 }
6db1f43b 143 delete[] pts;
63b9e659
VZ
144}
145
1e6feb95
VZ
146// ----------------------------------------------------------------------------
147// splines
148// ----------------------------------------------------------------------------
dbe94982 149
88ac883a 150#if wxUSE_SPLINES
dbe94982
BM
151
152// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
72cdf4c9 153void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
dbe94982
BM
154{
155 wxList point_list;
156
157 wxPoint *point1 = new wxPoint;
158 point1->x = x1; point1->y = y1;
159 point_list.Append((wxObject*)point1);
160
161 wxPoint *point2 = new wxPoint;
162 point2->x = x2; point2->y = y2;
163 point_list.Append((wxObject*)point2);
164
165 wxPoint *point3 = new wxPoint;
166 point3->x = x3; point3->y = y3;
167 point_list.Append((wxObject*)point3);
168
169 DrawSpline(&point_list);
170
222ed1d6 171 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
dbe94982 172 {
b1d4dd7a 173 wxPoint *p = (wxPoint *)node->GetData();
dbe94982
BM
174 delete p;
175 }
176}
177
178void wxDCBase::DrawSpline(int n, wxPoint points[])
179{
180 wxList list;
181 for (int i =0; i < n; i++)
182 {
183 list.Append((wxObject*)&points[i]);
184 }
185
186 DrawSpline(&list);
187}
188
fe2e4366
VS
189// ----------------------------------- spline code ----------------------------------------
190
191void wx_quadratic_spline(double a1, double b1, double a2, double b2,
192 double a3, double b3, double a4, double b4);
193void wx_clear_stack();
194int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
195 double *y3, double *x4, double *y4);
196void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
197 double x4, double y4);
198static bool wx_spline_add_point(double x, double y);
199static void wx_spline_draw_point_array(wxDCBase *dc);
200
201wxList wx_spline_point_list;
202
203#define half(z1, z2) ((z1+z2)/2.0)
204#define THRESHOLD 5
205
206/* iterative version */
207
208void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
209 double b4)
210{
211 register double xmid, ymid;
212 double x1, y1, x2, y2, x3, y3, x4, y4;
213
214 wx_clear_stack();
215 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
216
217 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
218 xmid = (double)half(x2, x3);
219 ymid = (double)half(y2, y3);
220 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
221 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
222 wx_spline_add_point( x1, y1 );
223 wx_spline_add_point( xmid, ymid );
224 } else {
225 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
226 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
227 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
228 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
229 }
230 }
231}
232
233/* utilities used by spline drawing routines */
234
235typedef struct wx_spline_stack_struct {
236 double x1, y1, x2, y2, x3, y3, x4, y4;
237} Stack;
238
239#define SPLINE_STACK_DEPTH 20
240static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
241static Stack *wx_stack_top;
242static int wx_stack_count;
243
244void wx_clear_stack()
245{
246 wx_stack_top = wx_spline_stack;
247 wx_stack_count = 0;
248}
249
250void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
251{
252 wx_stack_top->x1 = x1;
253 wx_stack_top->y1 = y1;
254 wx_stack_top->x2 = x2;
255 wx_stack_top->y2 = y2;
256 wx_stack_top->x3 = x3;
257 wx_stack_top->y3 = y3;
258 wx_stack_top->x4 = x4;
259 wx_stack_top->y4 = y4;
260 wx_stack_top++;
261 wx_stack_count++;
262}
263
264int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
265 double *x3, double *y3, double *x4, double *y4)
266{
267 if (wx_stack_count == 0)
268 return (0);
269 wx_stack_top--;
270 wx_stack_count--;
271 *x1 = wx_stack_top->x1;
272 *y1 = wx_stack_top->y1;
273 *x2 = wx_stack_top->x2;
274 *y2 = wx_stack_top->y2;
275 *x3 = wx_stack_top->x3;
276 *y3 = wx_stack_top->y3;
277 *x4 = wx_stack_top->x4;
278 *y4 = wx_stack_top->y4;
279 return (1);
280}
281
282static bool wx_spline_add_point(double x, double y)
283{
284 wxPoint *point = new wxPoint ;
285 point->x = (int) x;
286 point->y = (int) y;
287 wx_spline_point_list.Append((wxObject*)point);
68379eaf 288 return true;
fe2e4366
VS
289}
290
291static void wx_spline_draw_point_array(wxDCBase *dc)
292{
293 dc->DrawLines(&wx_spline_point_list, 0, 0 );
222ed1d6 294 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
fe2e4366
VS
295 while (node)
296 {
b1d4dd7a 297 wxPoint *point = (wxPoint *)node->GetData();
fe2e4366 298 delete point;
222ed1d6 299 wx_spline_point_list.Erase(node);
b1d4dd7a 300 node = wx_spline_point_list.GetFirst();
fe2e4366
VS
301 }
302}
303
304void wxDCBase::DoDrawSpline( wxList *points )
305{
306 wxCHECK_RET( Ok(), wxT("invalid window dc") );
307
308 wxPoint *p;
309 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
310 double x1, y1, x2, y2;
311
222ed1d6 312 wxList::compatibility_iterator node = points->GetFirst();
55e3f1c4 313 if (node == wxList::compatibility_iterator())
410bb8c1
RD
314 // empty list
315 return;
e0d31471 316
b1d4dd7a 317 p = (wxPoint *)node->GetData();
fe2e4366
VS
318
319 x1 = p->x;
320 y1 = p->y;
321
b1d4dd7a
RL
322 node = node->GetNext();
323 p = (wxPoint *)node->GetData();
fe2e4366
VS
324
325 x2 = p->x;
326 y2 = p->y;
327 cx1 = (double)((x1 + x2) / 2);
328 cy1 = (double)((y1 + y2) / 2);
329 cx2 = (double)((cx1 + x2) / 2);
330 cy2 = (double)((cy1 + y2) / 2);
331
332 wx_spline_add_point(x1, y1);
333
28b4db7f
VZ
334 while ((node = node->GetNext())
335#if !wxUSE_STL
336 != NULL
337#endif // !wxUSE_STL
338 )
fe2e4366 339 {
b1d4dd7a 340 p = (wxPoint *)node->GetData();
fe2e4366
VS
341 x1 = x2;
342 y1 = y2;
343 x2 = p->x;
344 y2 = p->y;
345 cx4 = (double)(x1 + x2) / 2;
346 cy4 = (double)(y1 + y2) / 2;
347 cx3 = (double)(x1 + cx4) / 2;
348 cy3 = (double)(y1 + cy4) / 2;
349
350 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
351
352 cx1 = cx4;
353 cy1 = cy4;
354 cx2 = (double)(cx1 + x2) / 2;
355 cy2 = (double)(cy1 + y2) / 2;
356 }
357
358 wx_spline_add_point( cx1, cy1 );
359 wx_spline_add_point( x2, y2 );
360
361 wx_spline_draw_point_array( this );
362}
363
88ac883a 364#endif // wxUSE_SPLINES
1e6feb95 365
0919e93e
RD
366// ----------------------------------------------------------------------------
367// Partial Text Extents
368// ----------------------------------------------------------------------------
369
370
174ee1b3 371// Each element of the widths array will be the width of the string up to and
3103e8a9 372// including the corresponding character in text. This is the generic
0919e93e 373// implementation, the port-specific classes should do this with native APIs
174ee1b3
RD
374// if available and if faster. Note: pango_layout_index_to_pos is much slower
375// than calling GetTextExtent!!
376
06fe86b7 377#define FWC_SIZE 256
174ee1b3
RD
378
379class FontWidthCache
380{
381public:
382 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
383 ~FontWidthCache() { delete []m_widths; }
2aaa050c
VZ
384
385 void Reset()
386 {
387 if (!m_widths)
388 m_widths = new int[FWC_SIZE];
389
390 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
391 }
392
174ee1b3
RD
393 wxFont m_font;
394 double m_scaleX;
395 int *m_widths;
396};
397
398static FontWidthCache s_fontWidthCache;
0919e93e
RD
399
400bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
401{
402 int totalWidth = 0;
0919e93e 403
174ee1b3 404 size_t i, len = text.Length();
0919e93e 405 widths.Empty();
174ee1b3
RD
406 widths.Add(0, len);
407 int w, h;
2aaa050c 408
174ee1b3
RD
409 // reset the cache if font or horizontal scale have changed
410 if (!s_fontWidthCache.m_widths ||
411 (s_fontWidthCache.m_scaleX != m_scaleX) ||
412 (s_fontWidthCache.m_font != GetFont()))
413 {
414 s_fontWidthCache.Reset();
415 s_fontWidthCache.m_font = GetFont();
416 s_fontWidthCache.m_scaleX = m_scaleX;
417 }
418
0919e93e
RD
419 // Calculate the position of each character based on the widths of
420 // the previous characters
2aaa050c 421 for (i=0; i<len; i++)
174ee1b3
RD
422 {
423 const wxChar c = text[i];
424 unsigned int c_int = (unsigned int)c;
425
2aaa050c 426 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
174ee1b3
RD
427 {
428 w = s_fontWidthCache.m_widths[c_int];
429 }
2aaa050c 430 else
174ee1b3
RD
431 {
432 GetTextExtent(c, &w, &h);
433 if (c_int < FWC_SIZE)
434 s_fontWidthCache.m_widths[c_int] = w;
435 }
436
0919e93e
RD
437 totalWidth += w;
438 widths[i] = totalWidth;
439 }
2aaa050c 440
0919e93e
RD
441 return true;
442}
443
444
1e6feb95
VZ
445// ----------------------------------------------------------------------------
446// enhanced text drawing
447// ----------------------------------------------------------------------------
448
449void wxDCBase::GetMultiLineTextExtent(const wxString& text,
450 wxCoord *x,
451 wxCoord *y,
452 wxCoord *h,
453 wxFont *font)
454{
c7aaa64f
VS
455 wxCoord widthTextMax = 0, widthLine,
456 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
1e6feb95
VZ
457
458 wxString curLine;
459 for ( const wxChar *pc = text; ; pc++ )
460 {
461 if ( *pc == _T('\n') || *pc == _T('\0') )
462 {
463 if ( curLine.empty() )
464 {
465 // we can't use GetTextExtent - it will return 0 for both width
466 // and height and an empty line should count in height
467 // calculation
468
469 // assume that this line has the same height as the previous
470 // one
471 if ( !heightLineDefault )
472 heightLineDefault = heightLine;
473
474 if ( !heightLineDefault )
475 {
476 // but we don't know it yet - choose something reasonable
477 GetTextExtent(_T("W"), NULL, &heightLineDefault,
478 NULL, NULL, font);
479 }
480
481 heightTextTotal += heightLineDefault;
482 }
483 else
484 {
485 GetTextExtent(curLine, &widthLine, &heightLine,
486 NULL, NULL, font);
487 if ( widthLine > widthTextMax )
488 widthTextMax = widthLine;
489 heightTextTotal += heightLine;
490 }
491
492 if ( *pc == _T('\n') )
493 {
494 curLine.clear();
495 }
496 else
497 {
498 // the end of string
499 break;
500 }
501 }
502 else
503 {
504 curLine += *pc;
505 }
506 }
507
508 if ( x )
509 *x = widthTextMax;
510 if ( y )
511 *y = heightTextTotal;
512 if ( h )
513 *h = heightLine;
514}
515
516void wxDCBase::DrawLabel(const wxString& text,
517 const wxBitmap& bitmap,
518 const wxRect& rect,
519 int alignment,
520 int indexAccel,
521 wxRect *rectBounding)
522{
523 // find the text position
524 wxCoord widthText, heightText, heightLine;
525 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
526
527 wxCoord width, height;
528 if ( bitmap.Ok() )
529 {
530 width = widthText + bitmap.GetWidth();
531 height = bitmap.GetHeight();
532 }
533 else // no bitmap
534 {
535 width = widthText;
536 height = heightText;
537 }
538
539 wxCoord x, y;
540 if ( alignment & wxALIGN_RIGHT )
541 {
542 x = rect.GetRight() - width;
543 }
544 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
545 {
546 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
547 }
548 else // alignment & wxALIGN_LEFT
549 {
550 x = rect.GetLeft();
551 }
552
553 if ( alignment & wxALIGN_BOTTOM )
554 {
555 y = rect.GetBottom() - height;
556 }
557 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
558 {
559 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
560 }
561 else // alignment & wxALIGN_TOP
562 {
563 y = rect.GetTop();
564 }
565
566 // draw the bitmap first
567 wxCoord x0 = x,
568 y0 = y,
569 width0 = width;
570 if ( bitmap.Ok() )
571 {
68379eaf 572 DrawBitmap(bitmap, x, y, true /* use mask */);
1e6feb95
VZ
573
574 wxCoord offset = bitmap.GetWidth() + 4;
575 x += offset;
576 width -= offset;
577
578 y += (height - heightText) / 2;
579 }
580
581 // we will draw the underscore under the accel char later
582 wxCoord startUnderscore = 0,
583 endUnderscore = 0,
584 yUnderscore = 0;
585
586 // split the string into lines and draw each of them separately
587 wxString curLine;
588 for ( const wxChar *pc = text; ; pc++ )
589 {
590 if ( *pc == _T('\n') || *pc == _T('\0') )
591 {
592 int xRealStart = x; // init it here to avoid compielr warnings
593
594 if ( !curLine.empty() )
595 {
596 // NB: can't test for !(alignment & wxALIGN_LEFT) because
597 // wxALIGN_LEFT is 0
598 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
599 {
600 wxCoord widthLine;
601 GetTextExtent(curLine, &widthLine, NULL);
602
603 if ( alignment & wxALIGN_RIGHT )
604 {
605 xRealStart += width - widthLine;
606 }
607 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
608 {
609 xRealStart += (width - widthLine) / 2;
610 }
611 }
612 //else: left aligned, nothing to do
613
614 DrawText(curLine, xRealStart, y);
615 }
616
617 y += heightLine;
618
619 // do we have underscore in this line? we can check yUnderscore
620 // because it is set below to just y + heightLine if we do
621 if ( y == yUnderscore )
622 {
623 // adjust the horz positions to account for the shift
624 startUnderscore += xRealStart;
625 endUnderscore += xRealStart;
626 }
627
628 if ( *pc == _T('\0') )
629 break;
630
631 curLine.clear();
632 }
633 else // not end of line
634 {
328bfc22 635 if ( pc - text.c_str() == indexAccel )
1e6feb95
VZ
636 {
637 // remeber to draw underscore here
638 GetTextExtent(curLine, &startUnderscore, NULL);
639 curLine += *pc;
640 GetTextExtent(curLine, &endUnderscore, NULL);
641
642 yUnderscore = y + heightLine;
643 }
644 else
645 {
646 curLine += *pc;
647 }
648 }
649 }
650
651 // draw the underscore if found
652 if ( startUnderscore != endUnderscore )
653 {
654 // it should be of the same colour as text
655 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
656
657 yUnderscore--;
658
659 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
660 }
661
662 // return bounding rect if requested
663 if ( rectBounding )
664 {
665 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
666 }
667
668 CalcBoundingBox(x0, y0);
669 CalcBoundingBox(x0 + width0, y0 + height);
670}
12bdd77c
JS
671
672/*
77ffb593 673Notes for wxWidgets DrawEllipticArcRot(...)
12bdd77c
JS
674
675wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
676It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
677which are also new.
678
679All methods are generic, so they can be implemented in wxDCBase.
680DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
681methods like (WinCE) wxDC::DoDrawArc(...).
682
683CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2aaa050c 684of an elliptic arc. The algorithm is pixel-based: In every row (in flat
12bdd77c
JS
685parts) or every column (in steep parts) only one pixel is calculated.
686Trigonometric calculation (sin, cos, tan, atan) is only done if the
2aaa050c 687starting angle is not equal to the ending angle. The calculation of the
12bdd77c
JS
688pixels is done using simple arithmetic only and should perform not too
689bad even on devices without floating point processor. I didn't test this yet.
690
691Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2aaa050c 692For instance: an ellipse rotated 180 degrees is drawn
12bdd77c
JS
693slightly different from the original.
694
2aaa050c
VZ
695The points are then moved to an array and used to draw a polyline and/or polygon
696(with center added, the pie).
12bdd77c
JS
697The result looks quite similar to the native ellipse, only e few pixels differ.
698
699The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
700slower as DrawEllipse(...), which calls the native API.
701An rotated ellipse outside the clipping region takes nearly the same time,
702while an native ellipse outside takes nearly no time to draw.
703
2aaa050c 704If you draw an arc with this new method, you will see the starting and ending angles
12bdd77c
JS
705are calculated properly.
706If you use DrawEllipticArc(...), you will see they are only correct for circles
707and not properly calculated for ellipses.
708
709Peter Lenhard
710p.lenhard@t-online.de
711*/
712
713#ifdef __WXWINCE__
2aaa050c
VZ
714void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
715 wxCoord w, wxCoord h,
12bdd77c
JS
716 double sa, double ea, double angle )
717{
718 wxList list;
719
720 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
721 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
722
723 // Add center (for polygon/pie)
724 list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) );
725
726 // copy list into array and delete list elements
727 int n = list.Number();
728 wxPoint *points = new wxPoint[n];
729 int i = 0;
2aaa050c 730 wxNode* node = 0;
12bdd77c
JS
731 for ( node = list.First(); node; node = node->Next(), i++ )
732 {
733 wxPoint *point = (wxPoint *)node->Data();
734 points[i].x = point->x;
735 points[i].y = point->y;
736 delete point;
737 }
738
739 // first draw the pie without pen, if necessary
63b9e659 740 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
741 {
742 wxPen tempPen( GetPen() );
743 SetPen( *wxTRANSPARENT_PEN );
744 DoDrawPolygon( n, points, 0, 0 );
745 SetPen( tempPen );
746 }
747
748 // then draw the arc without brush, if necessary
63b9e659 749 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
750 {
751 // without center
752 DoDrawLines( n-1, points, 0, 0 );
753 }
754
755 delete [] points;
756
757} // DrawEllipticArcRot
758
759void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
760{
761 if( angle != 0.0 )
762 {
e0d31471 763 double pi(M_PI);
12bdd77c
JS
764 double dSinA = -sin(angle*2.0*pi/360.0);
765 double dCosA = cos(angle*2.0*pi/360.0);
766 for ( wxNode* node = points->First(); node; node = node->Next() )
767 {
768 wxPoint* point = (wxPoint*)node->Data();
2aaa050c 769
12bdd77c
JS
770 // transform coordinates, if necessary
771 if( center.x ) point->x -= center.x;
772 if( center.y ) point->y -= center.y;
773
774 // calculate rotation, rounding simply by implicit cast to integer
775 int xTemp = point->x * dCosA - point->y * dSinA;
776 point->y = point->x * dSinA + point->y * dCosA;
777 point->x = xTemp;
778
779 // back transform coordinates, if necessary
780 if( center.x ) point->x += center.x;
781 if( center.y ) point->y += center.y;
782 }
783 }
784}
785
2aaa050c
VZ
786void wxDCBase::CalculateEllipticPoints( wxList* points,
787 wxCoord xStart, wxCoord yStart,
788 wxCoord w, wxCoord h,
12bdd77c
JS
789 double sa, double ea )
790{
e0d31471 791 double pi = M_PI;
12bdd77c
JS
792 double sar = 0;
793 double ear = 0;
794 int xsa = 0;
795 int ysa = 0;
796 int xea = 0;
797 int yea = 0;
798 int sq = 0;
799 int eq = 0;
800 bool bUseAngles = false;
801 if( w<0 ) w = -w;
802 if( h<0 ) h = -h;
803 // half-axes
804 wxCoord a = w/2;
805 wxCoord b = h/2;
806 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
807 int decrX = 0;
2aaa050c 808 if( 2*a == w ) decrX = 1;
12bdd77c 809 int decrY = 0;
2aaa050c 810 if( 2*b == h ) decrY = 1;
12bdd77c
JS
811 // center
812 wxCoord xCenter = xStart + a;
813 wxCoord yCenter = yStart + b;
814 // calculate data for start and end, if necessary
815 if( sa != ea )
816 {
817 bUseAngles = true;
818 // normalisation of angles
819 while( sa<0 ) sa += 360;
820 while( ea<0 ) ea += 360;
821 while( sa>=360 ) sa -= 360;
822 while( ea>=360 ) ea -= 360;
823 // calculate quadrant numbers
824 if( sa > 270 ) sq = 3;
825 else if( sa > 180 ) sq = 2;
826 else if( sa > 90 ) sq = 1;
827 if( ea > 270 ) eq = 3;
828 else if( ea > 180 ) eq = 2;
829 else if( ea > 90 ) eq = 1;
830 sar = sa * pi / 180.0;
831 ear = ea * pi / 180.0;
832 // correct angle circle -> ellipse
833 sar = atan( -a/(double)b * tan( sar ) );
2aaa050c 834 if ( sq == 1 || sq == 2 ) sar += pi;
12bdd77c
JS
835 ear = atan( -a/(double)b * tan( ear ) );
836 if ( eq == 1 || eq == 2 ) ear += pi;
837 // coordinates of points
838 xsa = xCenter + a * cos( sar );
839 if( sq == 0 || sq == 3 ) xsa -= decrX;
840 ysa = yCenter + b * sin( sar );
841 if( sq == 2 || sq == 3 ) ysa -= decrY;
842 xea = xCenter + a * cos( ear );
843 if( eq == 0 || eq == 3 ) xea -= decrX;
844 yea = yCenter + b * sin( ear );
845 if( eq == 2 || eq == 3 ) yea -= decrY;
846 } // if iUseAngles
847 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
848 double c1 = b * b;
849 double c2 = 2.0 / w;
850 c2 *= c2;
851 c2 *= c1;
852 wxCoord x = 0;
853 wxCoord y = b;
854 long x2 = 1;
855 long y2 = y*y;
856 long y2_old = 0;
857 long y_old = 0;
858 // Lists for quadrant 1 to 4
859 wxList pointsarray[4];
860 // Calculate points for first quadrant and set in all quadrants
861 for( x = 0; x <= a; ++x )
862 {
863 x2 = x2+x+x-1;
864 y2_old = y2;
865 y_old = y;
866 bool bNewPoint = false;
867 while( y2 > c1 - c2 * x2 && y > 0 )
868 {
869 bNewPoint = true;
870 y2 = y2-y-y+1;
871 --y;
872 }
2aaa050c 873 // old y now to big: set point with old y, old x
12bdd77c
JS
874 if( bNewPoint && x>1)
875 {
876 int x1 = x - 1;
877 // remove points on the same line
878 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
879 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) );
880 pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
881 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
882 } // set point
883 } // calculate point
2aaa050c 884
12bdd77c
JS
885 // Starting and/or ending points for the quadrants, first quadrant gets both.
886 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
887 pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) );
888 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) );
889 pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) );
890 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
891
892 // copy quadrants in original list
893 if( bUseAngles )
894 {
895 // Copy the right part of the points in the lists
896 // and delete the wxPoints, because they do not leave this method.
897 points->Append( (wxObject*) new wxPoint( xsa, ysa ) );
898 int q = sq;
899 bool bStarted = false;
900 bool bReady = false;
901 bool bForceTurn = ( sq == eq && sa > ea );
902 while( !bReady )
903 {
904 for( wxNode *node = pointsarray[q].First(); node; node = node->Next() )
905 {
906 // once: go to starting point in start quadrant
907 if( !bStarted &&
2aaa050c
VZ
908 (
909 ( (wxPoint*) node->Data() )->x < xsa+1 && q <= 1
910 ||
12bdd77c
JS
911 ( (wxPoint*) node->Data() )->x > xsa-1 && q >= 2
912 )
2aaa050c 913 )
12bdd77c
JS
914 {
915 bStarted = true;
916 }
917
918 // copy point, if not at ending point
919 if( bStarted )
920 {
921 if( q != eq || bForceTurn
922 ||
2aaa050c
VZ
923 ( (wxPoint*) node->Data() )->x > xea+1 && q <= 1
924 ||
12bdd77c
JS
925 ( (wxPoint*) node->Data() )->x < xea-1 && q >= 2
926 )
927 {
928 // copy point
929 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->Data() ) );
930 points->Append( (wxObject*) pPoint );
931 }
932 else if( q == eq && !bForceTurn || ( (wxPoint*) node->Data() )->x == xea)
933 {
2aaa050c 934 bReady = true;
12bdd77c
JS
935 }
936 }
937 } // for node
938 ++q;
939 if( q > 3 ) q = 0;
940 bForceTurn = false;
941 bStarted = true;
942 } // while not bReady
943 points->Append( (wxObject*) new wxPoint( xea, yea ) );
944
945 // delete points
946 for( q = 0; q < 4; ++q )
947 {
948 for( wxNode *node = pointsarray[q].First(); node; node = node->Next() )
949 {
950 wxPoint *p = (wxPoint *)node->Data();
951 delete p;
952 }
2aaa050c 953 }
12bdd77c
JS
954 }
955 else
956 {
957 // copy whole ellipse, wxPoints will be deleted outside
958 for( wxNode *node = pointsarray[0].First(); node; node = node->Next() )
959 {
960 wxObject *p = node->Data();
961 points->Append( p );
962 }
963 for( node = pointsarray[1].First(); node; node = node->Next() )
964 {
965 wxObject *p = node->Data();
966 points->Append( p );
967 }
968 for( node = pointsarray[2].First(); node; node = node->Next() )
969 {
970 wxObject *p = node->Data();
971 points->Append( p );
972 }
973 for( node = pointsarray[3].First(); node; node = node->Next() )
974 {
975 wxObject *p = node->Data();
976 points->Append( p );
977 }
978 } // not iUseAngles
979} // CalculateEllipticPoints
980
981#endif
982