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