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