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