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