]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
add wxSizer::SetDimension() overload taking wxPoint/wxSize instead of 4 ints
[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)
04ee05f9 337 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT)
2970ae54
RR
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();
04ee05f9 748 SetPen(wxPen(*wxBLACK, 0, wxPENSTYLE_TRANSPARENT));
2970ae54
RR
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
7210c3a1
VZ
761void wxDCImpl::DrawSpline(wxCoord x1, wxCoord y1,
762 wxCoord x2, wxCoord y2,
763 wxCoord x3, wxCoord y3)
2970ae54 764{
7210c3a1
VZ
765 wxPoint points[] = { wxPoint(x1, y1), wxPoint(x2, y2), wxPoint(x3, y3) };
766 DrawSpline(WXSIZEOF(points), points);
2970ae54
RR
767}
768
7210c3a1 769void wxDCImpl::DrawSpline(int n, wxPoint points[])
2970ae54 770{
b0d7707b 771 wxPointList list;
7210c3a1
VZ
772 for ( int i = 0; i < n; i++ )
773 list.Append(&points[i]);
2970ae54 774
7210c3a1 775 DrawSpline(&list);
2970ae54
RR
776}
777
778// ----------------------------------- spline code ----------------------------------------
779
780void wx_quadratic_spline(double a1, double b1, double a2, double b2,
781 double a3, double b3, double a4, double b4);
782void wx_clear_stack();
783int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
784 double *y3, double *x4, double *y4);
785void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
786 double x4, double y4);
787static bool wx_spline_add_point(double x, double y);
ab171e95 788static void wx_spline_draw_point_array(wxDC *dc);
2970ae54 789
b0d7707b 790wxPointList wx_spline_point_list;
2970ae54
RR
791
792#define half(z1, z2) ((z1+z2)/2.0)
793#define THRESHOLD 5
794
795/* iterative version */
796
797void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
798 double b4)
799{
800 register double xmid, ymid;
801 double x1, y1, x2, y2, x3, y3, x4, y4;
802
803 wx_clear_stack();
804 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
805
806 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
807 xmid = (double)half(x2, x3);
808 ymid = (double)half(y2, y3);
809 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
810 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
811 wx_spline_add_point( x1, y1 );
812 wx_spline_add_point( xmid, ymid );
813 } else {
814 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
815 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
816 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
817 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
818 }
819 }
820}
821
822/* utilities used by spline drawing routines */
823
824typedef struct wx_spline_stack_struct {
825 double x1, y1, x2, y2, x3, y3, x4, y4;
826} Stack;
827
828#define SPLINE_STACK_DEPTH 20
829static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
830static Stack *wx_stack_top;
831static int wx_stack_count;
832
833void wx_clear_stack()
834{
835 wx_stack_top = wx_spline_stack;
836 wx_stack_count = 0;
837}
838
839void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
840{
841 wx_stack_top->x1 = x1;
842 wx_stack_top->y1 = y1;
843 wx_stack_top->x2 = x2;
844 wx_stack_top->y2 = y2;
845 wx_stack_top->x3 = x3;
846 wx_stack_top->y3 = y3;
847 wx_stack_top->x4 = x4;
848 wx_stack_top->y4 = y4;
849 wx_stack_top++;
850 wx_stack_count++;
851}
852
853int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
854 double *x3, double *y3, double *x4, double *y4)
855{
856 if (wx_stack_count == 0)
857 return (0);
858 wx_stack_top--;
859 wx_stack_count--;
860 *x1 = wx_stack_top->x1;
861 *y1 = wx_stack_top->y1;
862 *x2 = wx_stack_top->x2;
863 *y2 = wx_stack_top->y2;
864 *x3 = wx_stack_top->x3;
865 *y3 = wx_stack_top->y3;
866 *x4 = wx_stack_top->x4;
867 *y4 = wx_stack_top->y4;
868 return (1);
869}
870
871static bool wx_spline_add_point(double x, double y)
872{
b0d7707b
RR
873 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
874 wx_spline_point_list.Append(point );
875 return true;
2970ae54
RR
876}
877
878static void wx_spline_draw_point_array(wxDC *dc)
879{
4f37154e 880 dc->DrawLines(&wx_spline_point_list, 0, 0 );
b0d7707b
RR
881 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
882 while (node)
883 {
884 wxPoint *point = node->GetData();
885 delete point;
886 wx_spline_point_list.Erase(node);
887 node = wx_spline_point_list.GetFirst();
888 }
2970ae54
RR
889}
890
888dde65 891void wxDCImpl::DoDrawSpline( const wxPointList *points )
2970ae54 892{
ab171e95 893 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
894
895 wxPoint *p;
896 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
897 double x1, y1, x2, y2;
898
b0d7707b 899 wxPointList::compatibility_iterator node = points->GetFirst();
2970ae54
RR
900 if (!node)
901 // empty list
902 return;
903
904 p = (wxPoint *)node->GetData();
905
906 x1 = p->x;
907 y1 = p->y;
908
909 node = node->GetNext();
b0d7707b 910 p = node->GetData();
2970ae54
RR
911
912 x2 = p->x;
913 y2 = p->y;
914 cx1 = (double)((x1 + x2) / 2);
915 cy1 = (double)((y1 + y2) / 2);
916 cx2 = (double)((cx1 + x2) / 2);
917 cy2 = (double)((cy1 + y2) / 2);
918
919 wx_spline_add_point(x1, y1);
920
921 while ((node = node->GetNext())
922#if !wxUSE_STL
923 != NULL
924#endif // !wxUSE_STL
925 )
926 {
b0d7707b 927 p = node->GetData();
2970ae54
RR
928 x1 = x2;
929 y1 = y2;
930 x2 = p->x;
931 y2 = p->y;
932 cx4 = (double)(x1 + x2) / 2;
933 cy4 = (double)(y1 + y2) / 2;
934 cx3 = (double)(x1 + cx4) / 2;
935 cy3 = (double)(y1 + cy4) / 2;
936
937 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
938
939 cx1 = cx4;
940 cy1 = cy4;
941 cx2 = (double)(cx1 + x2) / 2;
942 cy2 = (double)(cy1 + y2) / 2;
943 }
944
945 wx_spline_add_point( cx1, cy1 );
946 wx_spline_add_point( x2, y2 );
947
948 wx_spline_draw_point_array( m_owner );
949}
950
951#endif // wxUSE_SPLINES
952
953
2970ae54 954
888dde65 955void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
2970ae54
RR
956 const wxColour& initialColour,
957 const wxColour& destColour,
958 wxDirection nDirection)
959{
960 // save old pen
961 wxPen oldPen = m_pen;
962 wxBrush oldBrush = m_brush;
963
964 wxUint8 nR1 = initialColour.Red();
965 wxUint8 nG1 = initialColour.Green();
966 wxUint8 nB1 = initialColour.Blue();
967 wxUint8 nR2 = destColour.Red();
968 wxUint8 nG2 = destColour.Green();
969 wxUint8 nB2 = destColour.Blue();
970 wxUint8 nR, nG, nB;
971
972 if ( nDirection == wxEAST || nDirection == wxWEST )
973 {
974 wxInt32 x = rect.GetWidth();
975 wxInt32 w = x; // width of area to shade
976 wxInt32 xDelta = w/256; // height of one shade bend
977 if (xDelta < 1)
978 xDelta = 1;
979
980 while (x >= xDelta)
981 {
982 x -= xDelta;
983 if (nR1 > nR2)
984 nR = nR1 - (nR1-nR2)*(w-x)/w;
985 else
986 nR = nR1 + (nR2-nR1)*(w-x)/w;
987
988 if (nG1 > nG2)
989 nG = nG1 - (nG1-nG2)*(w-x)/w;
990 else
991 nG = nG1 + (nG2-nG1)*(w-x)/w;
992
993 if (nB1 > nB2)
994 nB = nB1 - (nB1-nB2)*(w-x)/w;
995 else
996 nB = nB1 + (nB2-nB1)*(w-x)/w;
997
998 wxColour colour(nR,nG,nB);
04ee05f9 999 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
2970ae54
RR
1000 SetBrush(wxBrush(colour));
1001 if(nDirection == wxEAST)
5f77ee3b 1002 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2970ae54
RR
1003 xDelta, rect.GetHeight());
1004 else //nDirection == wxWEST
1005 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1006 xDelta, rect.GetHeight());
1007 }
1008 }
1009 else // nDirection == wxNORTH || nDirection == wxSOUTH
1010 {
1011 wxInt32 y = rect.GetHeight();
1012 wxInt32 w = y; // height of area to shade
1013 wxInt32 yDelta = w/255; // height of one shade bend
1014 if (yDelta < 1)
1015 yDelta = 1;
1016
1017 while (y > 0)
1018 {
1019 y -= yDelta;
1020 if (nR1 > nR2)
1021 nR = nR1 - (nR1-nR2)*(w-y)/w;
1022 else
1023 nR = nR1 + (nR2-nR1)*(w-y)/w;
1024
1025 if (nG1 > nG2)
1026 nG = nG1 - (nG1-nG2)*(w-y)/w;
1027 else
1028 nG = nG1 + (nG2-nG1)*(w-y)/w;
1029
1030 if (nB1 > nB2)
1031 nB = nB1 - (nB1-nB2)*(w-y)/w;
1032 else
1033 nB = nB1 + (nB2-nB1)*(w-y)/w;
1034
1035 wxColour colour(nR,nG,nB);
04ee05f9 1036 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
2970ae54
RR
1037 SetBrush(wxBrush(colour));
1038 if(nDirection == wxNORTH)
1039 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1040 rect.GetWidth(), yDelta);
1041 else //nDirection == wxSOUTH
5f77ee3b 1042 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2970ae54
RR
1043 rect.GetWidth(), yDelta);
1044 }
1045 }
1046
1047 SetPen(oldPen);
1048 SetBrush(oldBrush);
1049}
1050
888dde65 1051void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
2970ae54
RR
1052 const wxColour& initialColour,
1053 const wxColour& destColour,
1054 const wxPoint& circleCenter)
1055{
1056 //save the old pen color
1057 wxColour oldPenColour = m_pen.GetColour();
1058
1059 wxUint8 nR1 = destColour.Red();
1060 wxUint8 nG1 = destColour.Green();
1061 wxUint8 nB1 = destColour.Blue();
1062 wxUint8 nR2 = initialColour.Red();
1063 wxUint8 nG2 = initialColour.Green();
1064 wxUint8 nB2 = initialColour.Blue();
1065 wxUint8 nR, nG, nB;
1066
1067
1068 //Radius
1069 wxInt32 cx = rect.GetWidth() / 2;
1070 wxInt32 cy = rect.GetHeight() / 2;
1071 wxInt32 nRadius;
1072 if (cx < cy)
1073 nRadius = cx;
1074 else
1075 nRadius = cy;
1076
1077 //Offset of circle
1078 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1079 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1080
1081 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1082 {
1083 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1084 {
1085 //get color difference
1086 wxInt32 nGradient = ((nRadius -
1087 (wxInt32)sqrt(
1088 pow((double)(x - cx - nCircleOffX), 2) +
1089 pow((double)(y - cy - nCircleOffY), 2)
1090 )) * 100) / nRadius;
1091
1092 //normalize Gradient
1093 if (nGradient < 0 )
1094 nGradient = 0;
1095
1096 //get dest colors
1097 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1098 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1099 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1100
1101 //set the pixel
1102 m_pen.SetColour(wxColour(nR,nG,nB));
ab171e95 1103 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
2970ae54
RR
1104 }
1105 }
1106 //return old pen color
1107 m_pen.SetColour(oldPenColour);
1108}
1109
1110//-----------------------------------------------------------------------------
1111// wxDC
1112//-----------------------------------------------------------------------------
1113
1114IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1115
ab171e95
RR
1116void wxDC::DrawLabel(const wxString& text,
1117 const wxBitmap& bitmap,
1118 const wxRect& rect,
1119 int alignment,
1120 int indexAccel,
1121 wxRect *rectBounding)
1122{
1123 // find the text position
1124 wxCoord widthText, heightText, heightLine;
1125 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1126
1127 wxCoord width, height;
1128 if ( bitmap.Ok() )
1129 {
1130 width = widthText + bitmap.GetWidth();
1131 height = bitmap.GetHeight();
1132 }
1133 else // no bitmap
1134 {
1135 width = widthText;
1136 height = heightText;
1137 }
1138
1139 wxCoord x, y;
1140 if ( alignment & wxALIGN_RIGHT )
1141 {
1142 x = rect.GetRight() - width;
1143 }
1144 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1145 {
1146 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1147 }
1148 else // alignment & wxALIGN_LEFT
1149 {
1150 x = rect.GetLeft();
1151 }
1152
1153 if ( alignment & wxALIGN_BOTTOM )
1154 {
1155 y = rect.GetBottom() - height;
1156 }
1157 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1158 {
1159 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1160 }
1161 else // alignment & wxALIGN_TOP
1162 {
1163 y = rect.GetTop();
1164 }
1165
1166 // draw the bitmap first
1167 wxCoord x0 = x,
1168 y0 = y,
1169 width0 = width;
1170 if ( bitmap.Ok() )
1171 {
1172 DrawBitmap(bitmap, x, y, true /* use mask */);
1173
1174 wxCoord offset = bitmap.GetWidth() + 4;
1175 x += offset;
1176 width -= offset;
1177
1178 y += (height - heightText) / 2;
1179 }
1180
1181 // we will draw the underscore under the accel char later
1182 wxCoord startUnderscore = 0,
1183 endUnderscore = 0,
1184 yUnderscore = 0;
1185
1186 // split the string into lines and draw each of them separately
1187 wxString curLine;
1188 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1189 {
e447be55 1190 if ( pc == text.end() || *pc == '\n' )
ab171e95
RR
1191 {
1192 int xRealStart = x; // init it here to avoid compielr warnings
1193
1194 if ( !curLine.empty() )
1195 {
1196 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1197 // wxALIGN_LEFT is 0
1198 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1199 {
1200 wxCoord widthLine;
1201 GetTextExtent(curLine, &widthLine, NULL);
1202
1203 if ( alignment & wxALIGN_RIGHT )
1204 {
1205 xRealStart += width - widthLine;
1206 }
1207 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1208 {
1209 xRealStart += (width - widthLine) / 2;
1210 }
1211 }
1212 //else: left aligned, nothing to do
1213
1214 DrawText(curLine, xRealStart, y);
1215 }
1216
1217 y += heightLine;
1218
1219 // do we have underscore in this line? we can check yUnderscore
1220 // because it is set below to just y + heightLine if we do
1221 if ( y == yUnderscore )
1222 {
1223 // adjust the horz positions to account for the shift
1224 startUnderscore += xRealStart;
1225 endUnderscore += xRealStart;
1226 }
1227
1228 if ( pc == text.end() )
1229 break;
1230
1231 curLine.clear();
1232 }
1233 else // not end of line
1234 {
1235 if ( pc - text.begin() == indexAccel )
1236 {
1237 // remeber to draw underscore here
1238 GetTextExtent(curLine, &startUnderscore, NULL);
1239 curLine += *pc;
1240 GetTextExtent(curLine, &endUnderscore, NULL);
1241
1242 yUnderscore = y + heightLine;
1243 }
1244 else
1245 {
1246 curLine += *pc;
1247 }
1248 }
1249 }
1250
1251 // draw the underscore if found
1252 if ( startUnderscore != endUnderscore )
1253 {
1254 // it should be of the same colour as text
04ee05f9 1255 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID));
ab171e95
RR
1256
1257 yUnderscore--;
1258
1259 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1260 }
1261
1262 // return bounding rect if requested
1263 if ( rectBounding )
1264 {
1265 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1266 }
1267
1268 CalcBoundingBox(x0, y0);
1269 CalcBoundingBox(x0 + width0, y0 + height);
1270}
1271
2970ae54
RR
1272#if WXWIN_COMPATIBILITY_2_8
1273 // for compatibility with the old code when wxCoord was long everywhere
1274void wxDC::GetTextExtent(const wxString& string,
1275 long *x, long *y,
1276 long *descent,
1277 long *externalLeading,
1278 const wxFont *theFont) const
1279 {
1280 wxCoord x2, y2, descent2, externalLeading2;
1281 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1282 &descent2, &externalLeading2,
1283 theFont);
1284 if ( x )
1285 *x = x2;
1286 if ( y )
1287 *y = y2;
1288 if ( descent )
1289 *descent = descent2;
1290 if ( externalLeading )
1291 *externalLeading = externalLeading2;
1292 }
1293
f0875501 1294void wxDC::GetLogicalOrigin(long *x, long *y) const
2970ae54
RR
1295 {
1296 wxCoord x2, y2;
1297 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1298 if ( x )
1299 *x = x2;
1300 if ( y )
1301 *y = y2;
1302 }
1303
f0875501 1304void wxDC::GetDeviceOrigin(long *x, long *y) const
2970ae54
RR
1305 {
1306 wxCoord x2, y2;
1307 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1308 if ( x )
1309 *x = x2;
1310 if ( y )
1311 *y = y2;
f0875501
VZ
1312 }
1313
1314void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
2970ae54
RR
1315 {
1316 wxCoord xx,yy,ww,hh;
1317 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1318 if (x) *x = xx;
1319 if (y) *y = yy;
1320 if (w) *w = ww;
1321 if (h) *h = hh;
f0875501
VZ
1322 }
1323
2970ae54 1324#endif // WXWIN_COMPATIBILITY_2_8
2261baf7
VZ
1325
1326/*
1327Notes for wxWidgets DrawEllipticArcRot(...)
1328
1329wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1330It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1331which are also new.
1332
1333All methods are generic, so they can be implemented in wxDCBase.
1334DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1335methods like (WinCE) wxDC::DoDrawArc(...).
1336
1337CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1338of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1339parts) or every column (in steep parts) only one pixel is calculated.
1340Trigonometric calculation (sin, cos, tan, atan) is only done if the
1341starting angle is not equal to the ending angle. The calculation of the
1342pixels is done using simple arithmetic only and should perform not too
1343bad even on devices without floating point processor. I didn't test this yet.
1344
1345Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1346For instance: an ellipse rotated 180 degrees is drawn
1347slightly different from the original.
1348
1349The points are then moved to an array and used to draw a polyline and/or polygon
1350(with center added, the pie).
1351The result looks quite similar to the native ellipse, only e few pixels differ.
1352
1353The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1354slower as DrawEllipse(...), which calls the native API.
1355An rotated ellipse outside the clipping region takes nearly the same time,
1356while an native ellipse outside takes nearly no time to draw.
1357
1358If you draw an arc with this new method, you will see the starting and ending angles
1359are calculated properly.
1360If you use DrawEllipticArc(...), you will see they are only correct for circles
1361and not properly calculated for ellipses.
1362
1363Peter Lenhard
1364p.lenhard@t-online.de
1365*/
1366
1367#ifdef __WXWINCE__
1368void wxDCImpl::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
1369 wxCoord w, wxCoord h,
1370 double sa, double ea, double angle )
1371{
1372 wxPointList list;
1373
1374 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
1375 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
1376
1377 // Add center (for polygon/pie)
1378 list.Append( new wxPoint( x+w/2, y+h/2 ) );
1379
1380 // copy list into array and delete list elements
1381 int n = list.GetCount();
1382 wxPoint *points = new wxPoint[n];
1383 int i = 0;
1384 wxPointList::compatibility_iterator node;
1385 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
1386 {
1387 wxPoint *point = node->GetData();
1388 points[i].x = point->x;
1389 points[i].y = point->y;
1390 delete point;
1391 }
1392
1393 // first draw the pie without pen, if necessary
1394 if( GetBrush() != *wxTRANSPARENT_BRUSH )
1395 {
1396 wxPen tempPen( GetPen() );
1397 SetPen( *wxTRANSPARENT_PEN );
1398 DoDrawPolygon( n, points, 0, 0 );
1399 SetPen( tempPen );
1400 }
1401
1402 // then draw the arc without brush, if necessary
1403 if( GetPen() != *wxTRANSPARENT_PEN )
1404 {
1405 // without center
1406 DoDrawLines( n-1, points, 0, 0 );
1407 }
1408
1409 delete [] points;
1410
1411} // DrawEllipticArcRot
1412
1413void wxDCImpl::Rotate( wxPointList* points, double angle, wxPoint center )
1414{
1415 if( angle != 0.0 )
1416 {
1417 double pi(M_PI);
1418 double dSinA = -sin(angle*2.0*pi/360.0);
1419 double dCosA = cos(angle*2.0*pi/360.0);
1420 wxPointList::compatibility_iterator node;
1421 for ( node = points->GetFirst(); node; node = node->GetNext() )
1422 {
1423 wxPoint* point = node->GetData();
1424
1425 // transform coordinates, if necessary
1426 if( center.x ) point->x -= center.x;
1427 if( center.y ) point->y -= center.y;
1428
1429 // calculate rotation, rounding simply by implicit cast to integer
1430 int xTemp = point->x * dCosA - point->y * dSinA;
1431 point->y = point->x * dSinA + point->y * dCosA;
1432 point->x = xTemp;
1433
1434 // back transform coordinates, if necessary
1435 if( center.x ) point->x += center.x;
1436 if( center.y ) point->y += center.y;
1437 }
1438 }
1439}
1440
1441void wxDCImpl::CalculateEllipticPoints( wxPointList* points,
1442 wxCoord xStart, wxCoord yStart,
1443 wxCoord w, wxCoord h,
1444 double sa, double ea )
1445{
1446 double pi = M_PI;
1447 double sar = 0;
1448 double ear = 0;
1449 int xsa = 0;
1450 int ysa = 0;
1451 int xea = 0;
1452 int yea = 0;
1453 int sq = 0;
1454 int eq = 0;
1455 bool bUseAngles = false;
1456 if( w<0 ) w = -w;
1457 if( h<0 ) h = -h;
1458 // half-axes
1459 wxCoord a = w/2;
1460 wxCoord b = h/2;
1461 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1462 int decrX = 0;
1463 if( 2*a == w ) decrX = 1;
1464 int decrY = 0;
1465 if( 2*b == h ) decrY = 1;
1466 // center
1467 wxCoord xCenter = xStart + a;
1468 wxCoord yCenter = yStart + b;
1469 // calculate data for start and end, if necessary
1470 if( sa != ea )
1471 {
1472 bUseAngles = true;
1473 // normalisation of angles
1474 while( sa<0 ) sa += 360;
1475 while( ea<0 ) ea += 360;
1476 while( sa>=360 ) sa -= 360;
1477 while( ea>=360 ) ea -= 360;
1478 // calculate quadrant numbers
1479 if( sa > 270 ) sq = 3;
1480 else if( sa > 180 ) sq = 2;
1481 else if( sa > 90 ) sq = 1;
1482 if( ea > 270 ) eq = 3;
1483 else if( ea > 180 ) eq = 2;
1484 else if( ea > 90 ) eq = 1;
1485 sar = sa * pi / 180.0;
1486 ear = ea * pi / 180.0;
1487 // correct angle circle -> ellipse
1488 sar = atan( -a/(double)b * tan( sar ) );
1489 if ( sq == 1 || sq == 2 ) sar += pi;
1490 ear = atan( -a/(double)b * tan( ear ) );
1491 if ( eq == 1 || eq == 2 ) ear += pi;
1492 // coordinates of points
1493 xsa = xCenter + a * cos( sar );
1494 if( sq == 0 || sq == 3 ) xsa -= decrX;
1495 ysa = yCenter + b * sin( sar );
1496 if( sq == 2 || sq == 3 ) ysa -= decrY;
1497 xea = xCenter + a * cos( ear );
1498 if( eq == 0 || eq == 3 ) xea -= decrX;
1499 yea = yCenter + b * sin( ear );
1500 if( eq == 2 || eq == 3 ) yea -= decrY;
1501 } // if iUseAngles
1502 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1503 double c1 = b * b;
1504 double c2 = 2.0 / w;
1505 c2 *= c2;
1506 c2 *= c1;
1507 wxCoord x = 0;
1508 wxCoord y = b;
1509 long x2 = 1;
1510 long y2 = y*y;
1511 long y2_old = 0;
1512 long y_old = 0;
1513 // Lists for quadrant 1 to 4
1514 wxPointList pointsarray[4];
1515 // Calculate points for first quadrant and set in all quadrants
1516 for( x = 0; x <= a; ++x )
1517 {
1518 x2 = x2+x+x-1;
1519 y2_old = y2;
1520 y_old = y;
1521 bool bNewPoint = false;
1522 while( y2 > c1 - c2 * x2 && y > 0 )
1523 {
1524 bNewPoint = true;
1525 y2 = y2-y-y+1;
1526 --y;
1527 }
1528 // old y now to big: set point with old y, old x
1529 if( bNewPoint && x>1)
1530 {
1531 int x1 = x - 1;
1532 // remove points on the same line
1533 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
1534 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
1535 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
1536 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
1537 } // set point
1538 } // calculate point
1539
1540 // Starting and/or ending points for the quadrants, first quadrant gets both.
1541 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
1542 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
1543 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
1544 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
1545 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
1546
1547 // copy quadrants in original list
1548 if( bUseAngles )
1549 {
1550 // Copy the right part of the points in the lists
1551 // and delete the wxPoints, because they do not leave this method.
1552 points->Append( new wxPoint( xsa, ysa ) );
1553 int q = sq;
1554 bool bStarted = false;
1555 bool bReady = false;
1556 bool bForceTurn = ( sq == eq && sa > ea );
1557 while( !bReady )
1558 {
1559 wxPointList::compatibility_iterator node;
1560 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1561 {
1562 // once: go to starting point in start quadrant
1563 if( !bStarted &&
1564 (
1565 node->GetData()->x < xsa+1 && q <= 1
1566 ||
1567 node->GetData()->x > xsa-1 && q >= 2
1568 )
1569 )
1570 {
1571 bStarted = true;
1572 }
1573
1574 // copy point, if not at ending point
1575 if( bStarted )
1576 {
1577 if( q != eq || bForceTurn
1578 ||
1579 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
1580 ||
1581 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
1582 )
1583 {
1584 // copy point
1585 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
1586 points->Append( pPoint );
1587 }
1588 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
1589 {
1590 bReady = true;
1591 }
1592 }
1593 } // for node
1594 ++q;
1595 if( q > 3 ) q = 0;
1596 bForceTurn = false;
1597 bStarted = true;
1598 } // while not bReady
1599 points->Append( new wxPoint( xea, yea ) );
1600
1601 // delete points
1602 for( q = 0; q < 4; ++q )
1603 {
1604 wxPointList::compatibility_iterator node;
1605 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1606 {
1607 wxPoint *p = node->GetData();
1608 delete p;
1609 }
1610 }
1611 }
1612 else
1613 {
1614 wxPointList::compatibility_iterator node;
1615 // copy whole ellipse, wxPoints will be deleted outside
1616 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
1617 {
1618 wxPoint *p = node->GetData();
1619 points->Append( p );
1620 }
1621 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
1622 {
1623 wxPoint *p = node->GetData();
1624 points->Append( p );
1625 }
1626 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
1627 {
1628 wxPoint *p = node->GetData();
1629 points->Append( p );
1630 }
1631 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
1632 {
1633 wxPoint *p = node->GetData();
1634 points->Append( p );
1635 }
1636 } // not iUseAngles
1637} // CalculateEllipticPoints
1638
1639#endif // __WXWINCE__