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