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