]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
Better compatibility with old files when creating an image cache
[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"
4f37154e 32#include "wx/prntbase.h"
1d8cdcf2 33#include "wx/scopeguard.h"
18680f86
WS
34
35#ifndef WX_PRECOMP
36 #include "wx/math.h"
f2498c4e 37 #include "wx/module.h"
3fb39fd5 38 #include "wx/window.h"
18680f86 39#endif
dbe94982 40
8cd79b7a
VZ
41#include "wx/private/textmeasure.h"
42
888dde65 43#ifdef __WXMSW__
f2498c4e
VZ
44 #include "wx/msw/dcclient.h"
45 #include "wx/msw/dcmemory.h"
46 #include "wx/msw/dcscreen.h"
888dde65 47#endif
2970ae54 48
9dc44eff
PC
49#ifdef __WXGTK3__
50 #include "wx/gtk/dc.h"
51#elif defined __WXGTK20__
f2498c4e
VZ
52 #include "wx/gtk/dcclient.h"
53 #include "wx/gtk/dcmemory.h"
54 #include "wx/gtk/dcscreen.h"
10d30222
VZ
55#elif defined(__WXGTK__)
56 #include "wx/gtk1/dcclient.h"
57 #include "wx/gtk1/dcmemory.h"
58 #include "wx/gtk1/dcscreen.h"
888dde65
RR
59#endif
60
61#ifdef __WXMAC__
c933e267
SC
62 #include "wx/osx/dcclient.h"
63 #include "wx/osx/dcmemory.h"
64 #include "wx/osx/dcscreen.h"
888dde65 65#endif
2970ae54 66
2c24e7ad
SN
67#ifdef __WXPM__
68 #include "wx/os2/dcclient.h"
69 #include "wx/os2/dcmemory.h"
70 #include "wx/os2/dcscreen.h"
71#endif
72
938156b2
DE
73#ifdef __WXCOCOA__
74 #include "wx/cocoa/dcclient.h"
75 #include "wx/cocoa/dcmemory.h"
76 #include "wx/cocoa/dcscreen.h"
77#endif
78
fce127d7
VZ
79#ifdef __WXMOTIF__
80 #include "wx/motif/dcclient.h"
81 #include "wx/motif/dcmemory.h"
82 #include "wx/motif/dcscreen.h"
83#endif
84
e6514d0e 85#ifdef __WXX11__
f2498c4e
VZ
86 #include "wx/x11/dcclient.h"
87 #include "wx/x11/dcmemory.h"
88 #include "wx/x11/dcscreen.h"
e6514d0e
RR
89#endif
90
4a624f6e
VZ
91#ifdef __WXDFB__
92 #include "wx/dfb/dcclient.h"
93 #include "wx/dfb/dcmemory.h"
94 #include "wx/dfb/dcscreen.h"
95#endif
96
2970ae54
RR
97//----------------------------------------------------------------------------
98// wxDCFactory
99//----------------------------------------------------------------------------
100
101wxDCFactory *wxDCFactory::m_factory = NULL;
102
f2498c4e 103void wxDCFactory::Set(wxDCFactory *factory)
2970ae54 104{
f2498c4e 105 delete m_factory;
2970ae54 106
f2498c4e 107 m_factory = factory;
2970ae54
RR
108}
109
f0875501 110wxDCFactory *wxDCFactory::Get()
2970ae54 111{
f2498c4e
VZ
112 if ( !m_factory )
113 m_factory = new wxNativeDCFactory;
2970ae54 114
f2498c4e 115 return m_factory;
2970ae54
RR
116}
117
f2498c4e
VZ
118class wxDCFactoryCleanupModule : public wxModule
119{
120public:
121 virtual bool OnInit() { return true; }
122 virtual void OnExit() { wxDCFactory::Set(NULL); }
123
124private:
125 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule)
126};
127
128IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule)
129
2970ae54
RR
130//-----------------------------------------------------------------------------
131// wxNativeDCFactory
132//-----------------------------------------------------------------------------
133
888dde65 134wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
f0875501 135{
edc51344
VZ
136 wxDCImpl * const impl = new wxWindowDCImpl( owner, window );
137 impl->InheritAttributes(window);
138 return impl;
2970ae54
RR
139}
140
888dde65
RR
141wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
142{
edc51344
VZ
143 wxDCImpl * const impl = new wxClientDCImpl( owner, window );
144 impl->InheritAttributes(window);
145 return impl;
2970ae54
RR
146}
147
888dde65
RR
148wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
149{
edc51344
VZ
150 wxDCImpl * const impl = new wxPaintDCImpl( owner, window );
151 impl->InheritAttributes(window);
152 return impl;
2970ae54
RR
153}
154
888dde65
RR
155wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
156{
157 return new wxMemoryDCImpl( owner );
2970ae54
RR
158}
159
2a02f84b 160wxDCImpl* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC *owner, wxBitmap& bitmap)
888dde65 161{
2a02f84b
VZ
162 // the bitmap may be modified when it's selected into a memory DC so make
163 // sure changing this bitmap doesn't affect any other shallow copies of it
164 // (see wxMemoryDC::SelectObject())
165 //
166 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
167 // method because this should be rarely needed and easy to work around by
168 // using the default ctor and calling SelectObjectAsSource itself
169 if ( bitmap.IsOk() )
170 bitmap.UnShare();
171
172 return new wxMemoryDCImpl(owner, bitmap);
2970ae54
RR
173}
174
888dde65
RR
175wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
176{
177 return new wxMemoryDCImpl( owner, dc );
ab171e95
RR
178}
179
888dde65
RR
180wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
181{
182 return new wxScreenDCImpl( owner );
2970ae54
RR
183}
184
6b4f4d47 185#if wxUSE_PRINTING_ARCHITECTURE
888dde65 186wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
c8ddadff 187{
4f37154e 188 wxPrintFactory *factory = wxPrintFactory::GetFactory();
888dde65 189 return factory->CreatePrinterDCImpl( owner, data );
c8ddadff 190}
6b4f4d47 191#endif
c8ddadff 192
2970ae54
RR
193//-----------------------------------------------------------------------------
194// wxWindowDC
195//-----------------------------------------------------------------------------
196
f0875501 197IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC)
2970ae54 198
f0875501
VZ
199wxWindowDC::wxWindowDC(wxWindow *win)
200 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win))
2970ae54 201{
2970ae54
RR
202}
203
204//-----------------------------------------------------------------------------
205// wxClientDC
206//-----------------------------------------------------------------------------
207
f0875501 208IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC)
2970ae54 209
f0875501
VZ
210wxClientDC::wxClientDC(wxWindow *win)
211 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win))
2970ae54 212{
2970ae54
RR
213}
214
2970ae54
RR
215//-----------------------------------------------------------------------------
216// wxMemoryDC
217//-----------------------------------------------------------------------------
218
219IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
220
221wxMemoryDC::wxMemoryDC()
f0875501 222 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
2970ae54 223{
2970ae54
RR
224}
225
f0875501
VZ
226wxMemoryDC::wxMemoryDC(wxBitmap& bitmap)
227 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap))
2970ae54 228{
2970ae54
RR
229}
230
f0875501
VZ
231wxMemoryDC::wxMemoryDC(wxDC *dc)
232 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc))
2970ae54 233{
ab171e95
RR
234}
235
236void wxMemoryDC::SelectObject(wxBitmap& bmp)
237{
71f5b0e7
VZ
238 if ( bmp.IsSameAs(GetSelectedBitmap()) )
239 {
240 // Nothing to do, this bitmap is already selected.
241 return;
242 }
243
ab171e95
RR
244 // make sure that the given wxBitmap is not sharing its data with other
245 // wxBitmap instances as its contents will be modified by any drawing
246 // operation done on this DC
247 if (bmp.IsOk())
248 bmp.UnShare();
249
4f37154e 250 GetImpl()->DoSelect(bmp);
ab171e95
RR
251}
252
253void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
254{
4f37154e 255 GetImpl()->DoSelect(bmp);
2970ae54 256}
ab171e95
RR
257
258const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
259{
4f37154e 260 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
261}
262
263wxBitmap& wxMemoryDC::GetSelectedBitmap()
264{
4f37154e 265 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
266}
267
f0875501 268
2970ae54
RR
269//-----------------------------------------------------------------------------
270// wxPaintDC
271//-----------------------------------------------------------------------------
272
f0875501 273IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC)
2970ae54 274
f0875501
VZ
275wxPaintDC::wxPaintDC(wxWindow *win)
276 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win))
2970ae54 277{
2970ae54
RR
278}
279
ab171e95
RR
280//-----------------------------------------------------------------------------
281// wxScreenDC
282//-----------------------------------------------------------------------------
283
284IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
285
286wxScreenDC::wxScreenDC()
f0875501 287 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
ab171e95 288{
2970ae54
RR
289}
290
4f37154e
RR
291//-----------------------------------------------------------------------------
292// wxPrinterDC
293//-----------------------------------------------------------------------------
294
6b4f4d47
RR
295#if wxUSE_PRINTING_ARCHITECTURE
296
4f37154e
RR
297IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
298
299wxPrinterDC::wxPrinterDC()
f0875501 300 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
4f37154e 301{
4f37154e
RR
302}
303
f0875501
VZ
304wxPrinterDC::wxPrinterDC(const wxPrintData& data)
305 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data))
38dd8ed4
RR
306{
307}
308
6d52ca53 309wxRect wxPrinterDC::GetPaperRect() const
38dd8ed4
RR
310{
311 return GetImpl()->GetPaperRect();
312}
313
6d52ca53 314int wxPrinterDC::GetResolution() const
38dd8ed4
RR
315{
316 return GetImpl()->GetResolution();
317}
318
f0875501 319#endif // wxUSE_PRINTING_ARCHITECTURE
38dd8ed4 320
2970ae54 321//-----------------------------------------------------------------------------
888dde65 322// wxDCImpl
2970ae54
RR
323//-----------------------------------------------------------------------------
324
888dde65 325IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
2970ae54 326
888dde65
RR
327wxDCImpl::wxDCImpl( wxDC *owner )
328 : m_window(NULL)
329 , m_colour(wxColourDisplay())
2970ae54
RR
330 , m_ok(true)
331 , m_clipping(false)
332 , m_isInteractive(0)
333 , m_isBBoxValid(false)
334 , m_logicalOriginX(0), m_logicalOriginY(0)
335 , m_deviceOriginX(0), m_deviceOriginY(0)
336 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
337 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
338 , m_userScaleX(1.0), m_userScaleY(1.0)
339 , m_scaleX(1.0), m_scaleY(1.0)
340 , m_signX(1), m_signY(1)
341 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
342 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
343 , m_logicalFunction(wxCOPY)
04ee05f9 344 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT)
2970ae54
RR
345 , m_mappingMode(wxMM_TEXT)
346 , m_pen()
347 , m_brush()
800f1379 348 , m_backgroundBrush()
2970ae54
RR
349 , m_textForegroundColour(*wxBLACK)
350 , m_textBackgroundColour(*wxWHITE)
351 , m_font()
352#if wxUSE_PALETTE
353 , m_palette()
354 , m_hasCustomPalette(false)
355#endif // wxUSE_PALETTE
356{
357 m_owner = owner;
358
359 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
360 (double)wxGetDisplaySizeMM().GetWidth();
361 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
362 (double)wxGetDisplaySizeMM().GetHeight();
f0875501 363
2970ae54
RR
364 ResetBoundingBox();
365 ResetClipping();
366}
367
888dde65 368wxDCImpl::~wxDCImpl()
2970ae54
RR
369{
370}
371
332afcdb
VZ
372// ----------------------------------------------------------------------------
373// clipping
374// ----------------------------------------------------------------------------
375
376void wxDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
377{
378 if ( m_clipping )
379 {
380 m_clipX1 = wxMax( m_clipX1, x );
381 m_clipY1 = wxMax( m_clipY1, y );
382 m_clipX2 = wxMin( m_clipX2, (x + w) );
383 m_clipY2 = wxMin( m_clipY2, (y + h) );
384 }
385 else
386 {
387 m_clipping = true;
388
389 m_clipX1 = x;
390 m_clipY1 = y;
391 m_clipX2 = x + w;
392 m_clipY2 = y + h;
393 }
394}
395
2970ae54
RR
396// ----------------------------------------------------------------------------
397// coordinate conversions and transforms
398// ----------------------------------------------------------------------------
399
888dde65 400wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
2970ae54 401{
d225267e 402 return wxRound( (double)((x - m_deviceOriginX - m_deviceLocalOriginX) * m_signX) / m_scaleX ) + m_logicalOriginX ;
2970ae54
RR
403}
404
888dde65 405wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
2970ae54 406{
d225267e 407 return wxRound( (double)((y - m_deviceOriginY - m_deviceLocalOriginY) * m_signY) / m_scaleY ) + m_logicalOriginY ;
2970ae54
RR
408}
409
888dde65 410wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
2970ae54
RR
411{
412 return wxRound((double)(x) / m_scaleX);
413}
414
888dde65 415wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
2970ae54
RR
416{
417 return wxRound((double)(y) / m_scaleY);
418}
419
888dde65 420wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
2970ae54 421{
d225267e 422 return wxRound( (double)((x - m_logicalOriginX) * m_signX) * m_scaleX) + m_deviceOriginX + m_deviceLocalOriginX;
2970ae54
RR
423}
424
888dde65 425wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
2970ae54 426{
d225267e 427 return wxRound( (double)((y - m_logicalOriginY) * m_signY) * m_scaleY) + m_deviceOriginY + m_deviceLocalOriginY;
2970ae54
RR
428}
429
888dde65 430wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
2970ae54
RR
431{
432 return wxRound((double)(x) * m_scaleX);
433}
434
888dde65 435wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
2970ae54
RR
436{
437 return wxRound((double)(y) * m_scaleY);
438}
439
888dde65 440void wxDCImpl::ComputeScaleAndOrigin()
2970ae54
RR
441{
442 m_scaleX = m_logicalScaleX * m_userScaleX;
443 m_scaleY = m_logicalScaleY * m_userScaleY;
444}
445
89efaf2b 446void wxDCImpl::SetMapMode( wxMappingMode mode )
2970ae54
RR
447{
448 switch (mode)
449 {
450 case wxMM_TWIPS:
451 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
452 break;
453 case wxMM_POINTS:
454 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
455 break;
456 case wxMM_METRIC:
457 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
458 break;
459 case wxMM_LOMETRIC:
460 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
461 break;
462 default:
463 case wxMM_TEXT:
464 SetLogicalScale( 1.0, 1.0 );
465 break;
466 }
467 m_mappingMode = mode;
468}
469
888dde65 470void wxDCImpl::SetUserScale( double x, double y )
2970ae54
RR
471{
472 // allow negative ? -> no
473 m_userScaleX = x;
474 m_userScaleY = y;
475 ComputeScaleAndOrigin();
476}
477
888dde65 478void wxDCImpl::SetLogicalScale( double x, double y )
2970ae54
RR
479{
480 // allow negative ?
481 m_logicalScaleX = x;
482 m_logicalScaleY = y;
483 ComputeScaleAndOrigin();
484}
485
888dde65 486void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
2970ae54
RR
487{
488 m_logicalOriginX = x * m_signX;
489 m_logicalOriginY = y * m_signY;
490 ComputeScaleAndOrigin();
491}
492
888dde65 493void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
2970ae54
RR
494{
495 m_deviceOriginX = x;
496 m_deviceOriginY = y;
497 ComputeScaleAndOrigin();
498}
499
888dde65 500void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
2970ae54
RR
501{
502 m_deviceLocalOriginX = x;
503 m_deviceLocalOriginY = y;
504 ComputeScaleAndOrigin();
505}
506
888dde65 507void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
2970ae54
RR
508{
509 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 510 // wxWidgets 2.9: no longer override it
2970ae54
RR
511 m_signX = (xLeftRight ? 1 : -1);
512 m_signY = (yBottomUp ? -1 : 1);
513 ComputeScaleAndOrigin();
514}
515
888dde65 516bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2970ae54 517{
8cd79b7a
VZ
518 wxTextMeasure tm(GetOwner(), &m_font);
519 return tm.GetPartialTextExtents(text, widths, m_scaleX);
2970ae54
RR
520}
521
888dde65 522void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
2970ae54
RR
523 wxCoord *x,
524 wxCoord *y,
525 wxCoord *h,
526 const wxFont *font) const
527{
8cd79b7a
VZ
528 wxTextMeasure tm(GetOwner(), font && font->IsOk() ? font : &m_font);
529 tm.GetMultiLineTextExtent(text, x, y, h);
2970ae54
RR
530}
531
888dde65 532void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
2970ae54
RR
533 wxCoord width, wxCoord height)
534{
ab171e95 535 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
536
537 wxCoord x2 = x1 + width,
538 y2 = y1 + height;
539
540 // the pen width is calibrated to give 3 for width == height == 10
ab171e95 541 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
2970ae54
RR
542
543 // we're drawing a scaled version of wx/generic/tick.xpm here
544 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
545 y3 = y1 + height / 2; // y of the left tick branch
546 DoDrawLine(x1, y3, x3, y2);
547 DoDrawLine(x3, y2, x2, y1);
548
549 CalcBoundingBox(x1, y1);
550 CalcBoundingBox(x2, y2);
551}
552
553bool
888dde65 554wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
2970ae54
RR
555 wxCoord dstWidth, wxCoord dstHeight,
556 wxDC *source,
557 wxCoord xsrc, wxCoord ysrc,
558 wxCoord srcWidth, wxCoord srcHeight,
89efaf2b 559 wxRasterOperationMode rop,
2970ae54
RR
560 bool useMask,
561 wxCoord xsrcMask,
562 wxCoord ysrcMask)
563{
564 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
9a83f860 565 wxT("invalid blit size") );
2970ae54
RR
566
567 // emulate the stretching by modifying the DC scale
568 double xscale = (double)srcWidth/dstWidth,
569 yscale = (double)srcHeight/dstHeight;
570
571 double xscaleOld, yscaleOld;
572 GetUserScale(&xscaleOld, &yscaleOld);
573 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
574
575 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
576 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
577 source,
578 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
579
580 SetUserScale(xscaleOld, yscaleOld);
581
582 return rc;
583}
584
888dde65 585void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
2970ae54
RR
586{
587 int n = list->GetCount();
588 wxPoint *points = new wxPoint[n];
589
590 int i = 0;
b0d7707b 591 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 592 {
b0d7707b 593 wxPoint *point = node->GetData();
2970ae54
RR
594 points[i].x = point->x;
595 points[i].y = point->y;
596 }
597
598 DoDrawLines(n, points, xoffset, yoffset);
599
600 delete [] points;
601}
602
888dde65 603void wxDCImpl::DrawPolygon(const wxPointList *list,
2970ae54 604 wxCoord xoffset, wxCoord yoffset,
89efaf2b 605 wxPolygonFillMode fillStyle)
2970ae54
RR
606{
607 int n = list->GetCount();
608 wxPoint *points = new wxPoint[n];
609
610 int i = 0;
b0d7707b 611 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 612 {
b0d7707b 613 wxPoint *point = node->GetData();
2970ae54
RR
614 points[i].x = point->x;
615 points[i].y = point->y;
616 }
617
618 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
619
620 delete [] points;
621}
622
623void
888dde65 624wxDCImpl::DoDrawPolyPolygon(int n,
2970ae54
RR
625 int count[],
626 wxPoint points[],
627 wxCoord xoffset, wxCoord yoffset,
89efaf2b 628 wxPolygonFillMode fillStyle)
2970ae54
RR
629{
630 if ( n == 1 )
631 {
632 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
633 return;
634 }
635
636 int i, j, lastOfs;
637 wxPoint* pts;
2970ae54
RR
638
639 for (i = j = lastOfs = 0; i < n; i++)
640 {
641 lastOfs = j;
642 j += count[i];
643 }
644 pts = new wxPoint[j+n-1];
645 for (i = 0; i < j; i++)
646 pts[i] = points[i];
647 for (i = 2; i <= n; i++)
648 {
649 lastOfs -= count[n-i];
650 pts[j++] = pts[lastOfs];
651 }
652
f8ce98de
VZ
653 {
654 wxDCPenChanger setTransp(*m_owner, *wxTRANSPARENT_PEN);
655 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
656 }
657
2970ae54
RR
658 for (i = j = 0; i < n; i++)
659 {
660 DoDrawLines(count[i], pts+j, xoffset, yoffset);
661 j += count[i];
662 }
663 delete[] pts;
664}
665
666#if wxUSE_SPLINES
667
7210c3a1
VZ
668void wxDCImpl::DrawSpline(wxCoord x1, wxCoord y1,
669 wxCoord x2, wxCoord y2,
670 wxCoord x3, wxCoord y3)
2970ae54 671{
7210c3a1
VZ
672 wxPoint points[] = { wxPoint(x1, y1), wxPoint(x2, y2), wxPoint(x3, y3) };
673 DrawSpline(WXSIZEOF(points), points);
2970ae54
RR
674}
675
7210c3a1 676void wxDCImpl::DrawSpline(int n, wxPoint points[])
2970ae54 677{
b0d7707b 678 wxPointList list;
7210c3a1
VZ
679 for ( int i = 0; i < n; i++ )
680 list.Append(&points[i]);
2970ae54 681
7210c3a1 682 DrawSpline(&list);
2970ae54
RR
683}
684
685// ----------------------------------- spline code ----------------------------------------
686
687void wx_quadratic_spline(double a1, double b1, double a2, double b2,
688 double a3, double b3, double a4, double b4);
689void wx_clear_stack();
690int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
691 double *y3, double *x4, double *y4);
692void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
693 double x4, double y4);
694static bool wx_spline_add_point(double x, double y);
ab171e95 695static void wx_spline_draw_point_array(wxDC *dc);
2970ae54 696
7d7b3f69 697static wxPointList wx_spline_point_list;
2970ae54
RR
698
699#define half(z1, z2) ((z1+z2)/2.0)
700#define THRESHOLD 5
701
702/* iterative version */
703
704void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
705 double b4)
706{
707 register double xmid, ymid;
708 double x1, y1, x2, y2, x3, y3, x4, y4;
709
710 wx_clear_stack();
711 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
712
713 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
714 xmid = (double)half(x2, x3);
715 ymid = (double)half(y2, y3);
716 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
717 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
718 wx_spline_add_point( x1, y1 );
719 wx_spline_add_point( xmid, ymid );
720 } else {
721 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
722 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
723 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
724 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
725 }
726 }
727}
728
729/* utilities used by spline drawing routines */
730
731typedef struct wx_spline_stack_struct {
732 double x1, y1, x2, y2, x3, y3, x4, y4;
733} Stack;
734
735#define SPLINE_STACK_DEPTH 20
736static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
737static Stack *wx_stack_top;
738static int wx_stack_count;
739
740void wx_clear_stack()
741{
742 wx_stack_top = wx_spline_stack;
743 wx_stack_count = 0;
744}
745
746void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
747{
748 wx_stack_top->x1 = x1;
749 wx_stack_top->y1 = y1;
750 wx_stack_top->x2 = x2;
751 wx_stack_top->y2 = y2;
752 wx_stack_top->x3 = x3;
753 wx_stack_top->y3 = y3;
754 wx_stack_top->x4 = x4;
755 wx_stack_top->y4 = y4;
756 wx_stack_top++;
757 wx_stack_count++;
758}
759
760int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
761 double *x3, double *y3, double *x4, double *y4)
762{
763 if (wx_stack_count == 0)
764 return (0);
765 wx_stack_top--;
766 wx_stack_count--;
767 *x1 = wx_stack_top->x1;
768 *y1 = wx_stack_top->y1;
769 *x2 = wx_stack_top->x2;
770 *y2 = wx_stack_top->y2;
771 *x3 = wx_stack_top->x3;
772 *y3 = wx_stack_top->y3;
773 *x4 = wx_stack_top->x4;
774 *y4 = wx_stack_top->y4;
775 return (1);
776}
777
778static bool wx_spline_add_point(double x, double y)
779{
b0d7707b
RR
780 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
781 wx_spline_point_list.Append(point );
782 return true;
2970ae54
RR
783}
784
785static void wx_spline_draw_point_array(wxDC *dc)
786{
4f37154e 787 dc->DrawLines(&wx_spline_point_list, 0, 0 );
b0d7707b
RR
788 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
789 while (node)
790 {
791 wxPoint *point = node->GetData();
792 delete point;
793 wx_spline_point_list.Erase(node);
794 node = wx_spline_point_list.GetFirst();
795 }
2970ae54
RR
796}
797
888dde65 798void wxDCImpl::DoDrawSpline( const wxPointList *points )
2970ae54 799{
ab171e95 800 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
801
802 wxPoint *p;
803 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
804 double x1, y1, x2, y2;
805
b0d7707b 806 wxPointList::compatibility_iterator node = points->GetFirst();
2970ae54
RR
807 if (!node)
808 // empty list
809 return;
810
811 p = (wxPoint *)node->GetData();
812
813 x1 = p->x;
814 y1 = p->y;
815
816 node = node->GetNext();
b0d7707b 817 p = node->GetData();
2970ae54
RR
818
819 x2 = p->x;
820 y2 = p->y;
821 cx1 = (double)((x1 + x2) / 2);
822 cy1 = (double)((y1 + y2) / 2);
823 cx2 = (double)((cx1 + x2) / 2);
824 cy2 = (double)((cy1 + y2) / 2);
825
826 wx_spline_add_point(x1, y1);
827
828 while ((node = node->GetNext())
01871bf6 829#if !wxUSE_STD_CONTAINERS
2970ae54 830 != NULL
01871bf6 831#endif // !wxUSE_STD_CONTAINERS
2970ae54
RR
832 )
833 {
b0d7707b 834 p = node->GetData();
2970ae54
RR
835 x1 = x2;
836 y1 = y2;
837 x2 = p->x;
838 y2 = p->y;
839 cx4 = (double)(x1 + x2) / 2;
840 cy4 = (double)(y1 + y2) / 2;
841 cx3 = (double)(x1 + cx4) / 2;
842 cy3 = (double)(y1 + cy4) / 2;
843
844 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
845
846 cx1 = cx4;
847 cy1 = cy4;
848 cx2 = (double)(cx1 + x2) / 2;
849 cy2 = (double)(cy1 + y2) / 2;
850 }
851
852 wx_spline_add_point( cx1, cy1 );
853 wx_spline_add_point( x2, y2 );
854
855 wx_spline_draw_point_array( m_owner );
856}
857
858#endif // wxUSE_SPLINES
859
860
2970ae54 861
888dde65 862void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
2970ae54
RR
863 const wxColour& initialColour,
864 const wxColour& destColour,
865 wxDirection nDirection)
866{
867 // save old pen
868 wxPen oldPen = m_pen;
869 wxBrush oldBrush = m_brush;
870
871 wxUint8 nR1 = initialColour.Red();
872 wxUint8 nG1 = initialColour.Green();
873 wxUint8 nB1 = initialColour.Blue();
874 wxUint8 nR2 = destColour.Red();
875 wxUint8 nG2 = destColour.Green();
876 wxUint8 nB2 = destColour.Blue();
877 wxUint8 nR, nG, nB;
878
879 if ( nDirection == wxEAST || nDirection == wxWEST )
880 {
881 wxInt32 x = rect.GetWidth();
882 wxInt32 w = x; // width of area to shade
883 wxInt32 xDelta = w/256; // height of one shade bend
884 if (xDelta < 1)
885 xDelta = 1;
886
887 while (x >= xDelta)
888 {
889 x -= xDelta;
890 if (nR1 > nR2)
891 nR = nR1 - (nR1-nR2)*(w-x)/w;
892 else
893 nR = nR1 + (nR2-nR1)*(w-x)/w;
894
895 if (nG1 > nG2)
896 nG = nG1 - (nG1-nG2)*(w-x)/w;
897 else
898 nG = nG1 + (nG2-nG1)*(w-x)/w;
899
900 if (nB1 > nB2)
901 nB = nB1 - (nB1-nB2)*(w-x)/w;
902 else
903 nB = nB1 + (nB2-nB1)*(w-x)/w;
904
905 wxColour colour(nR,nG,nB);
04ee05f9 906 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
2970ae54
RR
907 SetBrush(wxBrush(colour));
908 if(nDirection == wxEAST)
5f77ee3b 909 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2970ae54
RR
910 xDelta, rect.GetHeight());
911 else //nDirection == wxWEST
912 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
913 xDelta, rect.GetHeight());
914 }
915 }
916 else // nDirection == wxNORTH || nDirection == wxSOUTH
917 {
918 wxInt32 y = rect.GetHeight();
919 wxInt32 w = y; // height of area to shade
920 wxInt32 yDelta = w/255; // height of one shade bend
921 if (yDelta < 1)
922 yDelta = 1;
923
924 while (y > 0)
925 {
926 y -= yDelta;
927 if (nR1 > nR2)
928 nR = nR1 - (nR1-nR2)*(w-y)/w;
929 else
930 nR = nR1 + (nR2-nR1)*(w-y)/w;
931
932 if (nG1 > nG2)
933 nG = nG1 - (nG1-nG2)*(w-y)/w;
934 else
935 nG = nG1 + (nG2-nG1)*(w-y)/w;
936
937 if (nB1 > nB2)
938 nB = nB1 - (nB1-nB2)*(w-y)/w;
939 else
940 nB = nB1 + (nB2-nB1)*(w-y)/w;
941
942 wxColour colour(nR,nG,nB);
04ee05f9 943 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
2970ae54
RR
944 SetBrush(wxBrush(colour));
945 if(nDirection == wxNORTH)
946 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
947 rect.GetWidth(), yDelta);
948 else //nDirection == wxSOUTH
5f77ee3b 949 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2970ae54
RR
950 rect.GetWidth(), yDelta);
951 }
952 }
953
954 SetPen(oldPen);
955 SetBrush(oldBrush);
956}
957
888dde65 958void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
2970ae54
RR
959 const wxColour& initialColour,
960 const wxColour& destColour,
961 const wxPoint& circleCenter)
962{
1d8cdcf2
VZ
963 // save the old pen and ensure it is restored on exit
964 const wxPen penOrig = m_pen;
965 wxON_BLOCK_EXIT_SET(m_pen, penOrig);
2970ae54
RR
966
967 wxUint8 nR1 = destColour.Red();
968 wxUint8 nG1 = destColour.Green();
969 wxUint8 nB1 = destColour.Blue();
970 wxUint8 nR2 = initialColour.Red();
971 wxUint8 nG2 = initialColour.Green();
972 wxUint8 nB2 = initialColour.Blue();
973 wxUint8 nR, nG, nB;
974
975
976 //Radius
d176b301
VZ
977 double cx = rect.GetWidth() / 2;
978 double cy = rect.GetHeight() / 2;
979 double dRadius;
2970ae54 980 if (cx < cy)
d176b301 981 dRadius = cx;
2970ae54 982 else
d176b301 983 dRadius = cy;
2970ae54
RR
984
985 //Offset of circle
d176b301
VZ
986 double ptX, ptY;
987 ptX = circleCenter.x;
988 ptY = circleCenter.y;
989 double nCircleOffX = ptX - cx;
990 double nCircleOffY = ptY - cy;
991
992 double dGradient;
993 double dx, dy;
2970ae54
RR
994
995 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
996 {
997 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
998 {
999 //get color difference
d176b301
VZ
1000 dx = x;
1001 dy = y;
1002
1003 dGradient = ((dRadius - sqrt( (dx - cx - nCircleOffX) * (dx - cx - nCircleOffX)
1004 +(dy - cy - nCircleOffY) * (dy - cy - nCircleOffY)
1005 )
1006 ) * 100
1007 ) / dRadius;
2970ae54
RR
1008
1009 //normalize Gradient
d176b301
VZ
1010 if (dGradient < 0)
1011 dGradient = 0.0;
2970ae54
RR
1012
1013 //get dest colors
d176b301
VZ
1014 nR = (wxUint8)(nR1 + ((nR2 - nR1) * dGradient / 100));
1015 nG = (wxUint8)(nG1 + ((nG2 - nG1) * dGradient / 100));
1016 nB = (wxUint8)(nB1 + ((nB2 - nB1) * dGradient / 100));
2970ae54
RR
1017
1018 //set the pixel
7825e321 1019 SetPen(wxColour(nR,nG,nB));
ab171e95 1020 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
2970ae54
RR
1021 }
1022 }
2970ae54
RR
1023}
1024
edc51344
VZ
1025void wxDCImpl::InheritAttributes(wxWindow *win)
1026{
1027 wxCHECK_RET( win, "window can't be NULL" );
1028
1029 SetFont(win->GetFont());
1030 SetTextForeground(win->GetForegroundColour());
1031 SetTextBackground(win->GetBackgroundColour());
4feecbb9
VZ
1032 SetBackground(win->GetBackgroundColour());
1033 SetLayoutDirection(win->GetLayoutDirection());
edc51344
VZ
1034}
1035
e29bf4b0
VZ
1036void wxDCImpl::DoGetFontMetrics(int *height,
1037 int *ascent,
1038 int *descent,
1039 int *internalLeading,
1040 int *externalLeading,
1041 int *averageWidth) const
1042{
1043 // Average width is typically the same as width of 'x'.
1044 wxCoord h, d;
1045 DoGetTextExtent("x", averageWidth, &h, &d, externalLeading);
1046
1047 if ( height )
1048 *height = h;
1049 if ( ascent )
1050 *ascent = h - d;
1051 if ( descent )
1052 *descent = d;
1053 if ( internalLeading )
1054 *internalLeading = 0;
1055}
1056
2970ae54
RR
1057//-----------------------------------------------------------------------------
1058// wxDC
1059//-----------------------------------------------------------------------------
1060
1061IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1062
4feecbb9
VZ
1063void wxDC::CopyAttributes(const wxDC& dc)
1064{
1065 SetFont(dc.GetFont());
1066 SetTextForeground(dc.GetTextForeground());
1067 SetTextBackground(dc.GetTextBackground());
1068 SetBackground(dc.GetBackground());
1069 SetLayoutDirection(dc.GetLayoutDirection());
1070}
1071
ab171e95
RR
1072void wxDC::DrawLabel(const wxString& text,
1073 const wxBitmap& bitmap,
1074 const wxRect& rect,
1075 int alignment,
1076 int indexAccel,
1077 wxRect *rectBounding)
1078{
1079 // find the text position
1080 wxCoord widthText, heightText, heightLine;
1081 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1082
1083 wxCoord width, height;
a1b806b9 1084 if ( bitmap.IsOk() )
ab171e95
RR
1085 {
1086 width = widthText + bitmap.GetWidth();
1087 height = bitmap.GetHeight();
1088 }
1089 else // no bitmap
1090 {
1091 width = widthText;
1092 height = heightText;
1093 }
1094
1095 wxCoord x, y;
1096 if ( alignment & wxALIGN_RIGHT )
1097 {
1098 x = rect.GetRight() - width;
1099 }
1100 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1101 {
1102 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1103 }
1104 else // alignment & wxALIGN_LEFT
1105 {
1106 x = rect.GetLeft();
1107 }
1108
1109 if ( alignment & wxALIGN_BOTTOM )
1110 {
1111 y = rect.GetBottom() - height;
1112 }
1113 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1114 {
1115 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1116 }
1117 else // alignment & wxALIGN_TOP
1118 {
1119 y = rect.GetTop();
1120 }
1121
1122 // draw the bitmap first
1123 wxCoord x0 = x,
1124 y0 = y,
1125 width0 = width;
a1b806b9 1126 if ( bitmap.IsOk() )
ab171e95
RR
1127 {
1128 DrawBitmap(bitmap, x, y, true /* use mask */);
1129
1130 wxCoord offset = bitmap.GetWidth() + 4;
1131 x += offset;
1132 width -= offset;
1133
1134 y += (height - heightText) / 2;
1135 }
1136
1137 // we will draw the underscore under the accel char later
1138 wxCoord startUnderscore = 0,
1139 endUnderscore = 0,
1140 yUnderscore = 0;
1141
1142 // split the string into lines and draw each of them separately
a5bb4514
VZ
1143 //
1144 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1145 // strings natively, this is not the case for all of them, notably not
1146 // wxMSW which uses this function for multi-line texts, so we may only
1147 // call DrawText() for single-line strings from here to avoid infinite
1148 // recursion.
ab171e95
RR
1149 wxString curLine;
1150 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1151 {
e447be55 1152 if ( pc == text.end() || *pc == '\n' )
ab171e95
RR
1153 {
1154 int xRealStart = x; // init it here to avoid compielr warnings
1155
1156 if ( !curLine.empty() )
1157 {
1158 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1159 // wxALIGN_LEFT is 0
1160 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1161 {
1162 wxCoord widthLine;
1163 GetTextExtent(curLine, &widthLine, NULL);
1164
1165 if ( alignment & wxALIGN_RIGHT )
1166 {
1167 xRealStart += width - widthLine;
1168 }
1169 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1170 {
1171 xRealStart += (width - widthLine) / 2;
1172 }
1173 }
1174 //else: left aligned, nothing to do
1175
1176 DrawText(curLine, xRealStart, y);
1177 }
1178
1179 y += heightLine;
1180
1181 // do we have underscore in this line? we can check yUnderscore
1182 // because it is set below to just y + heightLine if we do
1183 if ( y == yUnderscore )
1184 {
1185 // adjust the horz positions to account for the shift
1186 startUnderscore += xRealStart;
1187 endUnderscore += xRealStart;
1188 }
1189
1190 if ( pc == text.end() )
1191 break;
1192
1193 curLine.clear();
1194 }
1195 else // not end of line
1196 {
1197 if ( pc - text.begin() == indexAccel )
1198 {
37424888 1199 // remember to draw underscore here
ab171e95
RR
1200 GetTextExtent(curLine, &startUnderscore, NULL);
1201 curLine += *pc;
1202 GetTextExtent(curLine, &endUnderscore, NULL);
1203
1204 yUnderscore = y + heightLine;
1205 }
1206 else
1207 {
1208 curLine += *pc;
1209 }
1210 }
1211 }
1212
1213 // draw the underscore if found
1214 if ( startUnderscore != endUnderscore )
1215 {
1216 // it should be of the same colour as text
04ee05f9 1217 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID));
ab171e95 1218
5fd67293
VZ
1219 // This adjustment is relatively arbitrary: we need to draw the
1220 // underline slightly higher to avoid overflowing the character cell
1221 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1222 //
1223 // The currently used value seems to be compatible with native MSW
1224 // behaviour, i.e. it results in the same appearance of the owner-drawn
1225 // and normal labels.
1226 yUnderscore -= 2;
ab171e95
RR
1227
1228 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1229 }
1230
1231 // return bounding rect if requested
1232 if ( rectBounding )
1233 {
1234 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1235 }
1236
1237 CalcBoundingBox(x0, y0);
1238 CalcBoundingBox(x0 + width0, y0 + height);
1239}
1240
2970ae54
RR
1241#if WXWIN_COMPATIBILITY_2_8
1242 // for compatibility with the old code when wxCoord was long everywhere
1243void wxDC::GetTextExtent(const wxString& string,
1244 long *x, long *y,
1245 long *descent,
1246 long *externalLeading,
1247 const wxFont *theFont) const
1248 {
1249 wxCoord x2, y2, descent2, externalLeading2;
1250 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1251 &descent2, &externalLeading2,
1252 theFont);
1253 if ( x )
1254 *x = x2;
1255 if ( y )
1256 *y = y2;
1257 if ( descent )
1258 *descent = descent2;
1259 if ( externalLeading )
1260 *externalLeading = externalLeading2;
1261 }
1262
f0875501 1263void wxDC::GetLogicalOrigin(long *x, long *y) const
2970ae54
RR
1264 {
1265 wxCoord x2, y2;
1266 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1267 if ( x )
1268 *x = x2;
1269 if ( y )
1270 *y = y2;
1271 }
1272
f0875501 1273void wxDC::GetDeviceOrigin(long *x, long *y) const
2970ae54
RR
1274 {
1275 wxCoord x2, y2;
1276 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1277 if ( x )
1278 *x = x2;
1279 if ( y )
1280 *y = y2;
f0875501
VZ
1281 }
1282
1283void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
2970ae54
RR
1284 {
1285 wxCoord xx,yy,ww,hh;
1286 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1287 if (x) *x = xx;
1288 if (y) *y = yy;
1289 if (w) *w = ww;
1290 if (h) *h = hh;
f0875501
VZ
1291 }
1292
713e9290
VZ
1293void wxDC::DrawObject(wxDrawObject* drawobject)
1294{
1295 drawobject->Draw(*this);
1296 CalcBoundingBox(drawobject->MinX(),drawobject->MinY());
1297 CalcBoundingBox(drawobject->MaxX(),drawobject->MaxY());
1298}
1299
2970ae54 1300#endif // WXWIN_COMPATIBILITY_2_8
2261baf7
VZ
1301
1302/*
1303Notes for wxWidgets DrawEllipticArcRot(...)
1304
1305wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1306It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1307which are also new.
1308
1309All methods are generic, so they can be implemented in wxDCBase.
1310DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1311methods like (WinCE) wxDC::DoDrawArc(...).
1312
1313CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1314of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1315parts) or every column (in steep parts) only one pixel is calculated.
1316Trigonometric calculation (sin, cos, tan, atan) is only done if the
1317starting angle is not equal to the ending angle. The calculation of the
1318pixels is done using simple arithmetic only and should perform not too
1319bad even on devices without floating point processor. I didn't test this yet.
1320
1321Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1322For instance: an ellipse rotated 180 degrees is drawn
1323slightly different from the original.
1324
1325The points are then moved to an array and used to draw a polyline and/or polygon
1326(with center added, the pie).
1327The result looks quite similar to the native ellipse, only e few pixels differ.
1328
1329The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1330slower as DrawEllipse(...), which calls the native API.
1331An rotated ellipse outside the clipping region takes nearly the same time,
1332while an native ellipse outside takes nearly no time to draw.
1333
1334If you draw an arc with this new method, you will see the starting and ending angles
1335are calculated properly.
1336If you use DrawEllipticArc(...), you will see they are only correct for circles
1337and not properly calculated for ellipses.
1338
1339Peter Lenhard
1340p.lenhard@t-online.de
1341*/
1342
1343#ifdef __WXWINCE__
1344void wxDCImpl::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
1345 wxCoord w, wxCoord h,
1346 double sa, double ea, double angle )
1347{
1348 wxPointList list;
1349
1350 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
1351 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
1352
1353 // Add center (for polygon/pie)
1354 list.Append( new wxPoint( x+w/2, y+h/2 ) );
1355
1356 // copy list into array and delete list elements
1357 int n = list.GetCount();
1358 wxPoint *points = new wxPoint[n];
1359 int i = 0;
1360 wxPointList::compatibility_iterator node;
1361 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
1362 {
1363 wxPoint *point = node->GetData();
1364 points[i].x = point->x;
1365 points[i].y = point->y;
1366 delete point;
1367 }
1368
1369 // first draw the pie without pen, if necessary
1370 if( GetBrush() != *wxTRANSPARENT_BRUSH )
1371 {
1372 wxPen tempPen( GetPen() );
1373 SetPen( *wxTRANSPARENT_PEN );
1374 DoDrawPolygon( n, points, 0, 0 );
1375 SetPen( tempPen );
1376 }
1377
1378 // then draw the arc without brush, if necessary
1379 if( GetPen() != *wxTRANSPARENT_PEN )
1380 {
1381 // without center
1382 DoDrawLines( n-1, points, 0, 0 );
1383 }
1384
1385 delete [] points;
1386
1387} // DrawEllipticArcRot
1388
1389void wxDCImpl::Rotate( wxPointList* points, double angle, wxPoint center )
1390{
1391 if( angle != 0.0 )
1392 {
1393 double pi(M_PI);
1394 double dSinA = -sin(angle*2.0*pi/360.0);
1395 double dCosA = cos(angle*2.0*pi/360.0);
1396 wxPointList::compatibility_iterator node;
1397 for ( node = points->GetFirst(); node; node = node->GetNext() )
1398 {
1399 wxPoint* point = node->GetData();
1400
1401 // transform coordinates, if necessary
1402 if( center.x ) point->x -= center.x;
1403 if( center.y ) point->y -= center.y;
1404
1405 // calculate rotation, rounding simply by implicit cast to integer
1406 int xTemp = point->x * dCosA - point->y * dSinA;
1407 point->y = point->x * dSinA + point->y * dCosA;
1408 point->x = xTemp;
1409
1410 // back transform coordinates, if necessary
1411 if( center.x ) point->x += center.x;
1412 if( center.y ) point->y += center.y;
1413 }
1414 }
1415}
1416
1417void wxDCImpl::CalculateEllipticPoints( wxPointList* points,
1418 wxCoord xStart, wxCoord yStart,
1419 wxCoord w, wxCoord h,
1420 double sa, double ea )
1421{
1422 double pi = M_PI;
1423 double sar = 0;
1424 double ear = 0;
1425 int xsa = 0;
1426 int ysa = 0;
1427 int xea = 0;
1428 int yea = 0;
1429 int sq = 0;
1430 int eq = 0;
1431 bool bUseAngles = false;
1432 if( w<0 ) w = -w;
1433 if( h<0 ) h = -h;
1434 // half-axes
1435 wxCoord a = w/2;
1436 wxCoord b = h/2;
1437 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1438 int decrX = 0;
1439 if( 2*a == w ) decrX = 1;
1440 int decrY = 0;
1441 if( 2*b == h ) decrY = 1;
1442 // center
1443 wxCoord xCenter = xStart + a;
1444 wxCoord yCenter = yStart + b;
1445 // calculate data for start and end, if necessary
1446 if( sa != ea )
1447 {
1448 bUseAngles = true;
1449 // normalisation of angles
1450 while( sa<0 ) sa += 360;
1451 while( ea<0 ) ea += 360;
1452 while( sa>=360 ) sa -= 360;
1453 while( ea>=360 ) ea -= 360;
1454 // calculate quadrant numbers
1455 if( sa > 270 ) sq = 3;
1456 else if( sa > 180 ) sq = 2;
1457 else if( sa > 90 ) sq = 1;
1458 if( ea > 270 ) eq = 3;
1459 else if( ea > 180 ) eq = 2;
1460 else if( ea > 90 ) eq = 1;
1461 sar = sa * pi / 180.0;
1462 ear = ea * pi / 180.0;
1463 // correct angle circle -> ellipse
1464 sar = atan( -a/(double)b * tan( sar ) );
1465 if ( sq == 1 || sq == 2 ) sar += pi;
1466 ear = atan( -a/(double)b * tan( ear ) );
1467 if ( eq == 1 || eq == 2 ) ear += pi;
1468 // coordinates of points
1469 xsa = xCenter + a * cos( sar );
1470 if( sq == 0 || sq == 3 ) xsa -= decrX;
1471 ysa = yCenter + b * sin( sar );
1472 if( sq == 2 || sq == 3 ) ysa -= decrY;
1473 xea = xCenter + a * cos( ear );
1474 if( eq == 0 || eq == 3 ) xea -= decrX;
1475 yea = yCenter + b * sin( ear );
1476 if( eq == 2 || eq == 3 ) yea -= decrY;
1477 } // if iUseAngles
1478 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1479 double c1 = b * b;
1480 double c2 = 2.0 / w;
1481 c2 *= c2;
1482 c2 *= c1;
1483 wxCoord x = 0;
1484 wxCoord y = b;
1485 long x2 = 1;
1486 long y2 = y*y;
1487 long y2_old = 0;
1488 long y_old = 0;
1489 // Lists for quadrant 1 to 4
1490 wxPointList pointsarray[4];
1491 // Calculate points for first quadrant and set in all quadrants
1492 for( x = 0; x <= a; ++x )
1493 {
1494 x2 = x2+x+x-1;
1495 y2_old = y2;
1496 y_old = y;
1497 bool bNewPoint = false;
1498 while( y2 > c1 - c2 * x2 && y > 0 )
1499 {
1500 bNewPoint = true;
1501 y2 = y2-y-y+1;
1502 --y;
1503 }
d13b34d3 1504 // old y now too big: set point with old y, old x
2261baf7
VZ
1505 if( bNewPoint && x>1)
1506 {
1507 int x1 = x - 1;
1508 // remove points on the same line
1509 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
1510 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
1511 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
1512 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
1513 } // set point
1514 } // calculate point
1515
1516 // Starting and/or ending points for the quadrants, first quadrant gets both.
1517 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
1518 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
1519 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
1520 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
1521 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
1522
1523 // copy quadrants in original list
1524 if( bUseAngles )
1525 {
1526 // Copy the right part of the points in the lists
1527 // and delete the wxPoints, because they do not leave this method.
1528 points->Append( new wxPoint( xsa, ysa ) );
1529 int q = sq;
1530 bool bStarted = false;
1531 bool bReady = false;
1532 bool bForceTurn = ( sq == eq && sa > ea );
1533 while( !bReady )
1534 {
1535 wxPointList::compatibility_iterator node;
1536 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1537 {
1538 // once: go to starting point in start quadrant
1539 if( !bStarted &&
1540 (
1541 node->GetData()->x < xsa+1 && q <= 1
1542 ||
1543 node->GetData()->x > xsa-1 && q >= 2
1544 )
1545 )
1546 {
1547 bStarted = true;
1548 }
1549
1550 // copy point, if not at ending point
1551 if( bStarted )
1552 {
1553 if( q != eq || bForceTurn
1554 ||
1555 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
1556 ||
1557 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
1558 )
1559 {
1560 // copy point
1561 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
1562 points->Append( pPoint );
1563 }
1564 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
1565 {
1566 bReady = true;
1567 }
1568 }
1569 } // for node
1570 ++q;
1571 if( q > 3 ) q = 0;
1572 bForceTurn = false;
1573 bStarted = true;
1574 } // while not bReady
1575 points->Append( new wxPoint( xea, yea ) );
1576
1577 // delete points
1578 for( q = 0; q < 4; ++q )
1579 {
1580 wxPointList::compatibility_iterator node;
1581 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1582 {
1583 wxPoint *p = node->GetData();
1584 delete p;
1585 }
1586 }
1587 }
1588 else
1589 {
1590 wxPointList::compatibility_iterator node;
1591 // copy whole ellipse, wxPoints will be deleted outside
1592 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
1593 {
1594 wxPoint *p = node->GetData();
1595 points->Append( p );
1596 }
1597 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
1598 {
1599 wxPoint *p = node->GetData();
1600 points->Append( p );
1601 }
1602 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
1603 {
1604 wxPoint *p = node->GetData();
1605 points->Append( p );
1606 }
1607 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
1608 {
1609 wxPoint *p = node->GetData();
1610 points->Append( p );
1611 }
1612 } // not iUseAngles
1613} // CalculateEllipticPoints
1614
1615#endif // __WXWINCE__
12ca5586
VS
1616
1617float wxDCImpl::GetFontPointSizeAdjustment(float dpi)
1618{
1619 // wxMSW has long-standing bug where wxFont point size is interpreted as
1620 // "pixel size corresponding to given point size *on screen*". In other
1621 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1622 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1623 // that *all* printing code has to account for it and consequently, other
1624 // ports need to emulate this bug too:
1625 const wxSize screenPPI = wxGetDisplayPPI();
1626 return float(screenPPI.y) / dpi;
1627}