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