]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
corrected DECLARE_DYNAMIC_CLASS use
[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"
ab171e95
RR
28#include "wx/dcclient.h"
29#include "wx/dcmemory.h"
30#include "wx/dcscreen.h"
4f37154e 31#include "wx/dcprint.h"
653752be 32#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
4f37154e 33#include "wx/prntbase.h"
18680f86
WS
34
35#ifndef WX_PRECOMP
36 #include "wx/math.h"
37#endif
dbe94982 38
888dde65 39#if wxUSE_NEW_DC
2970ae54 40
888dde65
RR
41#ifdef __WXMSW__
42#include "wx/msw/dcclient.h"
43#include "wx/msw/dcmemory.h"
44#include "wx/msw/dcscreen.h"
45#endif
2970ae54 46
888dde65
RR
47#ifdef __WXGTK__
48#include "wx/gtk/dcclient.h"
49#include "wx/gtk/dcmemory.h"
50#include "wx/gtk/dcscreen.h"
51#endif
52
53#ifdef __WXMAC__
54#include "wx/mac/dcclient.h"
55#include "wx/mac/dcmemory.h"
56#include "wx/mac/dcscreen.h"
57#endif
2970ae54
RR
58
59//----------------------------------------------------------------------------
60// wxDCFactory
61//----------------------------------------------------------------------------
62
63wxDCFactory *wxDCFactory::m_factory = NULL;
64
65void wxDCFactory::SetDCFactory( wxDCFactory *factory )
66{
67 if (wxDCFactory::m_factory)
68 delete wxDCFactory::m_factory;
69
70 wxDCFactory::m_factory = factory;
71}
72
73wxDCFactory *wxDCFactory::GetFactory()
74{
75 if (!wxDCFactory::m_factory)
76 wxDCFactory::m_factory = new wxNativeDCFactory;
77
78 return wxDCFactory::m_factory;
79}
80
81//-----------------------------------------------------------------------------
82// wxNativeDCFactory
83//-----------------------------------------------------------------------------
84
888dde65 85wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
2970ae54 86{
888dde65 87 return new wxWindowDCImpl( owner );
2970ae54
RR
88}
89
888dde65 90wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
2970ae54 91{
888dde65 92 return new wxWindowDCImpl( owner, window );
2970ae54
RR
93}
94
888dde65
RR
95wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
96{
97 return new wxClientDCImpl( owner );
2970ae54
RR
98}
99
888dde65
RR
100wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
101{
102 return new wxClientDCImpl( owner, window );
2970ae54
RR
103}
104
888dde65
RR
105wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
106{
107 return new wxPaintDCImpl( owner );
2970ae54
RR
108}
109
888dde65
RR
110wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
111{
112 return new wxPaintDCImpl( owner, window );
2970ae54
RR
113}
114
888dde65
RR
115wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
116{
117 return new wxMemoryDCImpl( owner );
2970ae54
RR
118}
119
888dde65
RR
120wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
121{
122 return new wxMemoryDCImpl( owner, bitmap );
2970ae54
RR
123}
124
888dde65
RR
125wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
126{
127 return new wxMemoryDCImpl( owner, dc );
ab171e95
RR
128}
129
888dde65
RR
130wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
131{
132 return new wxScreenDCImpl( owner );
2970ae54
RR
133}
134
888dde65 135wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
c8ddadff 136{
4f37154e 137 wxPrintFactory *factory = wxPrintFactory::GetFactory();
888dde65 138 return factory->CreatePrinterDCImpl( owner, data );
c8ddadff
RR
139}
140
2970ae54
RR
141//-----------------------------------------------------------------------------
142// wxWindowDC
143//-----------------------------------------------------------------------------
144
145IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
146
ab171e95 147wxWindowDC::wxWindowDC()
2970ae54 148{
2970ae54
RR
149}
150
ab171e95 151wxWindowDC::wxWindowDC( wxWindow *win )
2970ae54
RR
152{
153 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 154 m_pimpl = factory->CreateWindowDC( this, win );
2970ae54
RR
155}
156
157//-----------------------------------------------------------------------------
158// wxClientDC
159//-----------------------------------------------------------------------------
160
888dde65 161IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
2970ae54
RR
162
163wxClientDC::wxClientDC()
164{
2970ae54
RR
165}
166
167wxClientDC::wxClientDC( wxWindow *win )
168{
169 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 170 m_pimpl = factory->CreateClientDC( this, win );
2970ae54
RR
171}
172
173//-----------------------------------------------------------------------------
174// wxMemoryDC
175//-----------------------------------------------------------------------------
176
177IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
178
179wxMemoryDC::wxMemoryDC()
180{
181 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 182 m_pimpl = factory->CreateMemoryDC( this );
2970ae54
RR
183}
184
185wxMemoryDC::wxMemoryDC( wxBitmap& bitmap )
186{
187 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 188 m_pimpl = factory->CreateMemoryDC( this, bitmap );
2970ae54
RR
189}
190
191wxMemoryDC::wxMemoryDC( wxDC *dc )
192{
193 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95
RR
194 m_pimpl = factory->CreateMemoryDC( this, dc );
195}
196
197void wxMemoryDC::SelectObject(wxBitmap& bmp)
198{
199 // make sure that the given wxBitmap is not sharing its data with other
200 // wxBitmap instances as its contents will be modified by any drawing
201 // operation done on this DC
202 if (bmp.IsOk())
203 bmp.UnShare();
204
4f37154e 205 GetImpl()->DoSelect(bmp);
ab171e95
RR
206}
207
208void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
209{
4f37154e 210 GetImpl()->DoSelect(bmp);
2970ae54 211}
ab171e95
RR
212
213const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
214{
4f37154e 215 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
216}
217
218wxBitmap& wxMemoryDC::GetSelectedBitmap()
219{
4f37154e 220 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
221}
222
2970ae54
RR
223
224//-----------------------------------------------------------------------------
225// wxPaintDC
226//-----------------------------------------------------------------------------
227
888dde65 228IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
2970ae54
RR
229
230wxPaintDC::wxPaintDC()
231{
2970ae54
RR
232}
233
234wxPaintDC::wxPaintDC( wxWindow *win )
235{
236 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95
RR
237 m_pimpl = factory->CreatePaintDC( this, win );
238}
239
240//-----------------------------------------------------------------------------
241// wxScreenDC
242//-----------------------------------------------------------------------------
243
244IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
245
246wxScreenDC::wxScreenDC()
247{
248 wxDCFactory *factory = wxDCFactory::GetFactory();
249 m_pimpl = factory->CreateScreenDC( this );
2970ae54
RR
250}
251
4f37154e
RR
252//-----------------------------------------------------------------------------
253// wxPrinterDC
254//-----------------------------------------------------------------------------
255
256IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
257
258wxPrinterDC::wxPrinterDC()
259{
888dde65 260 wxPrintData data; // Does this make sense?
4f37154e 261 wxDCFactory *factory = wxDCFactory::GetFactory();
888dde65 262 m_pimpl = factory->CreatePrinterDC( this, data );
4f37154e
RR
263}
264
265wxPrinterDC::wxPrinterDC( const wxPrintData &data )
266{
267 wxDCFactory *factory = wxDCFactory::GetFactory();
268 m_pimpl = factory->CreatePrinterDC( this, data );
269}
270
38dd8ed4
RR
271wxPrinterDC::~wxPrinterDC()
272{
273}
274
275wxRect wxPrinterDC::GetPaperRect()
276{
277 return GetImpl()->GetPaperRect();
278}
279
280int wxPrinterDC::GetResolution()
281{
282 return GetImpl()->GetResolution();
283}
284
285
2970ae54 286//-----------------------------------------------------------------------------
888dde65 287// wxDCImpl
2970ae54
RR
288//-----------------------------------------------------------------------------
289
888dde65 290IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
2970ae54 291
888dde65
RR
292wxDCImpl::wxDCImpl( wxDC *owner )
293 : m_window(NULL)
294 , m_colour(wxColourDisplay())
2970ae54
RR
295 , m_ok(true)
296 , m_clipping(false)
297 , m_isInteractive(0)
298 , m_isBBoxValid(false)
299 , m_logicalOriginX(0), m_logicalOriginY(0)
300 , m_deviceOriginX(0), m_deviceOriginY(0)
301 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
302 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
303 , m_userScaleX(1.0), m_userScaleY(1.0)
304 , m_scaleX(1.0), m_scaleY(1.0)
305 , m_signX(1), m_signY(1)
306 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
307 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
308 , m_logicalFunction(wxCOPY)
309 , m_backgroundMode(wxTRANSPARENT)
310 , m_mappingMode(wxMM_TEXT)
311 , m_pen()
312 , m_brush()
313 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
314 , m_textForegroundColour(*wxBLACK)
315 , m_textBackgroundColour(*wxWHITE)
316 , m_font()
317#if wxUSE_PALETTE
318 , m_palette()
319 , m_hasCustomPalette(false)
320#endif // wxUSE_PALETTE
321{
322 m_owner = owner;
323
324 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
325 (double)wxGetDisplaySizeMM().GetWidth();
326 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
327 (double)wxGetDisplaySizeMM().GetHeight();
328
329 ResetBoundingBox();
330 ResetClipping();
331}
332
888dde65 333wxDCImpl::~wxDCImpl()
2970ae54
RR
334{
335}
336
2970ae54
RR
337// ----------------------------------------------------------------------------
338// coordinate conversions and transforms
339// ----------------------------------------------------------------------------
340
888dde65 341wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
2970ae54
RR
342{
343 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
344}
345
888dde65 346wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
2970ae54
RR
347{
348 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
349}
350
888dde65 351wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
2970ae54
RR
352{
353 return wxRound((double)(x) / m_scaleX);
354}
355
888dde65 356wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
2970ae54
RR
357{
358 return wxRound((double)(y) / m_scaleY);
359}
360
888dde65 361wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
2970ae54 362{
02255e07 363 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
2970ae54
RR
364}
365
888dde65 366wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
2970ae54 367{
02255e07 368 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY;
2970ae54
RR
369}
370
888dde65 371wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
2970ae54
RR
372{
373 return wxRound((double)(x) * m_scaleX);
374}
375
888dde65 376wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
2970ae54
RR
377{
378 return wxRound((double)(y) * m_scaleY);
379}
380
888dde65 381void wxDCImpl::ComputeScaleAndOrigin()
2970ae54
RR
382{
383 m_scaleX = m_logicalScaleX * m_userScaleX;
384 m_scaleY = m_logicalScaleY * m_userScaleY;
385}
386
888dde65 387void wxDCImpl::SetMapMode( int mode )
2970ae54
RR
388{
389 switch (mode)
390 {
391 case wxMM_TWIPS:
392 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
393 break;
394 case wxMM_POINTS:
395 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
396 break;
397 case wxMM_METRIC:
398 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
399 break;
400 case wxMM_LOMETRIC:
401 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
402 break;
403 default:
404 case wxMM_TEXT:
405 SetLogicalScale( 1.0, 1.0 );
406 break;
407 }
408 m_mappingMode = mode;
409}
410
888dde65 411void wxDCImpl::SetUserScale( double x, double y )
2970ae54
RR
412{
413 // allow negative ? -> no
414 m_userScaleX = x;
415 m_userScaleY = y;
416 ComputeScaleAndOrigin();
417}
418
888dde65 419void wxDCImpl::SetLogicalScale( double x, double y )
2970ae54
RR
420{
421 // allow negative ?
422 m_logicalScaleX = x;
423 m_logicalScaleY = y;
424 ComputeScaleAndOrigin();
425}
426
888dde65 427void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
2970ae54
RR
428{
429 m_logicalOriginX = x * m_signX;
430 m_logicalOriginY = y * m_signY;
431 ComputeScaleAndOrigin();
432}
433
888dde65 434void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
2970ae54
RR
435{
436 m_deviceOriginX = x;
437 m_deviceOriginY = y;
438 ComputeScaleAndOrigin();
439}
440
888dde65 441void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
2970ae54
RR
442{
443 m_deviceLocalOriginX = x;
444 m_deviceLocalOriginY = y;
445 ComputeScaleAndOrigin();
446}
447
888dde65 448void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
2970ae54
RR
449{
450 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 451 // wxWidgets 2.9: no longer override it
2970ae54
RR
452 m_signX = (xLeftRight ? 1 : -1);
453 m_signY = (yBottomUp ? -1 : 1);
454 ComputeScaleAndOrigin();
455}
456
457
458// Each element of the widths array will be the width of the string up to and
459// including the corresponding character in text. This is the generic
460// implementation, the port-specific classes should do this with native APIs
461// if available and if faster. Note: pango_layout_index_to_pos is much slower
462// than calling GetTextExtent!!
463
464#define FWC_SIZE 256
465
466class FontWidthCache
467{
468public:
469 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
470 ~FontWidthCache() { delete []m_widths; }
471
472 void Reset()
473 {
474 if (!m_widths)
475 m_widths = new int[FWC_SIZE];
476
477 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
478 }
479
480 wxFont m_font;
481 double m_scaleX;
482 int *m_widths;
483};
484
485static FontWidthCache s_fontWidthCache;
486
888dde65 487bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2970ae54
RR
488{
489 int totalWidth = 0;
490
491 const size_t len = text.length();
492 widths.Empty();
493 widths.Add(0, len);
494
495 // reset the cache if font or horizontal scale have changed
496 if ( !s_fontWidthCache.m_widths ||
497 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
498 (s_fontWidthCache.m_font != GetFont()) )
499 {
500 s_fontWidthCache.Reset();
501 s_fontWidthCache.m_font = GetFont();
502 s_fontWidthCache.m_scaleX = m_scaleX;
503 }
504
505 // Calculate the position of each character based on the widths of
506 // the previous characters
507 int w, h;
508 for ( size_t i = 0; i < len; i++ )
509 {
510 const wxChar c = text[i];
511 unsigned int c_int = (unsigned int)c;
512
513 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
514 {
515 w = s_fontWidthCache.m_widths[c_int];
516 }
517 else
518 {
ab171e95 519 DoGetTextExtent(c, &w, &h);
2970ae54
RR
520 if (c_int < FWC_SIZE)
521 s_fontWidthCache.m_widths[c_int] = w;
522 }
523
524 totalWidth += w;
525 widths[i] = totalWidth;
526 }
527
528 return true;
529}
530
888dde65 531void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
2970ae54
RR
532 wxCoord *x,
533 wxCoord *y,
534 wxCoord *h,
535 const wxFont *font) const
536{
537 wxCoord widthTextMax = 0, widthLine,
538 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
539
540 wxString curLine;
4f37154e 541 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2970ae54 542 {
4f37154e 543 if ( pc == text.end() || *pc == _T('\n') )
2970ae54
RR
544 {
545 if ( curLine.empty() )
546 {
547 // we can't use GetTextExtent - it will return 0 for both width
548 // and height and an empty line should count in height
549 // calculation
550
551 // assume that this line has the same height as the previous
552 // one
553 if ( !heightLineDefault )
554 heightLineDefault = heightLine;
555
556 if ( !heightLineDefault )
557 {
558 // but we don't know it yet - choose something reasonable
559 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
560 NULL, NULL, font);
561 }
562
563 heightTextTotal += heightLineDefault;
564 }
565 else
566 {
567 DoGetTextExtent(curLine, &widthLine, &heightLine,
568 NULL, NULL, font);
569 if ( widthLine > widthTextMax )
570 widthTextMax = widthLine;
571 heightTextTotal += heightLine;
572 }
573
4f37154e 574 if ( pc == text.end() )
2970ae54 575 {
4f37154e 576 break;
2970ae54 577 }
4f37154e 578 else // '\n'
2970ae54 579 {
4f37154e 580 curLine.clear();
2970ae54
RR
581 }
582 }
583 else
584 {
585 curLine += *pc;
586 }
587 }
588
589 if ( x )
590 *x = widthTextMax;
591 if ( y )
592 *y = heightTextTotal;
593 if ( h )
594 *h = heightLine;
595}
596
888dde65 597void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
2970ae54
RR
598 wxCoord width, wxCoord height)
599{
ab171e95 600 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
601
602 wxCoord x2 = x1 + width,
603 y2 = y1 + height;
604
605 // the pen width is calibrated to give 3 for width == height == 10
ab171e95 606 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
2970ae54
RR
607
608 // we're drawing a scaled version of wx/generic/tick.xpm here
609 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
610 y3 = y1 + height / 2; // y of the left tick branch
611 DoDrawLine(x1, y3, x3, y2);
612 DoDrawLine(x3, y2, x2, y1);
613
614 CalcBoundingBox(x1, y1);
615 CalcBoundingBox(x2, y2);
616}
617
618bool
888dde65 619wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
2970ae54
RR
620 wxCoord dstWidth, wxCoord dstHeight,
621 wxDC *source,
622 wxCoord xsrc, wxCoord ysrc,
623 wxCoord srcWidth, wxCoord srcHeight,
624 int rop,
625 bool useMask,
626 wxCoord xsrcMask,
627 wxCoord ysrcMask)
628{
629 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
630 _T("invalid blit size") );
631
632 // emulate the stretching by modifying the DC scale
633 double xscale = (double)srcWidth/dstWidth,
634 yscale = (double)srcHeight/dstHeight;
635
636 double xscaleOld, yscaleOld;
637 GetUserScale(&xscaleOld, &yscaleOld);
638 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
639
640 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
641 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
642 source,
643 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
644
645 SetUserScale(xscaleOld, yscaleOld);
646
647 return rc;
648}
649
888dde65 650void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
2970ae54
RR
651{
652 int n = list->GetCount();
653 wxPoint *points = new wxPoint[n];
654
655 int i = 0;
b0d7707b 656 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 657 {
b0d7707b 658 wxPoint *point = node->GetData();
2970ae54
RR
659 points[i].x = point->x;
660 points[i].y = point->y;
661 }
662
663 DoDrawLines(n, points, xoffset, yoffset);
664
665 delete [] points;
666}
667
888dde65 668void wxDCImpl::DrawPolygon(const wxPointList *list,
2970ae54
RR
669 wxCoord xoffset, wxCoord yoffset,
670 int fillStyle)
671{
672 int n = list->GetCount();
673 wxPoint *points = new wxPoint[n];
674
675 int i = 0;
b0d7707b 676 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 677 {
b0d7707b 678 wxPoint *point = node->GetData();
2970ae54
RR
679 points[i].x = point->x;
680 points[i].y = point->y;
681 }
682
683 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
684
685 delete [] points;
686}
687
688void
888dde65 689wxDCImpl::DoDrawPolyPolygon(int n,
2970ae54
RR
690 int count[],
691 wxPoint points[],
692 wxCoord xoffset, wxCoord yoffset,
693 int fillStyle)
694{
695 if ( n == 1 )
696 {
697 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
698 return;
699 }
700
701 int i, j, lastOfs;
702 wxPoint* pts;
703 wxPen pen;
704
705 for (i = j = lastOfs = 0; i < n; i++)
706 {
707 lastOfs = j;
708 j += count[i];
709 }
710 pts = new wxPoint[j+n-1];
711 for (i = 0; i < j; i++)
712 pts[i] = points[i];
713 for (i = 2; i <= n; i++)
714 {
715 lastOfs -= count[n-i];
716 pts[j++] = pts[lastOfs];
717 }
718
719 pen = GetPen();
720 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
721 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
722 SetPen(pen);
723 for (i = j = 0; i < n; i++)
724 {
725 DoDrawLines(count[i], pts+j, xoffset, yoffset);
726 j += count[i];
727 }
728 delete[] pts;
729}
730
731#if wxUSE_SPLINES
732
888dde65 733void wxDCImpl::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
2970ae54 734{
b0d7707b 735 wxPointList point_list;
2970ae54
RR
736
737 wxPoint *point1 = new wxPoint;
738 point1->x = x1; point1->y = y1;
b0d7707b 739 point_list.Append( point1 );
2970ae54
RR
740
741 wxPoint *point2 = new wxPoint;
742 point2->x = x2; point2->y = y2;
b0d7707b 743 point_list.Append( point2 );
2970ae54
RR
744
745 wxPoint *point3 = new wxPoint;
746 point3->x = x3; point3->y = y3;
b0d7707b 747 point_list.Append( point3 );
2970ae54 748
ab171e95 749 DoDrawSpline(&point_list);
2970ae54 750
b0d7707b 751 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
2970ae54 752 {
b0d7707b 753 wxPoint *p = node->GetData();
2970ae54
RR
754 delete p;
755 }
756}
757
888dde65 758void wxDCImpl::DoDrawSpline(int n, wxPoint points[])
2970ae54 759{
b0d7707b 760 wxPointList list;
2970ae54 761 for (int i =0; i < n; i++)
b0d7707b 762 list.Append( &points[i] );
2970ae54 763
ab171e95 764 DoDrawSpline(&list);
2970ae54
RR
765}
766
767// ----------------------------------- spline code ----------------------------------------
768
769void wx_quadratic_spline(double a1, double b1, double a2, double b2,
770 double a3, double b3, double a4, double b4);
771void wx_clear_stack();
772int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
773 double *y3, double *x4, double *y4);
774void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
775 double x4, double y4);
776static bool wx_spline_add_point(double x, double y);
ab171e95 777static void wx_spline_draw_point_array(wxDC *dc);
2970ae54 778
b0d7707b 779wxPointList wx_spline_point_list;
2970ae54
RR
780
781#define half(z1, z2) ((z1+z2)/2.0)
782#define THRESHOLD 5
783
784/* iterative version */
785
786void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
787 double b4)
788{
789 register double xmid, ymid;
790 double x1, y1, x2, y2, x3, y3, x4, y4;
791
792 wx_clear_stack();
793 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
794
795 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
796 xmid = (double)half(x2, x3);
797 ymid = (double)half(y2, y3);
798 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
799 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
800 wx_spline_add_point( x1, y1 );
801 wx_spline_add_point( xmid, ymid );
802 } else {
803 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
804 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
805 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
806 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
807 }
808 }
809}
810
811/* utilities used by spline drawing routines */
812
813typedef struct wx_spline_stack_struct {
814 double x1, y1, x2, y2, x3, y3, x4, y4;
815} Stack;
816
817#define SPLINE_STACK_DEPTH 20
818static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
819static Stack *wx_stack_top;
820static int wx_stack_count;
821
822void wx_clear_stack()
823{
824 wx_stack_top = wx_spline_stack;
825 wx_stack_count = 0;
826}
827
828void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
829{
830 wx_stack_top->x1 = x1;
831 wx_stack_top->y1 = y1;
832 wx_stack_top->x2 = x2;
833 wx_stack_top->y2 = y2;
834 wx_stack_top->x3 = x3;
835 wx_stack_top->y3 = y3;
836 wx_stack_top->x4 = x4;
837 wx_stack_top->y4 = y4;
838 wx_stack_top++;
839 wx_stack_count++;
840}
841
842int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
843 double *x3, double *y3, double *x4, double *y4)
844{
845 if (wx_stack_count == 0)
846 return (0);
847 wx_stack_top--;
848 wx_stack_count--;
849 *x1 = wx_stack_top->x1;
850 *y1 = wx_stack_top->y1;
851 *x2 = wx_stack_top->x2;
852 *y2 = wx_stack_top->y2;
853 *x3 = wx_stack_top->x3;
854 *y3 = wx_stack_top->y3;
855 *x4 = wx_stack_top->x4;
856 *y4 = wx_stack_top->y4;
857 return (1);
858}
859
860static bool wx_spline_add_point(double x, double y)
861{
b0d7707b
RR
862 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
863 wx_spline_point_list.Append(point );
864 return true;
2970ae54
RR
865}
866
867static void wx_spline_draw_point_array(wxDC *dc)
868{
4f37154e 869 dc->DrawLines(&wx_spline_point_list, 0, 0 );
b0d7707b
RR
870 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
871 while (node)
872 {
873 wxPoint *point = node->GetData();
874 delete point;
875 wx_spline_point_list.Erase(node);
876 node = wx_spline_point_list.GetFirst();
877 }
2970ae54
RR
878}
879
888dde65 880void wxDCImpl::DoDrawSpline( const wxPointList *points )
2970ae54 881{
ab171e95 882 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
883
884 wxPoint *p;
885 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
886 double x1, y1, x2, y2;
887
b0d7707b 888 wxPointList::compatibility_iterator node = points->GetFirst();
2970ae54
RR
889 if (!node)
890 // empty list
891 return;
892
893 p = (wxPoint *)node->GetData();
894
895 x1 = p->x;
896 y1 = p->y;
897
898 node = node->GetNext();
b0d7707b 899 p = node->GetData();
2970ae54
RR
900
901 x2 = p->x;
902 y2 = p->y;
903 cx1 = (double)((x1 + x2) / 2);
904 cy1 = (double)((y1 + y2) / 2);
905 cx2 = (double)((cx1 + x2) / 2);
906 cy2 = (double)((cy1 + y2) / 2);
907
908 wx_spline_add_point(x1, y1);
909
910 while ((node = node->GetNext())
911#if !wxUSE_STL
912 != NULL
913#endif // !wxUSE_STL
914 )
915 {
b0d7707b 916 p = node->GetData();
2970ae54
RR
917 x1 = x2;
918 y1 = y2;
919 x2 = p->x;
920 y2 = p->y;
921 cx4 = (double)(x1 + x2) / 2;
922 cy4 = (double)(y1 + y2) / 2;
923 cx3 = (double)(x1 + cx4) / 2;
924 cy3 = (double)(y1 + cy4) / 2;
925
926 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
927
928 cx1 = cx4;
929 cy1 = cy4;
930 cx2 = (double)(cx1 + x2) / 2;
931 cy2 = (double)(cy1 + y2) / 2;
932 }
933
934 wx_spline_add_point( cx1, cy1 );
935 wx_spline_add_point( x2, y2 );
936
937 wx_spline_draw_point_array( m_owner );
938}
939
940#endif // wxUSE_SPLINES
941
942
2970ae54 943
888dde65 944void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
2970ae54
RR
945 const wxColour& initialColour,
946 const wxColour& destColour,
947 wxDirection nDirection)
948{
949 // save old pen
950 wxPen oldPen = m_pen;
951 wxBrush oldBrush = m_brush;
952
953 wxUint8 nR1 = initialColour.Red();
954 wxUint8 nG1 = initialColour.Green();
955 wxUint8 nB1 = initialColour.Blue();
956 wxUint8 nR2 = destColour.Red();
957 wxUint8 nG2 = destColour.Green();
958 wxUint8 nB2 = destColour.Blue();
959 wxUint8 nR, nG, nB;
960
961 if ( nDirection == wxEAST || nDirection == wxWEST )
962 {
963 wxInt32 x = rect.GetWidth();
964 wxInt32 w = x; // width of area to shade
965 wxInt32 xDelta = w/256; // height of one shade bend
966 if (xDelta < 1)
967 xDelta = 1;
968
969 while (x >= xDelta)
970 {
971 x -= xDelta;
972 if (nR1 > nR2)
973 nR = nR1 - (nR1-nR2)*(w-x)/w;
974 else
975 nR = nR1 + (nR2-nR1)*(w-x)/w;
976
977 if (nG1 > nG2)
978 nG = nG1 - (nG1-nG2)*(w-x)/w;
979 else
980 nG = nG1 + (nG2-nG1)*(w-x)/w;
981
982 if (nB1 > nB2)
983 nB = nB1 - (nB1-nB2)*(w-x)/w;
984 else
985 nB = nB1 + (nB2-nB1)*(w-x)/w;
986
987 wxColour colour(nR,nG,nB);
988 SetPen(wxPen(colour, 1, wxSOLID));
989 SetBrush(wxBrush(colour));
990 if(nDirection == wxEAST)
5f77ee3b 991 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2970ae54
RR
992 xDelta, rect.GetHeight());
993 else //nDirection == wxWEST
994 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
995 xDelta, rect.GetHeight());
996 }
997 }
998 else // nDirection == wxNORTH || nDirection == wxSOUTH
999 {
1000 wxInt32 y = rect.GetHeight();
1001 wxInt32 w = y; // height of area to shade
1002 wxInt32 yDelta = w/255; // height of one shade bend
1003 if (yDelta < 1)
1004 yDelta = 1;
1005
1006 while (y > 0)
1007 {
1008 y -= yDelta;
1009 if (nR1 > nR2)
1010 nR = nR1 - (nR1-nR2)*(w-y)/w;
1011 else
1012 nR = nR1 + (nR2-nR1)*(w-y)/w;
1013
1014 if (nG1 > nG2)
1015 nG = nG1 - (nG1-nG2)*(w-y)/w;
1016 else
1017 nG = nG1 + (nG2-nG1)*(w-y)/w;
1018
1019 if (nB1 > nB2)
1020 nB = nB1 - (nB1-nB2)*(w-y)/w;
1021 else
1022 nB = nB1 + (nB2-nB1)*(w-y)/w;
1023
1024 wxColour colour(nR,nG,nB);
1025 SetPen(wxPen(colour, 1, wxSOLID));
1026 SetBrush(wxBrush(colour));
1027 if(nDirection == wxNORTH)
1028 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1029 rect.GetWidth(), yDelta);
1030 else //nDirection == wxSOUTH
5f77ee3b 1031 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2970ae54
RR
1032 rect.GetWidth(), yDelta);
1033 }
1034 }
1035
1036 SetPen(oldPen);
1037 SetBrush(oldBrush);
1038}
1039
888dde65 1040void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
2970ae54
RR
1041 const wxColour& initialColour,
1042 const wxColour& destColour,
1043 const wxPoint& circleCenter)
1044{
1045 //save the old pen color
1046 wxColour oldPenColour = m_pen.GetColour();
1047
1048 wxUint8 nR1 = destColour.Red();
1049 wxUint8 nG1 = destColour.Green();
1050 wxUint8 nB1 = destColour.Blue();
1051 wxUint8 nR2 = initialColour.Red();
1052 wxUint8 nG2 = initialColour.Green();
1053 wxUint8 nB2 = initialColour.Blue();
1054 wxUint8 nR, nG, nB;
1055
1056
1057 //Radius
1058 wxInt32 cx = rect.GetWidth() / 2;
1059 wxInt32 cy = rect.GetHeight() / 2;
1060 wxInt32 nRadius;
1061 if (cx < cy)
1062 nRadius = cx;
1063 else
1064 nRadius = cy;
1065
1066 //Offset of circle
1067 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1068 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1069
1070 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1071 {
1072 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1073 {
1074 //get color difference
1075 wxInt32 nGradient = ((nRadius -
1076 (wxInt32)sqrt(
1077 pow((double)(x - cx - nCircleOffX), 2) +
1078 pow((double)(y - cy - nCircleOffY), 2)
1079 )) * 100) / nRadius;
1080
1081 //normalize Gradient
1082 if (nGradient < 0 )
1083 nGradient = 0;
1084
1085 //get dest colors
1086 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1087 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1088 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1089
1090 //set the pixel
1091 m_pen.SetColour(wxColour(nR,nG,nB));
ab171e95 1092 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
2970ae54
RR
1093 }
1094 }
1095 //return old pen color
1096 m_pen.SetColour(oldPenColour);
1097}
1098
1099//-----------------------------------------------------------------------------
1100// wxDC
1101//-----------------------------------------------------------------------------
1102
1103IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1104
ab171e95
RR
1105void wxDC::DrawLabel(const wxString& text,
1106 const wxBitmap& bitmap,
1107 const wxRect& rect,
1108 int alignment,
1109 int indexAccel,
1110 wxRect *rectBounding)
1111{
1112 // find the text position
1113 wxCoord widthText, heightText, heightLine;
1114 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1115
1116 wxCoord width, height;
1117 if ( bitmap.Ok() )
1118 {
1119 width = widthText + bitmap.GetWidth();
1120 height = bitmap.GetHeight();
1121 }
1122 else // no bitmap
1123 {
1124 width = widthText;
1125 height = heightText;
1126 }
1127
1128 wxCoord x, y;
1129 if ( alignment & wxALIGN_RIGHT )
1130 {
1131 x = rect.GetRight() - width;
1132 }
1133 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1134 {
1135 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1136 }
1137 else // alignment & wxALIGN_LEFT
1138 {
1139 x = rect.GetLeft();
1140 }
1141
1142 if ( alignment & wxALIGN_BOTTOM )
1143 {
1144 y = rect.GetBottom() - height;
1145 }
1146 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1147 {
1148 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1149 }
1150 else // alignment & wxALIGN_TOP
1151 {
1152 y = rect.GetTop();
1153 }
1154
1155 // draw the bitmap first
1156 wxCoord x0 = x,
1157 y0 = y,
1158 width0 = width;
1159 if ( bitmap.Ok() )
1160 {
1161 DrawBitmap(bitmap, x, y, true /* use mask */);
1162
1163 wxCoord offset = bitmap.GetWidth() + 4;
1164 x += offset;
1165 width -= offset;
1166
1167 y += (height - heightText) / 2;
1168 }
1169
1170 // we will draw the underscore under the accel char later
1171 wxCoord startUnderscore = 0,
1172 endUnderscore = 0,
1173 yUnderscore = 0;
1174
1175 // split the string into lines and draw each of them separately
1176 wxString curLine;
1177 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1178 {
1179 if ( *pc == _T('\n') || pc == text.end() )
1180 {
1181 int xRealStart = x; // init it here to avoid compielr warnings
1182
1183 if ( !curLine.empty() )
1184 {
1185 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1186 // wxALIGN_LEFT is 0
1187 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1188 {
1189 wxCoord widthLine;
1190 GetTextExtent(curLine, &widthLine, NULL);
1191
1192 if ( alignment & wxALIGN_RIGHT )
1193 {
1194 xRealStart += width - widthLine;
1195 }
1196 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1197 {
1198 xRealStart += (width - widthLine) / 2;
1199 }
1200 }
1201 //else: left aligned, nothing to do
1202
1203 DrawText(curLine, xRealStart, y);
1204 }
1205
1206 y += heightLine;
1207
1208 // do we have underscore in this line? we can check yUnderscore
1209 // because it is set below to just y + heightLine if we do
1210 if ( y == yUnderscore )
1211 {
1212 // adjust the horz positions to account for the shift
1213 startUnderscore += xRealStart;
1214 endUnderscore += xRealStart;
1215 }
1216
1217 if ( pc == text.end() )
1218 break;
1219
1220 curLine.clear();
1221 }
1222 else // not end of line
1223 {
1224 if ( pc - text.begin() == indexAccel )
1225 {
1226 // remeber to draw underscore here
1227 GetTextExtent(curLine, &startUnderscore, NULL);
1228 curLine += *pc;
1229 GetTextExtent(curLine, &endUnderscore, NULL);
1230
1231 yUnderscore = y + heightLine;
1232 }
1233 else
1234 {
1235 curLine += *pc;
1236 }
1237 }
1238 }
1239
1240 // draw the underscore if found
1241 if ( startUnderscore != endUnderscore )
1242 {
1243 // it should be of the same colour as text
1244 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1245
1246 yUnderscore--;
1247
1248 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1249 }
1250
1251 // return bounding rect if requested
1252 if ( rectBounding )
1253 {
1254 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1255 }
1256
1257 CalcBoundingBox(x0, y0);
1258 CalcBoundingBox(x0 + width0, y0 + height);
1259}
1260
2970ae54
RR
1261#if WXWIN_COMPATIBILITY_2_8
1262 // for compatibility with the old code when wxCoord was long everywhere
1263void wxDC::GetTextExtent(const wxString& string,
1264 long *x, long *y,
1265 long *descent,
1266 long *externalLeading,
1267 const wxFont *theFont) const
1268 {
1269 wxCoord x2, y2, descent2, externalLeading2;
1270 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1271 &descent2, &externalLeading2,
1272 theFont);
1273 if ( x )
1274 *x = x2;
1275 if ( y )
1276 *y = y2;
1277 if ( descent )
1278 *descent = descent2;
1279 if ( externalLeading )
1280 *externalLeading = externalLeading2;
1281 }
1282
1283void wxDC::GetLogicalOrigin(long *x, long *y) const
1284 {
1285 wxCoord x2, y2;
1286 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1287 if ( x )
1288 *x = x2;
1289 if ( y )
1290 *y = y2;
1291 }
1292
1293void wxDC::GetDeviceOrigin(long *x, long *y) const
1294 {
1295 wxCoord x2, y2;
1296 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1297 if ( x )
1298 *x = x2;
1299 if ( y )
1300 *y = y2;
1301 }
1302
1303void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1304 {
1305 wxCoord xx,yy,ww,hh;
1306 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1307 if (x) *x = xx;
1308 if (y) *y = yy;
1309 if (w) *w = ww;
1310 if (h) *h = hh;
1311 }
1312
1313#endif // WXWIN_COMPATIBILITY_2_8
1314
1315
1316#else // wxUSE_NEW_DC
1317
1318
68379eaf 1319// bool wxDCBase::sm_cacheing = false;
0cbff120 1320
e7445ff8
PC
1321IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
1322
1e6feb95
VZ
1323// ============================================================================
1324// implementation
1325// ============================================================================
1326
653752be
MB
1327IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
1328IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
1329
04ab8b6d
RR
1330wxDCBase::wxDCBase()
1331 : m_colour(wxColourDisplay())
1332 , m_ok(true)
1333 , m_clipping(false)
1334 , m_isInteractive(0)
1335 , m_isBBoxValid(false)
1336 , m_logicalOriginX(0), m_logicalOriginY(0)
1337 , m_deviceOriginX(0), m_deviceOriginY(0)
1338 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1339 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1340 , m_userScaleX(1.0), m_userScaleY(1.0)
1341 , m_scaleX(1.0), m_scaleY(1.0)
1342 , m_signX(1), m_signY(1)
1343 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1344 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1345 , m_logicalFunction(wxCOPY)
1346 , m_backgroundMode(wxTRANSPARENT)
1347 , m_mappingMode(wxMM_TEXT)
1348 , m_pen()
1349 , m_brush()
1350 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
1351 , m_textForegroundColour(*wxBLACK)
1352 , m_textBackgroundColour(*wxWHITE)
1353 , m_font()
1354#if wxUSE_PALETTE
1355 , m_palette()
1356 , m_hasCustomPalette(false)
1357#endif // wxUSE_PALETTE
1358{
1359 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
1360 (double)wxGetDisplaySizeMM().GetWidth();
1361 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
1362 (double)wxGetDisplaySizeMM().GetHeight();
1363
1364 ResetBoundingBox();
1365 ResetClipping();
1366}
1367
1368wxDCBase::~wxDCBase()
1369{
1370}
1371
68df211f
JG
1372#if WXWIN_COMPATIBILITY_2_6
1373void wxDCBase::BeginDrawing()
1374{
1375}
1376
1377void wxDCBase::EndDrawing()
1378{
1379}
1380#endif // WXWIN_COMPATIBILITY_2_6
1381
cfa87e81
RR
1382#if WXWIN_COMPATIBILITY_2_8
1383 // for compatibility with the old code when wxCoord was long everywhere
1384void wxDCBase::GetTextExtent(const wxString& string,
1385 long *x, long *y,
27ee942f
PC
1386 long *descent,
1387 long *externalLeading,
1388 const wxFont *theFont) const
cfa87e81
RR
1389 {
1390 wxCoord x2, y2, descent2, externalLeading2;
1391 DoGetTextExtent(string, &x2, &y2,
1392 &descent2, &externalLeading2,
1393 theFont);
1394 if ( x )
1395 *x = x2;
1396 if ( y )
1397 *y = y2;
1398 if ( descent )
1399 *descent = descent2;
1400 if ( externalLeading )
1401 *externalLeading = externalLeading2;
1402 }
1403
1404void wxDCBase::GetLogicalOrigin(long *x, long *y) const
1405 {
1406 wxCoord x2, y2;
1407 DoGetLogicalOrigin(&x2, &y2);
1408 if ( x )
1409 *x = x2;
1410 if ( y )
1411 *y = y2;
1412 }
1413
1414void wxDCBase::GetDeviceOrigin(long *x, long *y) const
1415 {
1416 wxCoord x2, y2;
1417 DoGetDeviceOrigin(&x2, &y2);
1418 if ( x )
1419 *x = x2;
1420 if ( y )
1421 *y = y2;
1422 }
1423
1424void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const
1425 {
1426 wxCoord xx,yy,ww,hh;
1427 DoGetClippingBox(&xx, &yy, &ww, &hh);
1428 if (x) *x = xx;
1429 if (y) *y = yy;
1430 if (w) *w = ww;
1431 if (h) *h = hh;
1432 }
1433#endif // WXWIN_COMPATIBILITY_2_8
1434
1435
1436
04ab8b6d
RR
1437// ----------------------------------------------------------------------------
1438// coordinate conversions and transforms
1439// ----------------------------------------------------------------------------
1440
1441wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1442{
1443 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
1444}
1445
1446wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1447{
1448 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
1449}
1450
1451wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1452{
1453 return wxRound((double)(x) / m_scaleX);
1454}
1455
1456wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1457{
1458 return wxRound((double)(y) / m_scaleY);
1459}
1460
1461wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1462{
1463 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
1464}
1465
1466wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1467{
1468 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
1469}
1470
1471wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1472{
1473 return wxRound((double)(x) * m_scaleX);
1474}
1475
1476wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1477{
1478 return wxRound((double)(y) * m_scaleY);
1479}
1480
1481void wxDCBase::ComputeScaleAndOrigin()
1482{
1483 m_scaleX = m_logicalScaleX * m_userScaleX;
1484 m_scaleY = m_logicalScaleY * m_userScaleY;
1485}
1486
1487void wxDCBase::SetMapMode( int mode )
1488{
1489 switch (mode)
1490 {
1491 case wxMM_TWIPS:
1492 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
1493 break;
1494 case wxMM_POINTS:
1495 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
1496 break;
1497 case wxMM_METRIC:
1498 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1499 break;
1500 case wxMM_LOMETRIC:
1501 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
1502 break;
1503 default:
1504 case wxMM_TEXT:
1505 SetLogicalScale( 1.0, 1.0 );
1506 break;
1507 }
1508 m_mappingMode = mode;
1509}
1510
1511void wxDCBase::SetUserScale( double x, double y )
1512{
1513 // allow negative ? -> no
1514 m_userScaleX = x;
1515 m_userScaleY = y;
1516 ComputeScaleAndOrigin();
1517}
1518
1519void wxDCBase::SetLogicalScale( double x, double y )
1520{
1521 // allow negative ?
1522 m_logicalScaleX = x;
1523 m_logicalScaleY = y;
1524 ComputeScaleAndOrigin();
1525}
1526
1527void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
1528{
1529 m_logicalOriginX = x * m_signX;
1530 m_logicalOriginY = y * m_signY;
1531 ComputeScaleAndOrigin();
1532}
1533
1534void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
1535{
1536 m_deviceOriginX = x;
1537 m_deviceOriginY = y;
1538 ComputeScaleAndOrigin();
1539}
1540
1541void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
1542{
1543 m_deviceLocalOriginX = x;
1544 m_deviceLocalOriginY = y;
1545 ComputeScaleAndOrigin();
1546}
1547
1548void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1549{
1550 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 1551 // wxWidgets 2.9: no longer override it
04ab8b6d
RR
1552 m_signX = (xLeftRight ? 1 : -1);
1553 m_signY = (yBottomUp ? -1 : 1);
1554 ComputeScaleAndOrigin();
1555}
1556
1e6feb95
VZ
1557// ----------------------------------------------------------------------------
1558// special symbols
1559// ----------------------------------------------------------------------------
1560
cd9da200
VZ
1561void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
1562 wxCoord width, wxCoord height)
1563{
1564 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1565
1566 wxCoord x2 = x1 + width,
1567 y2 = y1 + height;
1568
860a4018
VZ
1569 // the pen width is calibrated to give 3 for width == height == 10
1570 wxDCPenChanger pen((wxDC&)*this,
1571 wxPen(GetTextForeground(), (width + height + 1)/7));
cd9da200
VZ
1572
1573 // we're drawing a scaled version of wx/generic/tick.xpm here
1574 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
1575 y3 = y1 + height / 2; // y of the left tick branch
1576 DoDrawLine(x1, y3, x3, y2);
1577 DoDrawLine(x3, y2, x2, y1);
1578
1579 CalcBoundingBox(x1, y1);
1580 CalcBoundingBox(x2, y2);
1581}
1582
e3b81044
VZ
1583// ----------------------------------------------------------------------------
1584// stubs for functions not implemented in all ports
1585// ----------------------------------------------------------------------------
1586
1587bool
1588wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
1589 wxCoord dstWidth, wxCoord dstHeight,
1590 wxDC *source,
1591 wxCoord xsrc, wxCoord ysrc,
ce2fe5bc 1592 wxCoord srcWidth, wxCoord srcHeight,
e3b81044
VZ
1593 int rop,
1594 bool useMask,
1595 wxCoord xsrcMask,
1596 wxCoord ysrcMask)
1597{
ce2fe5bc
VZ
1598 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
1599 _T("invalid blit size") );
1600
1601 // emulate the stretching by modifying the DC scale
1602 double xscale = (double)srcWidth/dstWidth,
1603 yscale = (double)srcHeight/dstHeight;
1604
1605 double xscaleOld, yscaleOld;
1606 GetUserScale(&xscaleOld, &yscaleOld);
1607 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
1608
1609 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
1610 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
1611 source,
1612 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
1613
1614 SetUserScale(xscaleOld, yscaleOld);
1615
1616 return rc;
e3b81044
VZ
1617}
1618
1e6feb95
VZ
1619// ----------------------------------------------------------------------------
1620// line/polygons
1621// ----------------------------------------------------------------------------
1622
b0d7707b 1623void wxDCBase::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
dbe94982 1624{
b0d7707b 1625 unsigned int n = list->GetCount();
dbe94982
BM
1626 wxPoint *points = new wxPoint[n];
1627
b0d7707b
RR
1628 unsigned int i = 0;
1629 wxPointList::compatibility_iterator node;
1630 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1631 {
b0d7707b 1632 wxPoint *point = node->GetData();
dbe94982
BM
1633 points[i].x = point->x;
1634 points[i].y = point->y;
1635 }
1636
1637 DoDrawLines(n, points, xoffset, yoffset);
1638
1639 delete [] points;
1640}
1641
b0d7707b
RR
1642#if WXWIN_COMPATIBILITY_2_8
1643void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset )
1644{
1645 unsigned int n = list->GetCount();
1646 wxPoint *points = new wxPoint[n];
dbe94982 1647
b0d7707b 1648 unsigned int i = 0;
bc2ac5da 1649 wxObjectList::compatibility_iterator node;
b0d7707b
RR
1650 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1651 {
1652 wxPoint *point = (wxPoint*) node->GetData();
1653 points[i].x = point->x;
1654 points[i].y = point->y;
1655 }
1656
1657 DoDrawLines(n, points, xoffset, yoffset);
1658
1659 delete [] points;
1660}
1661#endif // WXWIN_COMPATIBILITY_2_8
1662
1663
1664void wxDCBase::DrawPolygon(const wxPointList *list,
72cdf4c9 1665 wxCoord xoffset, wxCoord yoffset,
dbe94982
BM
1666 int fillStyle)
1667{
b0d7707b 1668 unsigned int n = list->GetCount();
dbe94982
BM
1669 wxPoint *points = new wxPoint[n];
1670
b0d7707b
RR
1671 unsigned int i = 0;
1672 wxPointList::compatibility_iterator node;
1673 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1674 {
1675 wxPoint *point = node->GetData();
1676 points[i].x = point->x;
1677 points[i].y = point->y;
1678 }
1679
1680 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1681
1682 delete [] points;
1683}
1684
1685
1686#if WXWIN_COMPATIBILITY_2_8
1687void wxDCBase::DrawPolygon(const wxList *list,
1688 wxCoord xoffset, wxCoord yoffset,
1689 int fillStyle )
1690{
1691 unsigned int n = list->GetCount();
1692 wxPoint *points = new wxPoint[n];
1693
1694 unsigned int i = 0;
bc2ac5da 1695 wxObjectList::compatibility_iterator node;
b0d7707b 1696 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1697 {
b0d7707b 1698 wxPoint *point = (wxPoint*) node->GetData();
dbe94982
BM
1699 points[i].x = point->x;
1700 points[i].y = point->y;
1701 }
1702
1703 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1704
1705 delete [] points;
1706}
b0d7707b 1707#endif // WXWIN_COMPATIBILITY_2_8
dbe94982 1708
63b9e659
VZ
1709void
1710wxDCBase::DoDrawPolyPolygon(int n,
793db755 1711 int count[],
63b9e659
VZ
1712 wxPoint points[],
1713 wxCoord xoffset, wxCoord yoffset,
1714 int fillStyle)
1715{
1716 if ( n == 1 )
1717 {
793db755 1718 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
63b9e659
VZ
1719 return;
1720 }
1721
1722 int i, j, lastOfs;
1723 wxPoint* pts;
1724 wxPen pen;
1725
1726 for (i = j = lastOfs = 0; i < n; i++)
1727 {
1728 lastOfs = j;
793db755 1729 j += count[i];
63b9e659
VZ
1730 }
1731 pts = new wxPoint[j+n-1];
1732 for (i = 0; i < j; i++)
1733 pts[i] = points[i];
1734 for (i = 2; i <= n; i++)
1735 {
793db755 1736 lastOfs -= count[n-i];
63b9e659
VZ
1737 pts[j++] = pts[lastOfs];
1738 }
1739
1740 pen = GetPen();
1741 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
1742 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
1743 SetPen(pen);
1744 for (i = j = 0; i < n; i++)
1745 {
793db755
VZ
1746 DoDrawLines(count[i], pts+j, xoffset, yoffset);
1747 j += count[i];
63b9e659 1748 }
6db1f43b 1749 delete[] pts;
63b9e659
VZ
1750}
1751
1e6feb95
VZ
1752// ----------------------------------------------------------------------------
1753// splines
1754// ----------------------------------------------------------------------------
dbe94982 1755
88ac883a 1756#if wxUSE_SPLINES
dbe94982 1757
72cdf4c9 1758void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
dbe94982 1759{
b0d7707b 1760 wxPointList point_list;
dbe94982
BM
1761
1762 wxPoint *point1 = new wxPoint;
1763 point1->x = x1; point1->y = y1;
b0d7707b 1764 point_list.Append( point1 );
dbe94982
BM
1765
1766 wxPoint *point2 = new wxPoint;
1767 point2->x = x2; point2->y = y2;
b0d7707b 1768 point_list.Append( point2 );
dbe94982
BM
1769
1770 wxPoint *point3 = new wxPoint;
1771 point3->x = x3; point3->y = y3;
b0d7707b 1772 point_list.Append( point3 );
dbe94982
BM
1773
1774 DrawSpline(&point_list);
1775
b0d7707b 1776 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
dbe94982 1777 {
b0d7707b 1778 wxPoint *p = node->GetData();
dbe94982
BM
1779 delete p;
1780 }
1781}
1782
1783void wxDCBase::DrawSpline(int n, wxPoint points[])
1784{
b0d7707b 1785 wxPointList list;
dbe94982 1786 for (int i =0; i < n; i++)
b0d7707b 1787 list.Append( &points[i] );
dbe94982
BM
1788
1789 DrawSpline(&list);
1790}
1791
fe2e4366
VS
1792// ----------------------------------- spline code ----------------------------------------
1793
1794void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1795 double a3, double b3, double a4, double b4);
1796void wx_clear_stack();
1797int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1798 double *y3, double *x4, double *y4);
1799void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1800 double x4, double y4);
1801static bool wx_spline_add_point(double x, double y);
1802static void wx_spline_draw_point_array(wxDCBase *dc);
1803
b0d7707b 1804wxPointList wx_spline_point_list;
fe2e4366
VS
1805
1806#define half(z1, z2) ((z1+z2)/2.0)
1807#define THRESHOLD 5
1808
1809/* iterative version */
1810
1811void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1812 double b4)
1813{
1814 register double xmid, ymid;
1815 double x1, y1, x2, y2, x3, y3, x4, y4;
1816
1817 wx_clear_stack();
1818 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1819
1820 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1821 xmid = (double)half(x2, x3);
1822 ymid = (double)half(y2, y3);
1823 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1824 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1825 wx_spline_add_point( x1, y1 );
1826 wx_spline_add_point( xmid, ymid );
1827 } else {
1828 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1829 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1830 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1831 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1832 }
1833 }
1834}
1835
1836/* utilities used by spline drawing routines */
1837
1838typedef struct wx_spline_stack_struct {
1839 double x1, y1, x2, y2, x3, y3, x4, y4;
1840} Stack;
1841
1842#define SPLINE_STACK_DEPTH 20
1843static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1844static Stack *wx_stack_top;
1845static int wx_stack_count;
1846
1847void wx_clear_stack()
1848{
1849 wx_stack_top = wx_spline_stack;
1850 wx_stack_count = 0;
1851}
1852
1853void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1854{
1855 wx_stack_top->x1 = x1;
1856 wx_stack_top->y1 = y1;
1857 wx_stack_top->x2 = x2;
1858 wx_stack_top->y2 = y2;
1859 wx_stack_top->x3 = x3;
1860 wx_stack_top->y3 = y3;
1861 wx_stack_top->x4 = x4;
1862 wx_stack_top->y4 = y4;
1863 wx_stack_top++;
1864 wx_stack_count++;
1865}
1866
1867int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1868 double *x3, double *y3, double *x4, double *y4)
1869{
1870 if (wx_stack_count == 0)
1871 return (0);
1872 wx_stack_top--;
1873 wx_stack_count--;
1874 *x1 = wx_stack_top->x1;
1875 *y1 = wx_stack_top->y1;
1876 *x2 = wx_stack_top->x2;
1877 *y2 = wx_stack_top->y2;
1878 *x3 = wx_stack_top->x3;
1879 *y3 = wx_stack_top->y3;
1880 *x4 = wx_stack_top->x4;
1881 *y4 = wx_stack_top->y4;
1882 return (1);
1883}
1884
1885static bool wx_spline_add_point(double x, double y)
1886{
b0d7707b
RR
1887 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
1888 wx_spline_point_list.Append( point );
1889 return true;
fe2e4366
VS
1890}
1891
1892static void wx_spline_draw_point_array(wxDCBase *dc)
1893{
b0d7707b
RR
1894 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1895 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
1896 while (node)
1897 {
1898 wxPoint *point = node->GetData();
1899 delete point;
1900 wx_spline_point_list.Erase(node);
1901 node = wx_spline_point_list.GetFirst();
1902 }
fe2e4366
VS
1903}
1904
b0d7707b
RR
1905#if WXWIN_COMPATIBILITY_2_8
1906void wxDCBase::DrawSpline(const wxList *points)
1907{
1908 wxPointList list;
bc2ac5da 1909 wxObjectList::compatibility_iterator node = points->GetFirst();
b0d7707b
RR
1910 while (node)
1911 {
1912 list.Append( (wxPoint*) node->GetData() );
1913 node = node->GetNext();
1914 }
1915 DoDrawSpline( &list );
1916}
1917#endif // WXWIN_COMPATIBILITY_2_8
1918
1919void wxDCBase::DoDrawSpline( const wxPointList *points )
fe2e4366
VS
1920{
1921 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1922
1923 wxPoint *p;
1924 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1925 double x1, y1, x2, y2;
1926
b0d7707b 1927 wxPointList::compatibility_iterator node = points->GetFirst();
ef419e3b 1928 if (!node)
410bb8c1
RD
1929 // empty list
1930 return;
e0d31471 1931
b0d7707b 1932 p = node->GetData();
fe2e4366
VS
1933
1934 x1 = p->x;
1935 y1 = p->y;
1936
b1d4dd7a 1937 node = node->GetNext();
b0d7707b 1938 p = node->GetData();
fe2e4366
VS
1939
1940 x2 = p->x;
1941 y2 = p->y;
1942 cx1 = (double)((x1 + x2) / 2);
1943 cy1 = (double)((y1 + y2) / 2);
1944 cx2 = (double)((cx1 + x2) / 2);
1945 cy2 = (double)((cy1 + y2) / 2);
1946
1947 wx_spline_add_point(x1, y1);
1948
28b4db7f
VZ
1949 while ((node = node->GetNext())
1950#if !wxUSE_STL
1951 != NULL
1952#endif // !wxUSE_STL
1953 )
fe2e4366 1954 {
b0d7707b 1955 p = node->GetData();
fe2e4366
VS
1956 x1 = x2;
1957 y1 = y2;
1958 x2 = p->x;
1959 y2 = p->y;
1960 cx4 = (double)(x1 + x2) / 2;
1961 cy4 = (double)(y1 + y2) / 2;
1962 cx3 = (double)(x1 + cx4) / 2;
1963 cy3 = (double)(y1 + cy4) / 2;
1964
1965 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1966
1967 cx1 = cx4;
1968 cy1 = cy4;
1969 cx2 = (double)(cx1 + x2) / 2;
1970 cy2 = (double)(cy1 + y2) / 2;
1971 }
1972
1973 wx_spline_add_point( cx1, cy1 );
1974 wx_spline_add_point( x2, y2 );
1975
1976 wx_spline_draw_point_array( this );
1977}
1978
88ac883a 1979#endif // wxUSE_SPLINES
1e6feb95 1980
0919e93e
RD
1981// ----------------------------------------------------------------------------
1982// Partial Text Extents
1983// ----------------------------------------------------------------------------
1984
1985
174ee1b3 1986// Each element of the widths array will be the width of the string up to and
3103e8a9 1987// including the corresponding character in text. This is the generic
0919e93e 1988// implementation, the port-specific classes should do this with native APIs
174ee1b3
RD
1989// if available and if faster. Note: pango_layout_index_to_pos is much slower
1990// than calling GetTextExtent!!
1991
06fe86b7 1992#define FWC_SIZE 256
174ee1b3
RD
1993
1994class FontWidthCache
1995{
1996public:
1997 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
1998 ~FontWidthCache() { delete []m_widths; }
2aaa050c
VZ
1999
2000 void Reset()
2001 {
2002 if (!m_widths)
2003 m_widths = new int[FWC_SIZE];
2004
2005 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
2006 }
2007
174ee1b3
RD
2008 wxFont m_font;
2009 double m_scaleX;
2010 int *m_widths;
2011};
2012
2013static FontWidthCache s_fontWidthCache;
0919e93e
RD
2014
2015bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2016{
2017 int totalWidth = 0;
0919e93e 2018
18680f86 2019 const size_t len = text.length();
0919e93e 2020 widths.Empty();
174ee1b3 2021 widths.Add(0, len);
2aaa050c 2022
174ee1b3 2023 // reset the cache if font or horizontal scale have changed
c77a6796
VZ
2024 if ( !s_fontWidthCache.m_widths ||
2025 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
2026 (s_fontWidthCache.m_font != GetFont()) )
174ee1b3
RD
2027 {
2028 s_fontWidthCache.Reset();
2029 s_fontWidthCache.m_font = GetFont();
2030 s_fontWidthCache.m_scaleX = m_scaleX;
2031 }
2032
0919e93e
RD
2033 // Calculate the position of each character based on the widths of
2034 // the previous characters
c77a6796
VZ
2035 int w, h;
2036 for ( size_t i = 0; i < len; i++ )
174ee1b3
RD
2037 {
2038 const wxChar c = text[i];
2039 unsigned int c_int = (unsigned int)c;
2040
2aaa050c 2041 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
174ee1b3
RD
2042 {
2043 w = s_fontWidthCache.m_widths[c_int];
2044 }
2aaa050c 2045 else
174ee1b3
RD
2046 {
2047 GetTextExtent(c, &w, &h);
2048 if (c_int < FWC_SIZE)
2049 s_fontWidthCache.m_widths[c_int] = w;
2050 }
2051
0919e93e
RD
2052 totalWidth += w;
2053 widths[i] = totalWidth;
2054 }
2aaa050c 2055
0919e93e
RD
2056 return true;
2057}
2058
2059
1e6feb95
VZ
2060// ----------------------------------------------------------------------------
2061// enhanced text drawing
2062// ----------------------------------------------------------------------------
2063
2064void wxDCBase::GetMultiLineTextExtent(const wxString& text,
2065 wxCoord *x,
2066 wxCoord *y,
2067 wxCoord *h,
c94f845b 2068 const wxFont *font) const
1e6feb95 2069{
c7aaa64f
VS
2070 wxCoord widthTextMax = 0, widthLine,
2071 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
1e6feb95
VZ
2072
2073 wxString curLine;
86501081 2074 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2075 {
86501081 2076 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
2077 {
2078 if ( curLine.empty() )
2079 {
2080 // we can't use GetTextExtent - it will return 0 for both width
2081 // and height and an empty line should count in height
2082 // calculation
2083
2084 // assume that this line has the same height as the previous
2085 // one
2086 if ( !heightLineDefault )
2087 heightLineDefault = heightLine;
2088
2089 if ( !heightLineDefault )
2090 {
2091 // but we don't know it yet - choose something reasonable
2092 GetTextExtent(_T("W"), NULL, &heightLineDefault,
2093 NULL, NULL, font);
2094 }
2095
2096 heightTextTotal += heightLineDefault;
2097 }
2098 else
2099 {
2100 GetTextExtent(curLine, &widthLine, &heightLine,
2101 NULL, NULL, font);
2102 if ( widthLine > widthTextMax )
2103 widthTextMax = widthLine;
2104 heightTextTotal += heightLine;
2105 }
2106
86501081 2107 if ( pc == text.end() )
1e6feb95 2108 {
86501081 2109 break;
1e6feb95 2110 }
86501081 2111 else // '\n'
1e6feb95 2112 {
86501081 2113 curLine.clear();
1e6feb95
VZ
2114 }
2115 }
2116 else
2117 {
2118 curLine += *pc;
2119 }
2120 }
2121
2122 if ( x )
2123 *x = widthTextMax;
2124 if ( y )
2125 *y = heightTextTotal;
2126 if ( h )
2127 *h = heightLine;
2128}
2129
2130void wxDCBase::DrawLabel(const wxString& text,
2131 const wxBitmap& bitmap,
2132 const wxRect& rect,
2133 int alignment,
2134 int indexAccel,
2135 wxRect *rectBounding)
2136{
2137 // find the text position
2138 wxCoord widthText, heightText, heightLine;
2139 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
2140
2141 wxCoord width, height;
2142 if ( bitmap.Ok() )
2143 {
2144 width = widthText + bitmap.GetWidth();
2145 height = bitmap.GetHeight();
2146 }
2147 else // no bitmap
2148 {
2149 width = widthText;
2150 height = heightText;
2151 }
2152
2153 wxCoord x, y;
2154 if ( alignment & wxALIGN_RIGHT )
2155 {
2156 x = rect.GetRight() - width;
2157 }
2158 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2159 {
2160 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
2161 }
2162 else // alignment & wxALIGN_LEFT
2163 {
2164 x = rect.GetLeft();
2165 }
2166
2167 if ( alignment & wxALIGN_BOTTOM )
2168 {
2169 y = rect.GetBottom() - height;
2170 }
2171 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
2172 {
2173 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
2174 }
2175 else // alignment & wxALIGN_TOP
2176 {
2177 y = rect.GetTop();
2178 }
2179
2180 // draw the bitmap first
2181 wxCoord x0 = x,
2182 y0 = y,
2183 width0 = width;
2184 if ( bitmap.Ok() )
2185 {
68379eaf 2186 DrawBitmap(bitmap, x, y, true /* use mask */);
1e6feb95
VZ
2187
2188 wxCoord offset = bitmap.GetWidth() + 4;
2189 x += offset;
2190 width -= offset;
2191
2192 y += (height - heightText) / 2;
2193 }
2194
2195 // we will draw the underscore under the accel char later
2196 wxCoord startUnderscore = 0,
2197 endUnderscore = 0,
2198 yUnderscore = 0;
2199
2200 // split the string into lines and draw each of them separately
2201 wxString curLine;
c9f78968 2202 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2203 {
f5595af6 2204 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
2205 {
2206 int xRealStart = x; // init it here to avoid compielr warnings
2207
2208 if ( !curLine.empty() )
2209 {
2210 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2211 // wxALIGN_LEFT is 0
2212 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
2213 {
2214 wxCoord widthLine;
2215 GetTextExtent(curLine, &widthLine, NULL);
2216
2217 if ( alignment & wxALIGN_RIGHT )
2218 {
2219 xRealStart += width - widthLine;
2220 }
2221 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2222 {
2223 xRealStart += (width - widthLine) / 2;
2224 }
2225 }
2226 //else: left aligned, nothing to do
2227
2228 DrawText(curLine, xRealStart, y);
2229 }
2230
2231 y += heightLine;
2232
2233 // do we have underscore in this line? we can check yUnderscore
2234 // because it is set below to just y + heightLine if we do
2235 if ( y == yUnderscore )
2236 {
2237 // adjust the horz positions to account for the shift
2238 startUnderscore += xRealStart;
2239 endUnderscore += xRealStart;
2240 }
2241
c9f78968 2242 if ( pc == text.end() )
1e6feb95
VZ
2243 break;
2244
2245 curLine.clear();
2246 }
2247 else // not end of line
2248 {
9daaea28 2249 if ( pc - text.begin() == indexAccel )
1e6feb95
VZ
2250 {
2251 // remeber to draw underscore here
2252 GetTextExtent(curLine, &startUnderscore, NULL);
2253 curLine += *pc;
2254 GetTextExtent(curLine, &endUnderscore, NULL);
2255
2256 yUnderscore = y + heightLine;
2257 }
2258 else
2259 {
2260 curLine += *pc;
2261 }
2262 }
2263 }
2264
2265 // draw the underscore if found
2266 if ( startUnderscore != endUnderscore )
2267 {
2268 // it should be of the same colour as text
2269 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
2270
2271 yUnderscore--;
2272
2273 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
2274 }
2275
2276 // return bounding rect if requested
2277 if ( rectBounding )
2278 {
2279 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
2280 }
2281
2282 CalcBoundingBox(x0, y0);
2283 CalcBoundingBox(x0 + width0, y0 + height);
2284}
12bdd77c 2285
213ad8e7
VZ
2286
2287void wxDCBase::DoGradientFillLinear(const wxRect& rect,
2288 const wxColour& initialColour,
2289 const wxColour& destColour,
2290 wxDirection nDirection)
2291{
2292 // save old pen
2293 wxPen oldPen = m_pen;
a983a3cf 2294 wxBrush oldBrush = m_brush;
213ad8e7 2295
6dff0e29
BW
2296 wxUint8 nR1 = initialColour.Red();
2297 wxUint8 nG1 = initialColour.Green();
2298 wxUint8 nB1 = initialColour.Blue();
2299 wxUint8 nR2 = destColour.Red();
2300 wxUint8 nG2 = destColour.Green();
2301 wxUint8 nB2 = destColour.Blue();
213ad8e7
VZ
2302 wxUint8 nR, nG, nB;
2303
2304 if ( nDirection == wxEAST || nDirection == wxWEST )
2305 {
2306 wxInt32 x = rect.GetWidth();
2307 wxInt32 w = x; // width of area to shade
2308 wxInt32 xDelta = w/256; // height of one shade bend
2309 if (xDelta < 1)
2310 xDelta = 1;
2311
2312 while (x >= xDelta)
2313 {
2314 x -= xDelta;
2315 if (nR1 > nR2)
2316 nR = nR1 - (nR1-nR2)*(w-x)/w;
2317 else
2318 nR = nR1 + (nR2-nR1)*(w-x)/w;
2319
2320 if (nG1 > nG2)
2321 nG = nG1 - (nG1-nG2)*(w-x)/w;
2322 else
2323 nG = nG1 + (nG2-nG1)*(w-x)/w;
2324
2325 if (nB1 > nB2)
2326 nB = nB1 - (nB1-nB2)*(w-x)/w;
2327 else
2328 nB = nB1 + (nB2-nB1)*(w-x)/w;
2329
e3b81044 2330 wxColour colour(nR,nG,nB);
1dab6da9
BW
2331 SetPen(wxPen(colour, 1, wxSOLID));
2332 SetBrush(wxBrush(colour));
213ad8e7 2333 if(nDirection == wxEAST)
5f77ee3b 2334 DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
213ad8e7
VZ
2335 xDelta, rect.GetHeight());
2336 else //nDirection == wxWEST
1dab6da9 2337 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
213ad8e7
VZ
2338 xDelta, rect.GetHeight());
2339 }
2340 }
2341 else // nDirection == wxNORTH || nDirection == wxSOUTH
2342 {
2343 wxInt32 y = rect.GetHeight();
2344 wxInt32 w = y; // height of area to shade
2345 wxInt32 yDelta = w/255; // height of one shade bend
2346 if (yDelta < 1)
2347 yDelta = 1;
2348
2349 while (y > 0)
2350 {
2351 y -= yDelta;
2352 if (nR1 > nR2)
2353 nR = nR1 - (nR1-nR2)*(w-y)/w;
2354 else
2355 nR = nR1 + (nR2-nR1)*(w-y)/w;
2356
2357 if (nG1 > nG2)
2358 nG = nG1 - (nG1-nG2)*(w-y)/w;
2359 else
2360 nG = nG1 + (nG2-nG1)*(w-y)/w;
2361
2362 if (nB1 > nB2)
2363 nB = nB1 - (nB1-nB2)*(w-y)/w;
2364 else
2365 nB = nB1 + (nB2-nB1)*(w-y)/w;
2366
e3b81044 2367 wxColour colour(nR,nG,nB);
1dab6da9
BW
2368 SetPen(wxPen(colour, 1, wxSOLID));
2369 SetBrush(wxBrush(colour));
213ad8e7
VZ
2370 if(nDirection == wxNORTH)
2371 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
2372 rect.GetWidth(), yDelta);
2373 else //nDirection == wxSOUTH
5f77ee3b 2374 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
213ad8e7
VZ
2375 rect.GetWidth(), yDelta);
2376 }
2377 }
2378
2379 SetPen(oldPen);
a983a3cf 2380 SetBrush(oldBrush);
213ad8e7
VZ
2381}
2382
fb63a242 2383void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
213ad8e7
VZ
2384 const wxColour& initialColour,
2385 const wxColour& destColour,
2386 const wxPoint& circleCenter)
2387{
2388 //save the old pen color
2389 wxColour oldPenColour = m_pen.GetColour();
2390
2391 wxUint8 nR1 = destColour.Red();
2392 wxUint8 nG1 = destColour.Green();
2393 wxUint8 nB1 = destColour.Blue();
2394 wxUint8 nR2 = initialColour.Red();
2395 wxUint8 nG2 = initialColour.Green();
2396 wxUint8 nB2 = initialColour.Blue();
2397 wxUint8 nR, nG, nB;
2398
2399
213ad8e7
VZ
2400 //Radius
2401 wxInt32 cx = rect.GetWidth() / 2;
2402 wxInt32 cy = rect.GetHeight() / 2;
2403 wxInt32 nRadius;
2404 if (cx < cy)
2405 nRadius = cx;
2406 else
2407 nRadius = cy;
2408
2409 //Offset of circle
2410 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
2411 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
2412
e35d07b9 2413 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
213ad8e7 2414 {
e35d07b9 2415 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
213ad8e7
VZ
2416 {
2417 //get color difference
e35d07b9
VZ
2418 wxInt32 nGradient = ((nRadius -
2419 (wxInt32)sqrt(
2420 pow((double)(x - cx - nCircleOffX), 2) +
2421 pow((double)(y - cy - nCircleOffY), 2)
2422 )) * 100) / nRadius;
213ad8e7
VZ
2423
2424 //normalize Gradient
2425 if (nGradient < 0 )
2426 nGradient = 0;
2427
2428 //get dest colors
06052f3f
WS
2429 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2430 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2431 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
213ad8e7
VZ
2432
2433 //set the pixel
2434 m_pen.SetColour(wxColour(nR,nG,nB));
2435 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
2436 }
2437 }
2438 //return old pen color
2439 m_pen.SetColour(oldPenColour);
2440}
2441
12bdd77c 2442/*
77ffb593 2443Notes for wxWidgets DrawEllipticArcRot(...)
12bdd77c
JS
2444
2445wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2446It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2447which are also new.
2448
2449All methods are generic, so they can be implemented in wxDCBase.
2450DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2451methods like (WinCE) wxDC::DoDrawArc(...).
2452
2453CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2aaa050c 2454of an elliptic arc. The algorithm is pixel-based: In every row (in flat
12bdd77c
JS
2455parts) or every column (in steep parts) only one pixel is calculated.
2456Trigonometric calculation (sin, cos, tan, atan) is only done if the
2aaa050c 2457starting angle is not equal to the ending angle. The calculation of the
12bdd77c
JS
2458pixels is done using simple arithmetic only and should perform not too
2459bad even on devices without floating point processor. I didn't test this yet.
2460
2461Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2aaa050c 2462For instance: an ellipse rotated 180 degrees is drawn
12bdd77c
JS
2463slightly different from the original.
2464
2aaa050c
VZ
2465The points are then moved to an array and used to draw a polyline and/or polygon
2466(with center added, the pie).
12bdd77c
JS
2467The result looks quite similar to the native ellipse, only e few pixels differ.
2468
2469The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2470slower as DrawEllipse(...), which calls the native API.
2471An rotated ellipse outside the clipping region takes nearly the same time,
2472while an native ellipse outside takes nearly no time to draw.
2473
2aaa050c 2474If you draw an arc with this new method, you will see the starting and ending angles
12bdd77c
JS
2475are calculated properly.
2476If you use DrawEllipticArc(...), you will see they are only correct for circles
2477and not properly calculated for ellipses.
2478
2479Peter Lenhard
2480p.lenhard@t-online.de
2481*/
2482
2483#ifdef __WXWINCE__
2aaa050c
VZ
2484void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2485 wxCoord w, wxCoord h,
12bdd77c
JS
2486 double sa, double ea, double angle )
2487{
b0d7707b 2488 wxPointList list;
12bdd77c
JS
2489
2490 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
2491 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
2492
2493 // Add center (for polygon/pie)
b0d7707b 2494 list.Append( new wxPoint( x+w/2, y+h/2 ) );
12bdd77c
JS
2495
2496 // copy list into array and delete list elements
2c3ebf8b 2497 int n = list.GetCount();
12bdd77c
JS
2498 wxPoint *points = new wxPoint[n];
2499 int i = 0;
b0d7707b 2500 wxPointList::compatibility_iterator node;
2c3ebf8b 2501 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
12bdd77c 2502 {
b0d7707b 2503 wxPoint *point = node->GetData();
12bdd77c
JS
2504 points[i].x = point->x;
2505 points[i].y = point->y;
2506 delete point;
2507 }
2508
2509 // first draw the pie without pen, if necessary
63b9e659 2510 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
2511 {
2512 wxPen tempPen( GetPen() );
2513 SetPen( *wxTRANSPARENT_PEN );
2514 DoDrawPolygon( n, points, 0, 0 );
2515 SetPen( tempPen );
2516 }
2517
2518 // then draw the arc without brush, if necessary
63b9e659 2519 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
2520 {
2521 // without center
2522 DoDrawLines( n-1, points, 0, 0 );
2523 }
2524
2525 delete [] points;
2526
2527} // DrawEllipticArcRot
2528
b0d7707b 2529void wxDCBase::Rotate( wxPointList* points, double angle, wxPoint center )
12bdd77c
JS
2530{
2531 if( angle != 0.0 )
2532 {
e0d31471 2533 double pi(M_PI);
12bdd77c
JS
2534 double dSinA = -sin(angle*2.0*pi/360.0);
2535 double dCosA = cos(angle*2.0*pi/360.0);
b0d7707b
RR
2536 wxPointList::compatibility_iterator node;
2537 for ( node = points->GetFirst(); node; node = node->GetNext() )
12bdd77c 2538 {
b0d7707b 2539 wxPoint* point = node->GetData();
2aaa050c 2540
12bdd77c
JS
2541 // transform coordinates, if necessary
2542 if( center.x ) point->x -= center.x;
2543 if( center.y ) point->y -= center.y;
2544
2545 // calculate rotation, rounding simply by implicit cast to integer
2546 int xTemp = point->x * dCosA - point->y * dSinA;
2547 point->y = point->x * dSinA + point->y * dCosA;
2548 point->x = xTemp;
2549
2550 // back transform coordinates, if necessary
2551 if( center.x ) point->x += center.x;
2552 if( center.y ) point->y += center.y;
2553 }
2554 }
2555}
2556
b0d7707b 2557void wxDCBase::CalculateEllipticPoints( wxPointList* points,
2aaa050c
VZ
2558 wxCoord xStart, wxCoord yStart,
2559 wxCoord w, wxCoord h,
12bdd77c
JS
2560 double sa, double ea )
2561{
e0d31471 2562 double pi = M_PI;
12bdd77c
JS
2563 double sar = 0;
2564 double ear = 0;
2565 int xsa = 0;
2566 int ysa = 0;
2567 int xea = 0;
2568 int yea = 0;
2569 int sq = 0;
2570 int eq = 0;
2571 bool bUseAngles = false;
2572 if( w<0 ) w = -w;
2573 if( h<0 ) h = -h;
2574 // half-axes
2575 wxCoord a = w/2;
2576 wxCoord b = h/2;
2577 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2578 int decrX = 0;
2aaa050c 2579 if( 2*a == w ) decrX = 1;
12bdd77c 2580 int decrY = 0;
2aaa050c 2581 if( 2*b == h ) decrY = 1;
12bdd77c
JS
2582 // center
2583 wxCoord xCenter = xStart + a;
2584 wxCoord yCenter = yStart + b;
2585 // calculate data for start and end, if necessary
2586 if( sa != ea )
2587 {
2588 bUseAngles = true;
2589 // normalisation of angles
2590 while( sa<0 ) sa += 360;
2591 while( ea<0 ) ea += 360;
2592 while( sa>=360 ) sa -= 360;
2593 while( ea>=360 ) ea -= 360;
2594 // calculate quadrant numbers
2595 if( sa > 270 ) sq = 3;
2596 else if( sa > 180 ) sq = 2;
2597 else if( sa > 90 ) sq = 1;
2598 if( ea > 270 ) eq = 3;
2599 else if( ea > 180 ) eq = 2;
2600 else if( ea > 90 ) eq = 1;
2601 sar = sa * pi / 180.0;
2602 ear = ea * pi / 180.0;
2603 // correct angle circle -> ellipse
2604 sar = atan( -a/(double)b * tan( sar ) );
2aaa050c 2605 if ( sq == 1 || sq == 2 ) sar += pi;
12bdd77c
JS
2606 ear = atan( -a/(double)b * tan( ear ) );
2607 if ( eq == 1 || eq == 2 ) ear += pi;
2608 // coordinates of points
2609 xsa = xCenter + a * cos( sar );
2610 if( sq == 0 || sq == 3 ) xsa -= decrX;
2611 ysa = yCenter + b * sin( sar );
2612 if( sq == 2 || sq == 3 ) ysa -= decrY;
2613 xea = xCenter + a * cos( ear );
2614 if( eq == 0 || eq == 3 ) xea -= decrX;
2615 yea = yCenter + b * sin( ear );
2616 if( eq == 2 || eq == 3 ) yea -= decrY;
2617 } // if iUseAngles
2618 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2619 double c1 = b * b;
2620 double c2 = 2.0 / w;
2621 c2 *= c2;
2622 c2 *= c1;
2623 wxCoord x = 0;
2624 wxCoord y = b;
2625 long x2 = 1;
2626 long y2 = y*y;
2627 long y2_old = 0;
2628 long y_old = 0;
2629 // Lists for quadrant 1 to 4
b0d7707b 2630 wxPointList pointsarray[4];
12bdd77c
JS
2631 // Calculate points for first quadrant and set in all quadrants
2632 for( x = 0; x <= a; ++x )
2633 {
2634 x2 = x2+x+x-1;
2635 y2_old = y2;
2636 y_old = y;
2637 bool bNewPoint = false;
2638 while( y2 > c1 - c2 * x2 && y > 0 )
2639 {
2640 bNewPoint = true;
2641 y2 = y2-y-y+1;
2642 --y;
2643 }
2aaa050c 2644 // old y now to big: set point with old y, old x
12bdd77c
JS
2645 if( bNewPoint && x>1)
2646 {
2647 int x1 = x - 1;
2648 // remove points on the same line
b0d7707b
RR
2649 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
2650 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
2651 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
2652 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
12bdd77c
JS
2653 } // set point
2654 } // calculate point
2aaa050c 2655
12bdd77c 2656 // Starting and/or ending points for the quadrants, first quadrant gets both.
b0d7707b
RR
2657 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
2658 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
2659 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
2660 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
2661 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
12bdd77c
JS
2662
2663 // copy quadrants in original list
2664 if( bUseAngles )
2665 {
2666 // Copy the right part of the points in the lists
2667 // and delete the wxPoints, because they do not leave this method.
b0d7707b 2668 points->Append( new wxPoint( xsa, ysa ) );
12bdd77c
JS
2669 int q = sq;
2670 bool bStarted = false;
2671 bool bReady = false;
2672 bool bForceTurn = ( sq == eq && sa > ea );
2673 while( !bReady )
2674 {
b0d7707b
RR
2675 wxPointList::compatibility_iterator node;
2676 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c
JS
2677 {
2678 // once: go to starting point in start quadrant
2679 if( !bStarted &&
2aaa050c 2680 (
b0d7707b 2681 node->GetData()->x < xsa+1 && q <= 1
2aaa050c 2682 ||
b0d7707b 2683 node->GetData()->x > xsa-1 && q >= 2
12bdd77c 2684 )
2aaa050c 2685 )
12bdd77c
JS
2686 {
2687 bStarted = true;
2688 }
2689
2690 // copy point, if not at ending point
2691 if( bStarted )
2692 {
2693 if( q != eq || bForceTurn
2694 ||
2c3ebf8b 2695 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2aaa050c 2696 ||
2c3ebf8b 2697 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
12bdd77c
JS
2698 )
2699 {
2700 // copy point
b0d7707b
RR
2701 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
2702 points->Append( pPoint );
12bdd77c 2703 }
b0d7707b 2704 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
12bdd77c 2705 {
2aaa050c 2706 bReady = true;
12bdd77c
JS
2707 }
2708 }
2709 } // for node
2710 ++q;
2711 if( q > 3 ) q = 0;
2712 bForceTurn = false;
2713 bStarted = true;
2714 } // while not bReady
b0d7707b 2715 points->Append( new wxPoint( xea, yea ) );
12bdd77c
JS
2716
2717 // delete points
2718 for( q = 0; q < 4; ++q )
2719 {
b0d7707b
RR
2720 wxPointList::compatibility_iterator node;
2721 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c 2722 {
b0d7707b 2723 wxPoint *p = node->GetData();
12bdd77c
JS
2724 delete p;
2725 }
2aaa050c 2726 }
12bdd77c
JS
2727 }
2728 else
2729 {
b0d7707b 2730 wxPointList::compatibility_iterator node;
12bdd77c 2731 // copy whole ellipse, wxPoints will be deleted outside
2c3ebf8b 2732 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
12bdd77c 2733 {
b0d7707b 2734 wxPoint *p = node->GetData();
12bdd77c
JS
2735 points->Append( p );
2736 }
2c3ebf8b 2737 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
12bdd77c 2738 {
b0d7707b 2739 wxPoint *p = node->GetData();
12bdd77c
JS
2740 points->Append( p );
2741 }
2c3ebf8b 2742 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
12bdd77c 2743 {
b0d7707b 2744 wxPoint *p = node->GetData();
12bdd77c
JS
2745 points->Append( p );
2746 }
2c3ebf8b 2747 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
12bdd77c 2748 {
b0d7707b 2749 wxPoint *p = node->GetData();
12bdd77c
JS
2750 points->Append( p );
2751 }
2752 } // not iUseAngles
2753} // CalculateEllipticPoints
2754
e3b81044 2755#endif // __WXWINCE__
2970ae54
RR
2756
2757#endif // wxUSE_NEW_DC