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