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