~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/common/dcbase.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

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