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