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