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