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