]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
Fix wxHtmlHelpData::SetTempDir() to behave correctly without trailing slash.
[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
77ffb593 7// Copyright: (c) wxWidgets team
65571936 8// Licence: wxWindows licence
dbe94982
BM
9/////////////////////////////////////////////////////////////////////////////
10
1e6feb95
VZ
11// ============================================================================
12// declarations
13// ============================================================================
14
1e6feb95
VZ
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
dbe94982
BM
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
bd1e9c12 23 #pragma hdrstop
dbe94982
BM
24#endif
25
dbe94982 26#include "wx/dc.h"
ab171e95
RR
27#include "wx/dcclient.h"
28#include "wx/dcmemory.h"
29#include "wx/dcscreen.h"
4f37154e 30#include "wx/dcprint.h"
4f37154e 31#include "wx/prntbase.h"
1d8cdcf2 32#include "wx/scopeguard.h"
18680f86
WS
33
34#ifndef WX_PRECOMP
35 #include "wx/math.h"
f2498c4e 36 #include "wx/module.h"
3fb39fd5 37 #include "wx/window.h"
18680f86 38#endif
dbe94982 39
8cd79b7a
VZ
40#include "wx/private/textmeasure.h"
41
888dde65 42#ifdef __WXMSW__
f2498c4e
VZ
43 #include "wx/msw/dcclient.h"
44 #include "wx/msw/dcmemory.h"
45 #include "wx/msw/dcscreen.h"
888dde65 46#endif
2970ae54 47
9dc44eff
PC
48#ifdef __WXGTK3__
49 #include "wx/gtk/dc.h"
50#elif defined __WXGTK20__
f2498c4e
VZ
51 #include "wx/gtk/dcclient.h"
52 #include "wx/gtk/dcmemory.h"
53 #include "wx/gtk/dcscreen.h"
10d30222
VZ
54#elif defined(__WXGTK__)
55 #include "wx/gtk1/dcclient.h"
56 #include "wx/gtk1/dcmemory.h"
57 #include "wx/gtk1/dcscreen.h"
888dde65
RR
58#endif
59
60#ifdef __WXMAC__
c933e267
SC
61 #include "wx/osx/dcclient.h"
62 #include "wx/osx/dcmemory.h"
63 #include "wx/osx/dcscreen.h"
888dde65 64#endif
2970ae54 65
2c24e7ad
SN
66#ifdef __WXPM__
67 #include "wx/os2/dcclient.h"
68 #include "wx/os2/dcmemory.h"
69 #include "wx/os2/dcscreen.h"
70#endif
71
938156b2
DE
72#ifdef __WXCOCOA__
73 #include "wx/cocoa/dcclient.h"
74 #include "wx/cocoa/dcmemory.h"
75 #include "wx/cocoa/dcscreen.h"
76#endif
77
fce127d7
VZ
78#ifdef __WXMOTIF__
79 #include "wx/motif/dcclient.h"
80 #include "wx/motif/dcmemory.h"
81 #include "wx/motif/dcscreen.h"
82#endif
83
e6514d0e 84#ifdef __WXX11__
f2498c4e
VZ
85 #include "wx/x11/dcclient.h"
86 #include "wx/x11/dcmemory.h"
87 #include "wx/x11/dcscreen.h"
e6514d0e
RR
88#endif
89
4a624f6e
VZ
90#ifdef __WXDFB__
91 #include "wx/dfb/dcclient.h"
92 #include "wx/dfb/dcmemory.h"
93 #include "wx/dfb/dcscreen.h"
94#endif
95
2970ae54
RR
96//----------------------------------------------------------------------------
97// wxDCFactory
98//----------------------------------------------------------------------------
99
100wxDCFactory *wxDCFactory::m_factory = NULL;
101
f2498c4e 102void wxDCFactory::Set(wxDCFactory *factory)
2970ae54 103{
f2498c4e 104 delete m_factory;
2970ae54 105
f2498c4e 106 m_factory = factory;
2970ae54
RR
107}
108
f0875501 109wxDCFactory *wxDCFactory::Get()
2970ae54 110{
f2498c4e
VZ
111 if ( !m_factory )
112 m_factory = new wxNativeDCFactory;
2970ae54 113
f2498c4e 114 return m_factory;
2970ae54
RR
115}
116
f2498c4e
VZ
117class wxDCFactoryCleanupModule : public wxModule
118{
119public:
120 virtual bool OnInit() { return true; }
121 virtual void OnExit() { wxDCFactory::Set(NULL); }
122
123private:
124 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule)
125};
126
127IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule)
128
2970ae54
RR
129//-----------------------------------------------------------------------------
130// wxNativeDCFactory
131//-----------------------------------------------------------------------------
132
888dde65 133wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
f0875501 134{
edc51344
VZ
135 wxDCImpl * const impl = new wxWindowDCImpl( owner, window );
136 impl->InheritAttributes(window);
137 return impl;
2970ae54
RR
138}
139
888dde65
RR
140wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
141{
edc51344
VZ
142 wxDCImpl * const impl = new wxClientDCImpl( owner, window );
143 impl->InheritAttributes(window);
144 return impl;
2970ae54
RR
145}
146
888dde65
RR
147wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
148{
edc51344
VZ
149 wxDCImpl * const impl = new wxPaintDCImpl( owner, window );
150 impl->InheritAttributes(window);
151 return impl;
2970ae54
RR
152}
153
888dde65
RR
154wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
155{
156 return new wxMemoryDCImpl( owner );
2970ae54
RR
157}
158
2a02f84b 159wxDCImpl* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC *owner, wxBitmap& bitmap)
888dde65 160{
2a02f84b
VZ
161 // the bitmap may be modified when it's selected into a memory DC so make
162 // sure changing this bitmap doesn't affect any other shallow copies of it
163 // (see wxMemoryDC::SelectObject())
164 //
165 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
166 // method because this should be rarely needed and easy to work around by
167 // using the default ctor and calling SelectObjectAsSource itself
168 if ( bitmap.IsOk() )
169 bitmap.UnShare();
170
171 return new wxMemoryDCImpl(owner, bitmap);
2970ae54
RR
172}
173
888dde65
RR
174wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
175{
176 return new wxMemoryDCImpl( owner, dc );
ab171e95
RR
177}
178
888dde65
RR
179wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
180{
181 return new wxScreenDCImpl( owner );
2970ae54
RR
182}
183
6b4f4d47 184#if wxUSE_PRINTING_ARCHITECTURE
888dde65 185wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
c8ddadff 186{
4f37154e 187 wxPrintFactory *factory = wxPrintFactory::GetFactory();
888dde65 188 return factory->CreatePrinterDCImpl( owner, data );
c8ddadff 189}
6b4f4d47 190#endif
c8ddadff 191
2970ae54
RR
192//-----------------------------------------------------------------------------
193// wxWindowDC
194//-----------------------------------------------------------------------------
195
f0875501 196IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC)
2970ae54 197
f0875501
VZ
198wxWindowDC::wxWindowDC(wxWindow *win)
199 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win))
2970ae54 200{
2970ae54
RR
201}
202
203//-----------------------------------------------------------------------------
204// wxClientDC
205//-----------------------------------------------------------------------------
206
f0875501 207IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC)
2970ae54 208
f0875501
VZ
209wxClientDC::wxClientDC(wxWindow *win)
210 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win))
2970ae54 211{
2970ae54
RR
212}
213
2970ae54
RR
214//-----------------------------------------------------------------------------
215// wxMemoryDC
216//-----------------------------------------------------------------------------
217
218IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
219
220wxMemoryDC::wxMemoryDC()
f0875501 221 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
2970ae54 222{
2970ae54
RR
223}
224
f0875501
VZ
225wxMemoryDC::wxMemoryDC(wxBitmap& bitmap)
226 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap))
2970ae54 227{
2970ae54
RR
228}
229
f0875501
VZ
230wxMemoryDC::wxMemoryDC(wxDC *dc)
231 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc))
2970ae54 232{
ab171e95
RR
233}
234
235void wxMemoryDC::SelectObject(wxBitmap& bmp)
236{
71f5b0e7
VZ
237 if ( bmp.IsSameAs(GetSelectedBitmap()) )
238 {
239 // Nothing to do, this bitmap is already selected.
240 return;
241 }
242
ab171e95
RR
243 // make sure that the given wxBitmap is not sharing its data with other
244 // wxBitmap instances as its contents will be modified by any drawing
245 // operation done on this DC
246 if (bmp.IsOk())
247 bmp.UnShare();
248
4f37154e 249 GetImpl()->DoSelect(bmp);
ab171e95
RR
250}
251
252void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
253{
4f37154e 254 GetImpl()->DoSelect(bmp);
2970ae54 255}
ab171e95
RR
256
257const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
258{
4f37154e 259 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
260}
261
262wxBitmap& wxMemoryDC::GetSelectedBitmap()
263{
4f37154e 264 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
265}
266
f0875501 267
2970ae54
RR
268//-----------------------------------------------------------------------------
269// wxPaintDC
270//-----------------------------------------------------------------------------
271
f0875501 272IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC)
2970ae54 273
f0875501
VZ
274wxPaintDC::wxPaintDC(wxWindow *win)
275 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win))
2970ae54 276{
2970ae54
RR
277}
278
ab171e95
RR
279//-----------------------------------------------------------------------------
280// wxScreenDC
281//-----------------------------------------------------------------------------
282
283IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
284
285wxScreenDC::wxScreenDC()
f0875501 286 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
ab171e95 287{
2970ae54
RR
288}
289
4f37154e
RR
290//-----------------------------------------------------------------------------
291// wxPrinterDC
292//-----------------------------------------------------------------------------
293
6b4f4d47
RR
294#if wxUSE_PRINTING_ARCHITECTURE
295
4f37154e
RR
296IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
297
298wxPrinterDC::wxPrinterDC()
f0875501 299 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
4f37154e 300{
4f37154e
RR
301}
302
f0875501
VZ
303wxPrinterDC::wxPrinterDC(const wxPrintData& data)
304 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data))
38dd8ed4
RR
305{
306}
307
6d52ca53 308wxRect wxPrinterDC::GetPaperRect() const
38dd8ed4
RR
309{
310 return GetImpl()->GetPaperRect();
311}
312
6d52ca53 313int wxPrinterDC::GetResolution() const
38dd8ed4
RR
314{
315 return GetImpl()->GetResolution();
316}
317
f0875501 318#endif // wxUSE_PRINTING_ARCHITECTURE
38dd8ed4 319
2970ae54 320//-----------------------------------------------------------------------------
888dde65 321// wxDCImpl
2970ae54
RR
322//-----------------------------------------------------------------------------
323
888dde65 324IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
2970ae54 325
888dde65
RR
326wxDCImpl::wxDCImpl( wxDC *owner )
327 : m_window(NULL)
328 , m_colour(wxColourDisplay())
2970ae54
RR
329 , m_ok(true)
330 , m_clipping(false)
331 , m_isInteractive(0)
332 , m_isBBoxValid(false)
333 , m_logicalOriginX(0), m_logicalOriginY(0)
334 , m_deviceOriginX(0), m_deviceOriginY(0)
335 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
336 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
337 , m_userScaleX(1.0), m_userScaleY(1.0)
338 , m_scaleX(1.0), m_scaleY(1.0)
339 , m_signX(1), m_signY(1)
538a2cfa 340 , m_contentScaleFactor(1)
2970ae54
RR
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,
4787c92d
PC
625 const int count[],
626 const wxPoint points[],
2970ae54 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
4787c92d 676void wxDCImpl::DrawSpline(int n, const wxPoint points[])
2970ae54 677{
b0d7707b 678 wxPointList list;
7210c3a1 679 for ( int i = 0; i < n; i++ )
4787c92d 680 list.Append(const_cast<wxPoint*>(&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 801
4787c92d 802 const wxPoint *p;
2970ae54
RR
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
4787c92d 811 p = node->GetData();
2970ae54
RR
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}