]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
1. make debugging macros compatible with ANSI build even in Unicode build (i.e.,...
[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"
653752be 28#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
18680f86
WS
29
30#ifndef WX_PRECOMP
31 #include "wx/math.h"
32#endif
dbe94982 33
2970ae54
RR
34
35
36#if wxUSE_NEW_DC
37
38//----------------------------------------------------------------------------
39// wxDCFactory
40//----------------------------------------------------------------------------
41
42wxDCFactory *wxDCFactory::m_factory = NULL;
43
44void wxDCFactory::SetDCFactory( wxDCFactory *factory )
45{
46 if (wxDCFactory::m_factory)
47 delete wxDCFactory::m_factory;
48
49 wxDCFactory::m_factory = factory;
50}
51
52wxDCFactory *wxDCFactory::GetFactory()
53{
54 if (!wxDCFactory::m_factory)
55 wxDCFactory::m_factory = new wxNativeDCFactory;
56
57 return wxDCFactory::m_factory;
58}
59
60//-----------------------------------------------------------------------------
61// wxNativeDCFactory
62//-----------------------------------------------------------------------------
63
64wxImplDC* wxNativeDCFactory::CreateWindowDC()
65{
66#if defined(__WXMSW__)
67 return new wxWindowsWindowImplDC();
68#elif defined(__WXGTK20__)
69 return new wxGTKWindowImplDC();
70#elif defined(__WXGTK__)
71 return new wxGTKWindowImplDC();
72#elif defined(__WXMAC__)
73 return new wxMacWindowImplDC();
74#elif defined(__WXCOCOA__)
75 return new wxCocoaWindowImplDC();
76#elif defined(__WXMOTIF__)
77 return new wxMotifWindowImplDC();
78#elif defined(__WXX11__)
79 return new wxX11WindowImplDC();
80#elif defined(__WXMGL__)
81 return new wxMGLWindowImplDC();
82#elif defined(__WXDFB__)
83 return new wxDFBWindowImplDC();
84#elif defined(__WXPM__)
85 return new wxPMWindowImplDC();
86#elif defined(__PALMOS__)
87 return new wxPalmWindowImplDC();
88#endif
89}
90
91wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindow *window )
92{
93#if defined(__WXMSW__)
94 return new wxWindowsWindowImplDC( window );
95#elif defined(__WXGTK20__)
96 return new wxGTKWindowImplDC( window );
97#elif defined(__WXGTK__)
98 return new wxGTKWindowImplDC( window );
99#elif defined(__WXMAC__)
100 return new wxMacWindowImplDC( window );
101#elif defined(__WXCOCOA__)
102 return new wxCocoaWindowImplDC( window );
103#elif defined(__WXMOTIF__)
104 return new wxMotifWindowImplDC( window );
105#elif defined(__WXX11__)
106 return new wxX11WindowImplDC( window );
107#elif defined(__WXMGL__)
108 return new wxMGLWindowImplDC( window );
109#elif defined(__WXDFB__)
110 return new wxDFBWindowImplDC( window );
111#elif defined(__WXPM__)
112 return new wxPMWindowImplDC( window );
113#elif defined(__PALMOS__)
114 return new wxPalmWindowImplDC( window );
115#endif
116}
117
118wxImplDC* wxNativeDCFactory::CreateClientDC()
119{
120#if defined(__WXMSW__)
121 return new wxWindowsClientImplDC();
122#elif defined(__WXGTK20__)
123 return new wxGTKClientImplDC();
124#elif defined(__WXGTK__)
125 return new wxGTKClientImplDC();
126#elif defined(__WXMAC__)
127 return new wxMacClientImplDC();
128#elif defined(__WXCOCOA__)
129 return new wxCocoaClientImplDC();
130#elif defined(__WXMOTIF__)
131 return new wxMotifClientImplDC();
132#elif defined(__WXX11__)
133 return new wxX11ClientImplDC();
134#elif defined(__WXMGL__)
135 return new wxMGLClientImplDC();
136#elif defined(__WXDFB__)
137 return new wxDFBClientImplDC();
138#elif defined(__WXPM__)
139 return new wxPMClientImplDC();
140#elif defined(__PALMOS__)
141 return new wxPalmClientImplDC();
142#endif
143}
144
145wxImplDC* wxNativeDCFactory::CreateClientDC( wxWindow *window )
146{
147#if defined(__WXMSW__)
148 return new wxWindowsClientImplDC( window );
149#elif defined(__WXGTK20__)
150 return new wxGTKClientImplDC( window );
151#elif defined(__WXGTK__)
152 return new wxGTKClientImplDC( window );
153#elif defined(__WXMAC__)
154 return new wxMacClientImplDC( window );
155#elif defined(__WXCOCOA__)
156 return new wxCocoaClientImplDC( window );
157#elif defined(__WXMOTIF__)
158 return new wxMotifClientImplDC( window );
159#elif defined(__WXX11__)
160 return new wxX11ClientImplDC( window );
161#elif defined(__WXMGL__)
162 return new wxMGLClientImplDC( window );
163#elif defined(__WXDFB__)
164 return new wxDFBClientImplDC( window );
165#elif defined(__WXPM__)
166 return new wxPMClientImplDC( window );
167#elif defined(__PALMOS__)
168 return new wxPalmClientImplDC( window );
169#endif
170}
171
172wxImplDC* wxNativeDCFactory::CreatePaintDC()
173{
174#if defined(__WXMSW__)
175 return new wxWindowsPaintImplDC();
176#elif defined(__WXGTK20__)
177 return new wxGTKPaintImplDC();
178#elif defined(__WXGTK__)
179 return new wxGTKPaintImplDC();
180#elif defined(__WXMAC__)
181 return new wxMacPaintImplDC();
182#elif defined(__WXCOCOA__)
183 return new wxCocoaPaintImplDC();
184#elif defined(__WXMOTIF__)
185 return new wxMotifPaintImplDC();
186#elif defined(__WXX11__)
187 return new wxX11PaintImplDC();
188#elif defined(__WXMGL__)
189 return new wxMGLPaintImplDC();
190#elif defined(__WXDFB__)
191 return new wxDFBPaintImplDC();
192#elif defined(__WXPM__)
193 return new wxPMPaintImplDC();
194#elif defined(__PALMOS__)
195 return new wxPalmPaintImplDC();
196#endif
197}
198
199wxImplDC* wxNativeDCFactory::CreatePaintDC( wxWindow *window )
200{
201#if defined(__WXMSW__)
202 return new wxWindowsPaintImplDC( window );
203#elif defined(__WXGTK20__)
204 return new wxGTKPaintImplDC( window );
205#elif defined(__WXGTK__)
206 return new wxGTKPaintImplDC( window );
207#elif defined(__WXMAC__)
208 return new wxMacPaintImplDC( window );
209#elif defined(__WXCOCOA__)
210 return new wxCocoaPaintImplDC( window );
211#elif defined(__WXMOTIF__)
212 return new wxMotifPaintImplDC( window );
213#elif defined(__WXX11__)
214 return new wxX11PaintImplDC( window );
215#elif defined(__WXMGL__)
216 return new wxMGLPaintImplDC( window );
217#elif defined(__WXDFB__)
218 return new wxDFBPaintImplDC( window );
219#elif defined(__WXPM__)
220 return new wxPMPaintImplDC( window );
221#elif defined(__PALMOS__)
222 return new wxPalmPaintImplDC( window );
223#endif
224}
225
226wxImplDC* wxNativeDCFactory::CreateMemoryDC()
227{
228#if defined(__WXMSW__)
229 return new wxWindowsMemoryImplDC();
230#elif defined(__WXGTK20__)
231 return new wxGTKMemoryImplDC();
232#elif defined(__WXGTK__)
233 return new wxGTKMemoryImplDC();
234#elif defined(__WXMAC__)
235 return new wxMacMemoryImplDC();
236#elif defined(__WXCOCOA__)
237 return new wxCocoaMemoryImplDC();
238#elif defined(__WXMOTIF__)
239 return new wxMotifMemoryImplDC();
240#elif defined(__WXX11__)
241 return new wxX11MemoryImplDC();
242#elif defined(__WXMGL__)
243 return new wxMGLMemoryImplDC();
244#elif defined(__WXDFB__)
245 return new wxDFBMemoryImplDC();
246#elif defined(__WXPM__)
247 return new wxPMMemoryImplDC();
248#elif defined(__PALMOS__)
249 return new wxPalmMemoryImplDC();
250#endif
251}
252
253wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxBitmap &bitmap )
254{
255#if defined(__WXMSW__)
256 return new wxWindowsMemoryImplDC( bitmap );
257#elif defined(__WXGTK20__)
258 return new wxGTKMemoryImplDC( bitmap );
259#elif defined(__WXGTK__)
260 return new wxGTKMemoryImplDC( bitmap );
261#elif defined(__WXMAC__)
262 return new wxMacMemoryImplDC( bitmap );
263#elif defined(__WXCOCOA__)
264 return new wxCocoaMemoryImplDC( bitmap );
265#elif defined(__WXMOTIF__)
266 return new wxMotifMemoryImplDC( bitmap );
267#elif defined(__WXX11__)
268 return new wxX11MemoryImplDC( bitmap );
269#elif defined(__WXMGL__)
270 return new wxMGLMemoryImplDC( bitmap );
271#elif defined(__WXDFB__)
272 return new wxDFBMemoryImplDC( bitmap );
273#elif defined(__WXPM__)
274 return new wxPMMemoryImplDC( bitmap );
275#elif defined(__PALMOS__)
276 return new wxPalmMemoryImplDC( bitmap );
277#endif
278}
279
280wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxDC *dc )
281{
282#if defined(__WXMSW__)
283 return new wxWindowsMemoryImplDC( dc );
284#elif defined(__WXGTK20__)
285 return new wxGTKMemoryImplDC( dc );
286#elif defined(__WXGTK__)
287 return new wxGTKMemoryImplDC( dc );
288#elif defined(__WXMAC__)
289 return new wxMacMemoryImplDC( dc );
290#elif defined(__WXCOCOA__)
291 return new wxCocoaMemoryImplDC( dc );
292#elif defined(__WXMOTIF__)
293 return new wxMotifMemoryImplDC( dc );
294#elif defined(__WXX11__)
295 return new wxX11MemoryImplDC( dc );
296#elif defined(__WXMGL__)
297 return new wxMGLMemoryImplDC( dc );
298#elif defined(__WXDFB__)
299 return new wxDFBMemoryImplDC( dc );
300#elif defined(__WXPM__)
301 return new wxPMMemoryImplDC( dc );
302#elif defined(__PALMOS__)
303 return new wxPalmMemoryImplDC( dc );
304#endif
305}
306
307//-----------------------------------------------------------------------------
308// wxWindowDC
309//-----------------------------------------------------------------------------
310
311IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
312
313wxWindow::wxWindowDC()
314{
315 wxDCFactory *factory = wxDCFactory::GetFactory();
316 m_pimpl = factory->CreateWindowDC();
317}
318
319wxWindow::wxWindowDC( wxWindow *win )
320{
321 wxDCFactory *factory = wxDCFactory::GetFactory();
322 m_pimpl = factory->CreateWindowDC( win );
323}
324
325//-----------------------------------------------------------------------------
326// wxClientDC
327//-----------------------------------------------------------------------------
328
329IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxDC)
330
331wxClientDC::wxClientDC()
332{
333 wxDCFactory *factory = wxDCFactory::GetFactory();
334 m_pimpl = factory->CreateClientDC();
335}
336
337wxClientDC::wxClientDC( wxWindow *win )
338{
339 wxDCFactory *factory = wxDCFactory::GetFactory();
340 m_pimpl = factory->CreateClientDC( win );
341}
342
343//-----------------------------------------------------------------------------
344// wxMemoryDC
345//-----------------------------------------------------------------------------
346
347IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
348
349wxMemoryDC::wxMemoryDC()
350{
351 wxDCFactory *factory = wxDCFactory::GetFactory();
352 m_pimpl = factory->CreateMemoryDC();
353}
354
355wxMemoryDC::wxMemoryDC( wxBitmap& bitmap )
356{
357 wxDCFactory *factory = wxDCFactory::GetFactory();
358 m_pimpl = factory->CreateMemoryDC( bitmap );
359}
360
361wxMemoryDC::wxMemoryDC( wxDC *dc )
362{
363 wxDCFactory *factory = wxDCFactory::GetFactory();
364 m_pimpl = factory->CreateMemoryDC( dc );
365}
366
367//-----------------------------------------------------------------------------
368// wxPaintDC
369//-----------------------------------------------------------------------------
370
371IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxDC)
372
373wxPaintDC::wxPaintDC()
374{
375 wxDCFactory *factory = wxDCFactory::GetFactory();
376 m_pimpl = factory->CreatePaintDC();
377}
378
379wxPaintDC::wxPaintDC( wxWindow *win )
380{
381 wxDCFactory *factory = wxDCFactory::GetFactory();
382 m_pimpl = factory->CreatePaintDC( win );
383}
384
385//-----------------------------------------------------------------------------
386// wxImplDC
387//-----------------------------------------------------------------------------
388
389IMPLEMENT_ABSTRACT_CLASS(wxImplDC, wxObject)
390
391wxImplDC::wxImplDC( wxDC *owner )
392 : m_colour(wxColourDisplay())
393 , m_ok(true)
394 , m_clipping(false)
395 , m_isInteractive(0)
396 , m_isBBoxValid(false)
397 , m_logicalOriginX(0), m_logicalOriginY(0)
398 , m_deviceOriginX(0), m_deviceOriginY(0)
399 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
400 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
401 , m_userScaleX(1.0), m_userScaleY(1.0)
402 , m_scaleX(1.0), m_scaleY(1.0)
403 , m_signX(1), m_signY(1)
404 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
405 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
406 , m_logicalFunction(wxCOPY)
407 , m_backgroundMode(wxTRANSPARENT)
408 , m_mappingMode(wxMM_TEXT)
409 , m_pen()
410 , m_brush()
411 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
412 , m_textForegroundColour(*wxBLACK)
413 , m_textBackgroundColour(*wxWHITE)
414 , m_font()
415#if wxUSE_PALETTE
416 , m_palette()
417 , m_hasCustomPalette(false)
418#endif // wxUSE_PALETTE
419{
420 m_owner = owner;
421
422 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
423 (double)wxGetDisplaySizeMM().GetWidth();
424 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
425 (double)wxGetDisplaySizeMM().GetHeight();
426
427 ResetBoundingBox();
428 ResetClipping();
429}
430
431wxImplDC::~wxImplDC()
432{
433}
434
435#if WXWIN_COMPATIBILITY_2_8
436 // for compatibility with the old code when wxCoord was long everywhere
437void wxImplDC::GetTextExtent(const wxString& string,
438 long *x, long *y,
439 long *descent,
440 long *externalLeading,
441 const wxFont *theFont) const
442 {
443 wxCoord x2, y2, descent2, externalLeading2;
444 DoGetTextExtent(string, &x2, &y2,
445 &descent2, &externalLeading2,
446 theFont);
447 if ( x )
448 *x = x2;
449 if ( y )
450 *y = y2;
451 if ( descent )
452 *descent = descent2;
453 if ( externalLeading )
454 *externalLeading = externalLeading2;
455 }
456
457void wxImplDC::GetLogicalOrigin(long *x, long *y) const
458 {
459 wxCoord x2, y2;
460 DoGetLogicalOrigin(&x2, &y2);
461 if ( x )
462 *x = x2;
463 if ( y )
464 *y = y2;
465 }
466
467void wxImplDC::GetDeviceOrigin(long *x, long *y) const
468 {
469 wxCoord x2, y2;
470 DoGetDeviceOrigin(&x2, &y2);
471 if ( x )
472 *x = x2;
473 if ( y )
474 *y = y2;
475 }
476
477void wxImplDC::GetClippingBox(long *x, long *y, long *w, long *h) const
478 {
479 wxCoord xx,yy,ww,hh;
480 DoGetClippingBox(&xx, &yy, &ww, &hh);
481 if (x) *x = xx;
482 if (y) *y = yy;
483 if (w) *w = ww;
484 if (h) *h = hh;
485 }
486#endif // WXWIN_COMPATIBILITY_2_8
487
488
489
490// ----------------------------------------------------------------------------
491// coordinate conversions and transforms
492// ----------------------------------------------------------------------------
493
494wxCoord wxImplDC::DeviceToLogicalX(wxCoord x) const
495{
496 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
497}
498
499wxCoord wxImplDC::DeviceToLogicalY(wxCoord y) const
500{
501 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
502}
503
504wxCoord wxImplDC::DeviceToLogicalXRel(wxCoord x) const
505{
506 return wxRound((double)(x) / m_scaleX);
507}
508
509wxCoord wxImplDC::DeviceToLogicalYRel(wxCoord y) const
510{
511 return wxRound((double)(y) / m_scaleY);
512}
513
514wxCoord wxImplDC::LogicalToDeviceX(wxCoord x) const
515{
516 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
517}
518
519wxCoord wxImplDC::LogicalToDeviceY(wxCoord y) const
520{
521 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
522}
523
524wxCoord wxImplDC::LogicalToDeviceXRel(wxCoord x) const
525{
526 return wxRound((double)(x) * m_scaleX);
527}
528
529wxCoord wxImplDC::LogicalToDeviceYRel(wxCoord y) const
530{
531 return wxRound((double)(y) * m_scaleY);
532}
533
534void wxImplDC::ComputeScaleAndOrigin()
535{
536 m_scaleX = m_logicalScaleX * m_userScaleX;
537 m_scaleY = m_logicalScaleY * m_userScaleY;
538}
539
540void wxImplDC::SetMapMode( int mode )
541{
542 switch (mode)
543 {
544 case wxMM_TWIPS:
545 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
546 break;
547 case wxMM_POINTS:
548 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
549 break;
550 case wxMM_METRIC:
551 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
552 break;
553 case wxMM_LOMETRIC:
554 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
555 break;
556 default:
557 case wxMM_TEXT:
558 SetLogicalScale( 1.0, 1.0 );
559 break;
560 }
561 m_mappingMode = mode;
562}
563
564void wxImplDC::SetUserScale( double x, double y )
565{
566 // allow negative ? -> no
567 m_userScaleX = x;
568 m_userScaleY = y;
569 ComputeScaleAndOrigin();
570}
571
572void wxImplDC::SetLogicalScale( double x, double y )
573{
574 // allow negative ?
575 m_logicalScaleX = x;
576 m_logicalScaleY = y;
577 ComputeScaleAndOrigin();
578}
579
580void wxImplDC::SetLogicalOrigin( wxCoord x, wxCoord y )
581{
582 m_logicalOriginX = x * m_signX;
583 m_logicalOriginY = y * m_signY;
584 ComputeScaleAndOrigin();
585}
586
587void wxImplDC::SetDeviceOrigin( wxCoord x, wxCoord y )
588{
589 m_deviceOriginX = x;
590 m_deviceOriginY = y;
591 ComputeScaleAndOrigin();
592}
593
594void wxImplDC::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
595{
596 m_deviceLocalOriginX = x;
597 m_deviceLocalOriginY = y;
598 ComputeScaleAndOrigin();
599}
600
601void wxImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
602{
603 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
604 m_signX = (xLeftRight ? 1 : -1);
605 m_signY = (yBottomUp ? -1 : 1);
606 ComputeScaleAndOrigin();
607}
608
609
610// Each element of the widths array will be the width of the string up to and
611// including the corresponding character in text. This is the generic
612// implementation, the port-specific classes should do this with native APIs
613// if available and if faster. Note: pango_layout_index_to_pos is much slower
614// than calling GetTextExtent!!
615
616#define FWC_SIZE 256
617
618class FontWidthCache
619{
620public:
621 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
622 ~FontWidthCache() { delete []m_widths; }
623
624 void Reset()
625 {
626 if (!m_widths)
627 m_widths = new int[FWC_SIZE];
628
629 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
630 }
631
632 wxFont m_font;
633 double m_scaleX;
634 int *m_widths;
635};
636
637static FontWidthCache s_fontWidthCache;
638
639bool wxImplDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
640{
641 int totalWidth = 0;
642
643 const size_t len = text.length();
644 widths.Empty();
645 widths.Add(0, len);
646
647 // reset the cache if font or horizontal scale have changed
648 if ( !s_fontWidthCache.m_widths ||
649 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
650 (s_fontWidthCache.m_font != GetFont()) )
651 {
652 s_fontWidthCache.Reset();
653 s_fontWidthCache.m_font = GetFont();
654 s_fontWidthCache.m_scaleX = m_scaleX;
655 }
656
657 // Calculate the position of each character based on the widths of
658 // the previous characters
659 int w, h;
660 for ( size_t i = 0; i < len; i++ )
661 {
662 const wxChar c = text[i];
663 unsigned int c_int = (unsigned int)c;
664
665 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
666 {
667 w = s_fontWidthCache.m_widths[c_int];
668 }
669 else
670 {
671 GetTextExtent(c, &w, &h);
672 if (c_int < FWC_SIZE)
673 s_fontWidthCache.m_widths[c_int] = w;
674 }
675
676 totalWidth += w;
677 widths[i] = totalWidth;
678 }
679
680 return true;
681}
682
683void wxImplDC::GetMultiLineTextExtent(const wxString& text,
684 wxCoord *x,
685 wxCoord *y,
686 wxCoord *h,
687 const wxFont *font) const
688{
689 wxCoord widthTextMax = 0, widthLine,
690 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
691
692 wxString curLine;
693 for ( const wxChar *pc = text; ; pc++ )
694 {
695 if ( *pc == _T('\n') || *pc == _T('\0') )
696 {
697 if ( curLine.empty() )
698 {
699 // we can't use GetTextExtent - it will return 0 for both width
700 // and height and an empty line should count in height
701 // calculation
702
703 // assume that this line has the same height as the previous
704 // one
705 if ( !heightLineDefault )
706 heightLineDefault = heightLine;
707
708 if ( !heightLineDefault )
709 {
710 // but we don't know it yet - choose something reasonable
711 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
712 NULL, NULL, font);
713 }
714
715 heightTextTotal += heightLineDefault;
716 }
717 else
718 {
719 DoGetTextExtent(curLine, &widthLine, &heightLine,
720 NULL, NULL, font);
721 if ( widthLine > widthTextMax )
722 widthTextMax = widthLine;
723 heightTextTotal += heightLine;
724 }
725
726 if ( *pc == _T('\n') )
727 {
728 curLine.clear();
729 }
730 else
731 {
732 // the end of string
733 break;
734 }
735 }
736 else
737 {
738 curLine += *pc;
739 }
740 }
741
742 if ( x )
743 *x = widthTextMax;
744 if ( y )
745 *y = heightTextTotal;
746 if ( h )
747 *h = heightLine;
748}
749
750void wxImplDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
751 wxCoord width, wxCoord height)
752{
753 wxCHECK_RET( Ok(), wxT("invalid window dc") );
754
755 wxCoord x2 = x1 + width,
756 y2 = y1 + height;
757
758 // the pen width is calibrated to give 3 for width == height == 10
759 wxDCPenChanger pen(m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
760
761 // we're drawing a scaled version of wx/generic/tick.xpm here
762 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
763 y3 = y1 + height / 2; // y of the left tick branch
764 DoDrawLine(x1, y3, x3, y2);
765 DoDrawLine(x3, y2, x2, y1);
766
767 CalcBoundingBox(x1, y1);
768 CalcBoundingBox(x2, y2);
769}
770
771bool
772wxImplDC::DoStretchBlit(wxCoord xdest, wxCoord ydest,
773 wxCoord dstWidth, wxCoord dstHeight,
774 wxDC *source,
775 wxCoord xsrc, wxCoord ysrc,
776 wxCoord srcWidth, wxCoord srcHeight,
777 int rop,
778 bool useMask,
779 wxCoord xsrcMask,
780 wxCoord ysrcMask)
781{
782 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
783 _T("invalid blit size") );
784
785 // emulate the stretching by modifying the DC scale
786 double xscale = (double)srcWidth/dstWidth,
787 yscale = (double)srcHeight/dstHeight;
788
789 double xscaleOld, yscaleOld;
790 GetUserScale(&xscaleOld, &yscaleOld);
791 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
792
793 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
794 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
795 source,
796 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
797
798 SetUserScale(xscaleOld, yscaleOld);
799
800 return rc;
801}
802
803void wxImplDC::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
804{
805 int n = list->GetCount();
806 wxPoint *points = new wxPoint[n];
807
808 int i = 0;
809 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
810 {
811 wxPoint *point = (wxPoint *)node->GetData();
812 points[i].x = point->x;
813 points[i].y = point->y;
814 }
815
816 DoDrawLines(n, points, xoffset, yoffset);
817
818 delete [] points;
819}
820
821void wxImplDC::DrawPolygon(const wxList *list,
822 wxCoord xoffset, wxCoord yoffset,
823 int fillStyle)
824{
825 int n = list->GetCount();
826 wxPoint *points = new wxPoint[n];
827
828 int i = 0;
829 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
830 {
831 wxPoint *point = (wxPoint *)node->GetData();
832 points[i].x = point->x;
833 points[i].y = point->y;
834 }
835
836 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
837
838 delete [] points;
839}
840
841void
842wxImplDC::DoDrawPolyPolygon(int n,
843 int count[],
844 wxPoint points[],
845 wxCoord xoffset, wxCoord yoffset,
846 int fillStyle)
847{
848 if ( n == 1 )
849 {
850 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
851 return;
852 }
853
854 int i, j, lastOfs;
855 wxPoint* pts;
856 wxPen pen;
857
858 for (i = j = lastOfs = 0; i < n; i++)
859 {
860 lastOfs = j;
861 j += count[i];
862 }
863 pts = new wxPoint[j+n-1];
864 for (i = 0; i < j; i++)
865 pts[i] = points[i];
866 for (i = 2; i <= n; i++)
867 {
868 lastOfs -= count[n-i];
869 pts[j++] = pts[lastOfs];
870 }
871
872 pen = GetPen();
873 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
874 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
875 SetPen(pen);
876 for (i = j = 0; i < n; i++)
877 {
878 DoDrawLines(count[i], pts+j, xoffset, yoffset);
879 j += count[i];
880 }
881 delete[] pts;
882}
883
884#if wxUSE_SPLINES
885
886// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
887void wxImplDC::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
888{
889 wxList point_list;
890
891 wxPoint *point1 = new wxPoint;
892 point1->x = x1; point1->y = y1;
893 point_list.Append((wxObject*)point1);
894
895 wxPoint *point2 = new wxPoint;
896 point2->x = x2; point2->y = y2;
897 point_list.Append((wxObject*)point2);
898
899 wxPoint *point3 = new wxPoint;
900 point3->x = x3; point3->y = y3;
901 point_list.Append((wxObject*)point3);
902
903 DrawSpline(&point_list);
904
905 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
906 {
907 wxPoint *p = (wxPoint *)node->GetData();
908 delete p;
909 }
910}
911
912void wxImplDC::DrawSpline(int n, wxPoint points[])
913{
914 wxList list;
915 for (int i =0; i < n; i++)
916 {
917 list.Append((wxObject*)&points[i]);
918 }
919
920 DrawSpline(&list);
921}
922
923// ----------------------------------- spline code ----------------------------------------
924
925void wx_quadratic_spline(double a1, double b1, double a2, double b2,
926 double a3, double b3, double a4, double b4);
927void wx_clear_stack();
928int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
929 double *y3, double *x4, double *y4);
930void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
931 double x4, double y4);
932static bool wx_spline_add_point(double x, double y);
933static void wx_spline_draw_point_array(wxDCBase *dc);
934
935wxList wx_spline_point_list;
936
937#define half(z1, z2) ((z1+z2)/2.0)
938#define THRESHOLD 5
939
940/* iterative version */
941
942void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
943 double b4)
944{
945 register double xmid, ymid;
946 double x1, y1, x2, y2, x3, y3, x4, y4;
947
948 wx_clear_stack();
949 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
950
951 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
952 xmid = (double)half(x2, x3);
953 ymid = (double)half(y2, y3);
954 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
955 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
956 wx_spline_add_point( x1, y1 );
957 wx_spline_add_point( xmid, ymid );
958 } else {
959 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
960 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
961 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
962 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
963 }
964 }
965}
966
967/* utilities used by spline drawing routines */
968
969typedef struct wx_spline_stack_struct {
970 double x1, y1, x2, y2, x3, y3, x4, y4;
971} Stack;
972
973#define SPLINE_STACK_DEPTH 20
974static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
975static Stack *wx_stack_top;
976static int wx_stack_count;
977
978void wx_clear_stack()
979{
980 wx_stack_top = wx_spline_stack;
981 wx_stack_count = 0;
982}
983
984void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
985{
986 wx_stack_top->x1 = x1;
987 wx_stack_top->y1 = y1;
988 wx_stack_top->x2 = x2;
989 wx_stack_top->y2 = y2;
990 wx_stack_top->x3 = x3;
991 wx_stack_top->y3 = y3;
992 wx_stack_top->x4 = x4;
993 wx_stack_top->y4 = y4;
994 wx_stack_top++;
995 wx_stack_count++;
996}
997
998int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
999 double *x3, double *y3, double *x4, double *y4)
1000{
1001 if (wx_stack_count == 0)
1002 return (0);
1003 wx_stack_top--;
1004 wx_stack_count--;
1005 *x1 = wx_stack_top->x1;
1006 *y1 = wx_stack_top->y1;
1007 *x2 = wx_stack_top->x2;
1008 *y2 = wx_stack_top->y2;
1009 *x3 = wx_stack_top->x3;
1010 *y3 = wx_stack_top->y3;
1011 *x4 = wx_stack_top->x4;
1012 *y4 = wx_stack_top->y4;
1013 return (1);
1014}
1015
1016static bool wx_spline_add_point(double x, double y)
1017{
1018 wxPoint *point = new wxPoint ;
1019 point->x = (int) x;
1020 point->y = (int) y;
1021 wx_spline_point_list.Append((wxObject*)point);
1022 return true;
1023}
1024
1025static void wx_spline_draw_point_array(wxDC *dc)
1026{
1027 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1028 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
1029 while (node)
1030 {
1031 wxPoint *point = (wxPoint *)node->GetData();
1032 delete point;
1033 wx_spline_point_list.Erase(node);
1034 node = wx_spline_point_list.GetFirst();
1035 }
1036}
1037
1038void wxImplDC::DoDrawSpline( wxList *points )
1039{
1040 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1041
1042 wxPoint *p;
1043 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1044 double x1, y1, x2, y2;
1045
1046 wxList::compatibility_iterator node = points->GetFirst();
1047 if (!node)
1048 // empty list
1049 return;
1050
1051 p = (wxPoint *)node->GetData();
1052
1053 x1 = p->x;
1054 y1 = p->y;
1055
1056 node = node->GetNext();
1057 p = (wxPoint *)node->GetData();
1058
1059 x2 = p->x;
1060 y2 = p->y;
1061 cx1 = (double)((x1 + x2) / 2);
1062 cy1 = (double)((y1 + y2) / 2);
1063 cx2 = (double)((cx1 + x2) / 2);
1064 cy2 = (double)((cy1 + y2) / 2);
1065
1066 wx_spline_add_point(x1, y1);
1067
1068 while ((node = node->GetNext())
1069#if !wxUSE_STL
1070 != NULL
1071#endif // !wxUSE_STL
1072 )
1073 {
1074 p = (wxPoint *)node->GetData();
1075 x1 = x2;
1076 y1 = y2;
1077 x2 = p->x;
1078 y2 = p->y;
1079 cx4 = (double)(x1 + x2) / 2;
1080 cy4 = (double)(y1 + y2) / 2;
1081 cx3 = (double)(x1 + cx4) / 2;
1082 cy3 = (double)(y1 + cy4) / 2;
1083
1084 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1085
1086 cx1 = cx4;
1087 cy1 = cy4;
1088 cx2 = (double)(cx1 + x2) / 2;
1089 cy2 = (double)(cy1 + y2) / 2;
1090 }
1091
1092 wx_spline_add_point( cx1, cy1 );
1093 wx_spline_add_point( x2, y2 );
1094
1095 wx_spline_draw_point_array( m_owner );
1096}
1097
1098#endif // wxUSE_SPLINES
1099
1100
1101void wxImplDC::DrawLabel(const wxString& text,
1102 const wxBitmap& bitmap,
1103 const wxRect& rect,
1104 int alignment,
1105 int indexAccel,
1106 wxRect *rectBounding)
1107{
1108 // find the text position
1109 wxCoord widthText, heightText, heightLine;
1110 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1111
1112 wxCoord width, height;
1113 if ( bitmap.Ok() )
1114 {
1115 width = widthText + bitmap.GetWidth();
1116 height = bitmap.GetHeight();
1117 }
1118 else // no bitmap
1119 {
1120 width = widthText;
1121 height = heightText;
1122 }
1123
1124 wxCoord x, y;
1125 if ( alignment & wxALIGN_RIGHT )
1126 {
1127 x = rect.GetRight() - width;
1128 }
1129 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1130 {
1131 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1132 }
1133 else // alignment & wxALIGN_LEFT
1134 {
1135 x = rect.GetLeft();
1136 }
1137
1138 if ( alignment & wxALIGN_BOTTOM )
1139 {
1140 y = rect.GetBottom() - height;
1141 }
1142 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1143 {
1144 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1145 }
1146 else // alignment & wxALIGN_TOP
1147 {
1148 y = rect.GetTop();
1149 }
1150
1151 // draw the bitmap first
1152 wxCoord x0 = x,
1153 y0 = y,
1154 width0 = width;
1155 if ( bitmap.Ok() )
1156 {
1157 DoDrawBitmap(bitmap, x, y, true /* use mask */);
1158
1159 wxCoord offset = bitmap.GetWidth() + 4;
1160 x += offset;
1161 width -= offset;
1162
1163 y += (height - heightText) / 2;
1164 }
1165
1166 // we will draw the underscore under the accel char later
1167 wxCoord startUnderscore = 0,
1168 endUnderscore = 0,
1169 yUnderscore = 0;
1170
1171 // split the string into lines and draw each of them separately
1172 wxString curLine;
1173 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1174 {
1175 if ( *pc == _T('\n') || pc == text.end() )
1176 {
1177 int xRealStart = x; // init it here to avoid compielr warnings
1178
1179 if ( !curLine.empty() )
1180 {
1181 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1182 // wxALIGN_LEFT is 0
1183 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1184 {
1185 wxCoord widthLine;
1186 m_owner->GetTextExtent(curLine, &widthLine, NULL);
1187
1188 if ( alignment & wxALIGN_RIGHT )
1189 {
1190 xRealStart += width - widthLine;
1191 }
1192 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1193 {
1194 xRealStart += (width - widthLine) / 2;
1195 }
1196 }
1197 //else: left aligned, nothing to do
1198
1199 DoDrawText(curLine, xRealStart, y);
1200 }
1201
1202 y += heightLine;
1203
1204 // do we have underscore in this line? we can check yUnderscore
1205 // because it is set below to just y + heightLine if we do
1206 if ( y == yUnderscore )
1207 {
1208 // adjust the horz positions to account for the shift
1209 startUnderscore += xRealStart;
1210 endUnderscore += xRealStart;
1211 }
1212
1213 if ( pc == text.end() )
1214 break;
1215
1216 curLine.clear();
1217 }
1218 else // not end of line
1219 {
1220 if ( pc - text.begin() == indexAccel )
1221 {
1222 // remeber to draw underscore here
1223 GetTextExtent(curLine, &startUnderscore, NULL);
1224 curLine += *pc;
1225 GetTextExtent(curLine, &endUnderscore, NULL);
1226
1227 yUnderscore = y + heightLine;
1228 }
1229 else
1230 {
1231 curLine += *pc;
1232 }
1233 }
1234 }
1235
1236 // draw the underscore if found
1237 if ( startUnderscore != endUnderscore )
1238 {
1239 // it should be of the same colour as text
1240 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1241
1242 yUnderscore--;
1243
1244 DoDrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1245 }
1246
1247 // return bounding rect if requested
1248 if ( rectBounding )
1249 {
1250 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1251 }
1252
1253 CalcBoundingBox(x0, y0);
1254 CalcBoundingBox(x0 + width0, y0 + height);
1255}
1256
1257
1258void wxImplDC::DoGradientFillLinear(const wxRect& rect,
1259 const wxColour& initialColour,
1260 const wxColour& destColour,
1261 wxDirection nDirection)
1262{
1263 // save old pen
1264 wxPen oldPen = m_pen;
1265 wxBrush oldBrush = m_brush;
1266
1267 wxUint8 nR1 = initialColour.Red();
1268 wxUint8 nG1 = initialColour.Green();
1269 wxUint8 nB1 = initialColour.Blue();
1270 wxUint8 nR2 = destColour.Red();
1271 wxUint8 nG2 = destColour.Green();
1272 wxUint8 nB2 = destColour.Blue();
1273 wxUint8 nR, nG, nB;
1274
1275 if ( nDirection == wxEAST || nDirection == wxWEST )
1276 {
1277 wxInt32 x = rect.GetWidth();
1278 wxInt32 w = x; // width of area to shade
1279 wxInt32 xDelta = w/256; // height of one shade bend
1280 if (xDelta < 1)
1281 xDelta = 1;
1282
1283 while (x >= xDelta)
1284 {
1285 x -= xDelta;
1286 if (nR1 > nR2)
1287 nR = nR1 - (nR1-nR2)*(w-x)/w;
1288 else
1289 nR = nR1 + (nR2-nR1)*(w-x)/w;
1290
1291 if (nG1 > nG2)
1292 nG = nG1 - (nG1-nG2)*(w-x)/w;
1293 else
1294 nG = nG1 + (nG2-nG1)*(w-x)/w;
1295
1296 if (nB1 > nB2)
1297 nB = nB1 - (nB1-nB2)*(w-x)/w;
1298 else
1299 nB = nB1 + (nB2-nB1)*(w-x)/w;
1300
1301 wxColour colour(nR,nG,nB);
1302 SetPen(wxPen(colour, 1, wxSOLID));
1303 SetBrush(wxBrush(colour));
1304 if(nDirection == wxEAST)
1305 DoDrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(),
1306 xDelta, rect.GetHeight());
1307 else //nDirection == wxWEST
1308 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1309 xDelta, rect.GetHeight());
1310 }
1311 }
1312 else // nDirection == wxNORTH || nDirection == wxSOUTH
1313 {
1314 wxInt32 y = rect.GetHeight();
1315 wxInt32 w = y; // height of area to shade
1316 wxInt32 yDelta = w/255; // height of one shade bend
1317 if (yDelta < 1)
1318 yDelta = 1;
1319
1320 while (y > 0)
1321 {
1322 y -= yDelta;
1323 if (nR1 > nR2)
1324 nR = nR1 - (nR1-nR2)*(w-y)/w;
1325 else
1326 nR = nR1 + (nR2-nR1)*(w-y)/w;
1327
1328 if (nG1 > nG2)
1329 nG = nG1 - (nG1-nG2)*(w-y)/w;
1330 else
1331 nG = nG1 + (nG2-nG1)*(w-y)/w;
1332
1333 if (nB1 > nB2)
1334 nB = nB1 - (nB1-nB2)*(w-y)/w;
1335 else
1336 nB = nB1 + (nB2-nB1)*(w-y)/w;
1337
1338 wxColour colour(nR,nG,nB);
1339 SetPen(wxPen(colour, 1, wxSOLID));
1340 SetBrush(wxBrush(colour));
1341 if(nDirection == wxNORTH)
1342 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1343 rect.GetWidth(), yDelta);
1344 else //nDirection == wxSOUTH
1345 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta,
1346 rect.GetWidth(), yDelta);
1347 }
1348 }
1349
1350 SetPen(oldPen);
1351 SetBrush(oldBrush);
1352}
1353
1354void wxImplDC::DoGradientFillConcentric(const wxRect& rect,
1355 const wxColour& initialColour,
1356 const wxColour& destColour,
1357 const wxPoint& circleCenter)
1358{
1359 //save the old pen color
1360 wxColour oldPenColour = m_pen.GetColour();
1361
1362 wxUint8 nR1 = destColour.Red();
1363 wxUint8 nG1 = destColour.Green();
1364 wxUint8 nB1 = destColour.Blue();
1365 wxUint8 nR2 = initialColour.Red();
1366 wxUint8 nG2 = initialColour.Green();
1367 wxUint8 nB2 = initialColour.Blue();
1368 wxUint8 nR, nG, nB;
1369
1370
1371 //Radius
1372 wxInt32 cx = rect.GetWidth() / 2;
1373 wxInt32 cy = rect.GetHeight() / 2;
1374 wxInt32 nRadius;
1375 if (cx < cy)
1376 nRadius = cx;
1377 else
1378 nRadius = cy;
1379
1380 //Offset of circle
1381 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1382 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1383
1384 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1385 {
1386 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1387 {
1388 //get color difference
1389 wxInt32 nGradient = ((nRadius -
1390 (wxInt32)sqrt(
1391 pow((double)(x - cx - nCircleOffX), 2) +
1392 pow((double)(y - cy - nCircleOffY), 2)
1393 )) * 100) / nRadius;
1394
1395 //normalize Gradient
1396 if (nGradient < 0 )
1397 nGradient = 0;
1398
1399 //get dest colors
1400 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1401 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1402 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1403
1404 //set the pixel
1405 m_pen.SetColour(wxColour(nR,nG,nB));
1406 DoDrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
1407 }
1408 }
1409 //return old pen color
1410 m_pen.SetColour(oldPenColour);
1411}
1412
1413//-----------------------------------------------------------------------------
1414// wxDC
1415//-----------------------------------------------------------------------------
1416
1417IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1418
1419#if WXWIN_COMPATIBILITY_2_8
1420 // for compatibility with the old code when wxCoord was long everywhere
1421void wxDC::GetTextExtent(const wxString& string,
1422 long *x, long *y,
1423 long *descent,
1424 long *externalLeading,
1425 const wxFont *theFont) const
1426 {
1427 wxCoord x2, y2, descent2, externalLeading2;
1428 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1429 &descent2, &externalLeading2,
1430 theFont);
1431 if ( x )
1432 *x = x2;
1433 if ( y )
1434 *y = y2;
1435 if ( descent )
1436 *descent = descent2;
1437 if ( externalLeading )
1438 *externalLeading = externalLeading2;
1439 }
1440
1441void wxDC::GetLogicalOrigin(long *x, long *y) const
1442 {
1443 wxCoord x2, y2;
1444 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1445 if ( x )
1446 *x = x2;
1447 if ( y )
1448 *y = y2;
1449 }
1450
1451void wxDC::GetDeviceOrigin(long *x, long *y) const
1452 {
1453 wxCoord x2, y2;
1454 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1455 if ( x )
1456 *x = x2;
1457 if ( y )
1458 *y = y2;
1459 }
1460
1461void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1462 {
1463 wxCoord xx,yy,ww,hh;
1464 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1465 if (x) *x = xx;
1466 if (y) *y = yy;
1467 if (w) *w = ww;
1468 if (h) *h = hh;
1469 }
1470
1471#endif // WXWIN_COMPATIBILITY_2_8
1472
1473
1474#else // wxUSE_NEW_DC
1475
1476
68379eaf 1477// bool wxDCBase::sm_cacheing = false;
0cbff120 1478
e7445ff8
PC
1479IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
1480
1e6feb95
VZ
1481// ============================================================================
1482// implementation
1483// ============================================================================
1484
653752be
MB
1485IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
1486IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
1487
04ab8b6d
RR
1488wxDCBase::wxDCBase()
1489 : m_colour(wxColourDisplay())
1490 , m_ok(true)
1491 , m_clipping(false)
1492 , m_isInteractive(0)
1493 , m_isBBoxValid(false)
1494 , m_logicalOriginX(0), m_logicalOriginY(0)
1495 , m_deviceOriginX(0), m_deviceOriginY(0)
1496 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1497 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1498 , m_userScaleX(1.0), m_userScaleY(1.0)
1499 , m_scaleX(1.0), m_scaleY(1.0)
1500 , m_signX(1), m_signY(1)
1501 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1502 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1503 , m_logicalFunction(wxCOPY)
1504 , m_backgroundMode(wxTRANSPARENT)
1505 , m_mappingMode(wxMM_TEXT)
1506 , m_pen()
1507 , m_brush()
1508 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
1509 , m_textForegroundColour(*wxBLACK)
1510 , m_textBackgroundColour(*wxWHITE)
1511 , m_font()
1512#if wxUSE_PALETTE
1513 , m_palette()
1514 , m_hasCustomPalette(false)
1515#endif // wxUSE_PALETTE
1516{
1517 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
1518 (double)wxGetDisplaySizeMM().GetWidth();
1519 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
1520 (double)wxGetDisplaySizeMM().GetHeight();
1521
1522 ResetBoundingBox();
1523 ResetClipping();
1524}
1525
1526wxDCBase::~wxDCBase()
1527{
1528}
1529
68df211f
JG
1530#if WXWIN_COMPATIBILITY_2_6
1531void wxDCBase::BeginDrawing()
1532{
1533}
1534
1535void wxDCBase::EndDrawing()
1536{
1537}
1538#endif // WXWIN_COMPATIBILITY_2_6
1539
cfa87e81
RR
1540#if WXWIN_COMPATIBILITY_2_8
1541 // for compatibility with the old code when wxCoord was long everywhere
1542void wxDCBase::GetTextExtent(const wxString& string,
1543 long *x, long *y,
27ee942f
PC
1544 long *descent,
1545 long *externalLeading,
1546 const wxFont *theFont) const
cfa87e81
RR
1547 {
1548 wxCoord x2, y2, descent2, externalLeading2;
1549 DoGetTextExtent(string, &x2, &y2,
1550 &descent2, &externalLeading2,
1551 theFont);
1552 if ( x )
1553 *x = x2;
1554 if ( y )
1555 *y = y2;
1556 if ( descent )
1557 *descent = descent2;
1558 if ( externalLeading )
1559 *externalLeading = externalLeading2;
1560 }
1561
1562void wxDCBase::GetLogicalOrigin(long *x, long *y) const
1563 {
1564 wxCoord x2, y2;
1565 DoGetLogicalOrigin(&x2, &y2);
1566 if ( x )
1567 *x = x2;
1568 if ( y )
1569 *y = y2;
1570 }
1571
1572void wxDCBase::GetDeviceOrigin(long *x, long *y) const
1573 {
1574 wxCoord x2, y2;
1575 DoGetDeviceOrigin(&x2, &y2);
1576 if ( x )
1577 *x = x2;
1578 if ( y )
1579 *y = y2;
1580 }
1581
1582void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const
1583 {
1584 wxCoord xx,yy,ww,hh;
1585 DoGetClippingBox(&xx, &yy, &ww, &hh);
1586 if (x) *x = xx;
1587 if (y) *y = yy;
1588 if (w) *w = ww;
1589 if (h) *h = hh;
1590 }
1591#endif // WXWIN_COMPATIBILITY_2_8
1592
1593
1594
04ab8b6d
RR
1595// ----------------------------------------------------------------------------
1596// coordinate conversions and transforms
1597// ----------------------------------------------------------------------------
1598
1599wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1600{
1601 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
1602}
1603
1604wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1605{
1606 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
1607}
1608
1609wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1610{
1611 return wxRound((double)(x) / m_scaleX);
1612}
1613
1614wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1615{
1616 return wxRound((double)(y) / m_scaleY);
1617}
1618
1619wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1620{
1621 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
1622}
1623
1624wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1625{
1626 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
1627}
1628
1629wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1630{
1631 return wxRound((double)(x) * m_scaleX);
1632}
1633
1634wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1635{
1636 return wxRound((double)(y) * m_scaleY);
1637}
1638
1639void wxDCBase::ComputeScaleAndOrigin()
1640{
1641 m_scaleX = m_logicalScaleX * m_userScaleX;
1642 m_scaleY = m_logicalScaleY * m_userScaleY;
1643}
1644
1645void wxDCBase::SetMapMode( int mode )
1646{
1647 switch (mode)
1648 {
1649 case wxMM_TWIPS:
1650 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
1651 break;
1652 case wxMM_POINTS:
1653 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
1654 break;
1655 case wxMM_METRIC:
1656 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1657 break;
1658 case wxMM_LOMETRIC:
1659 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
1660 break;
1661 default:
1662 case wxMM_TEXT:
1663 SetLogicalScale( 1.0, 1.0 );
1664 break;
1665 }
1666 m_mappingMode = mode;
1667}
1668
1669void wxDCBase::SetUserScale( double x, double y )
1670{
1671 // allow negative ? -> no
1672 m_userScaleX = x;
1673 m_userScaleY = y;
1674 ComputeScaleAndOrigin();
1675}
1676
1677void wxDCBase::SetLogicalScale( double x, double y )
1678{
1679 // allow negative ?
1680 m_logicalScaleX = x;
1681 m_logicalScaleY = y;
1682 ComputeScaleAndOrigin();
1683}
1684
1685void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
1686{
1687 m_logicalOriginX = x * m_signX;
1688 m_logicalOriginY = y * m_signY;
1689 ComputeScaleAndOrigin();
1690}
1691
1692void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
1693{
1694 m_deviceOriginX = x;
1695 m_deviceOriginY = y;
1696 ComputeScaleAndOrigin();
1697}
1698
1699void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
1700{
1701 m_deviceLocalOriginX = x;
1702 m_deviceLocalOriginY = y;
1703 ComputeScaleAndOrigin();
1704}
1705
1706void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1707{
1708 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1709 m_signX = (xLeftRight ? 1 : -1);
1710 m_signY = (yBottomUp ? -1 : 1);
1711 ComputeScaleAndOrigin();
1712}
1713
1e6feb95
VZ
1714// ----------------------------------------------------------------------------
1715// special symbols
1716// ----------------------------------------------------------------------------
1717
cd9da200
VZ
1718void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
1719 wxCoord width, wxCoord height)
1720{
1721 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1722
1723 wxCoord x2 = x1 + width,
1724 y2 = y1 + height;
1725
860a4018
VZ
1726 // the pen width is calibrated to give 3 for width == height == 10
1727 wxDCPenChanger pen((wxDC&)*this,
1728 wxPen(GetTextForeground(), (width + height + 1)/7));
cd9da200
VZ
1729
1730 // we're drawing a scaled version of wx/generic/tick.xpm here
1731 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
1732 y3 = y1 + height / 2; // y of the left tick branch
1733 DoDrawLine(x1, y3, x3, y2);
1734 DoDrawLine(x3, y2, x2, y1);
1735
1736 CalcBoundingBox(x1, y1);
1737 CalcBoundingBox(x2, y2);
1738}
1739
e3b81044
VZ
1740// ----------------------------------------------------------------------------
1741// stubs for functions not implemented in all ports
1742// ----------------------------------------------------------------------------
1743
1744bool
1745wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
1746 wxCoord dstWidth, wxCoord dstHeight,
1747 wxDC *source,
1748 wxCoord xsrc, wxCoord ysrc,
ce2fe5bc 1749 wxCoord srcWidth, wxCoord srcHeight,
e3b81044
VZ
1750 int rop,
1751 bool useMask,
1752 wxCoord xsrcMask,
1753 wxCoord ysrcMask)
1754{
ce2fe5bc
VZ
1755 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
1756 _T("invalid blit size") );
1757
1758 // emulate the stretching by modifying the DC scale
1759 double xscale = (double)srcWidth/dstWidth,
1760 yscale = (double)srcHeight/dstHeight;
1761
1762 double xscaleOld, yscaleOld;
1763 GetUserScale(&xscaleOld, &yscaleOld);
1764 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
1765
1766 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
1767 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
1768 source,
1769 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
1770
1771 SetUserScale(xscaleOld, yscaleOld);
1772
1773 return rc;
e3b81044
VZ
1774}
1775
1e6feb95
VZ
1776// ----------------------------------------------------------------------------
1777// line/polygons
1778// ----------------------------------------------------------------------------
1779
72cdf4c9 1780void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
dbe94982 1781{
b1d4dd7a 1782 int n = list->GetCount();
dbe94982
BM
1783 wxPoint *points = new wxPoint[n];
1784
1785 int i = 0;
222ed1d6 1786 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1787 {
b1d4dd7a 1788 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
1789 points[i].x = point->x;
1790 points[i].y = point->y;
1791 }
1792
1793 DoDrawLines(n, points, xoffset, yoffset);
1794
1795 delete [] points;
1796}
1797
1798
1799void wxDCBase::DrawPolygon(const wxList *list,
72cdf4c9 1800 wxCoord xoffset, wxCoord yoffset,
dbe94982
BM
1801 int fillStyle)
1802{
b1d4dd7a 1803 int n = list->GetCount();
dbe94982
BM
1804 wxPoint *points = new wxPoint[n];
1805
1806 int i = 0;
222ed1d6 1807 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1808 {
b1d4dd7a 1809 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
1810 points[i].x = point->x;
1811 points[i].y = point->y;
1812 }
1813
1814 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1815
1816 delete [] points;
1817}
1818
63b9e659
VZ
1819void
1820wxDCBase::DoDrawPolyPolygon(int n,
793db755 1821 int count[],
63b9e659
VZ
1822 wxPoint points[],
1823 wxCoord xoffset, wxCoord yoffset,
1824 int fillStyle)
1825{
1826 if ( n == 1 )
1827 {
793db755 1828 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
63b9e659
VZ
1829 return;
1830 }
1831
1832 int i, j, lastOfs;
1833 wxPoint* pts;
1834 wxPen pen;
1835
1836 for (i = j = lastOfs = 0; i < n; i++)
1837 {
1838 lastOfs = j;
793db755 1839 j += count[i];
63b9e659
VZ
1840 }
1841 pts = new wxPoint[j+n-1];
1842 for (i = 0; i < j; i++)
1843 pts[i] = points[i];
1844 for (i = 2; i <= n; i++)
1845 {
793db755 1846 lastOfs -= count[n-i];
63b9e659
VZ
1847 pts[j++] = pts[lastOfs];
1848 }
1849
1850 pen = GetPen();
1851 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
1852 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
1853 SetPen(pen);
1854 for (i = j = 0; i < n; i++)
1855 {
793db755
VZ
1856 DoDrawLines(count[i], pts+j, xoffset, yoffset);
1857 j += count[i];
63b9e659 1858 }
6db1f43b 1859 delete[] pts;
63b9e659
VZ
1860}
1861
1e6feb95
VZ
1862// ----------------------------------------------------------------------------
1863// splines
1864// ----------------------------------------------------------------------------
dbe94982 1865
88ac883a 1866#if wxUSE_SPLINES
dbe94982
BM
1867
1868// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
72cdf4c9 1869void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
dbe94982
BM
1870{
1871 wxList point_list;
1872
1873 wxPoint *point1 = new wxPoint;
1874 point1->x = x1; point1->y = y1;
1875 point_list.Append((wxObject*)point1);
1876
1877 wxPoint *point2 = new wxPoint;
1878 point2->x = x2; point2->y = y2;
1879 point_list.Append((wxObject*)point2);
1880
1881 wxPoint *point3 = new wxPoint;
1882 point3->x = x3; point3->y = y3;
1883 point_list.Append((wxObject*)point3);
1884
1885 DrawSpline(&point_list);
1886
222ed1d6 1887 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
dbe94982 1888 {
b1d4dd7a 1889 wxPoint *p = (wxPoint *)node->GetData();
dbe94982
BM
1890 delete p;
1891 }
1892}
1893
1894void wxDCBase::DrawSpline(int n, wxPoint points[])
1895{
1896 wxList list;
1897 for (int i =0; i < n; i++)
1898 {
1899 list.Append((wxObject*)&points[i]);
1900 }
1901
1902 DrawSpline(&list);
1903}
1904
fe2e4366
VS
1905// ----------------------------------- spline code ----------------------------------------
1906
1907void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1908 double a3, double b3, double a4, double b4);
1909void wx_clear_stack();
1910int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1911 double *y3, double *x4, double *y4);
1912void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1913 double x4, double y4);
1914static bool wx_spline_add_point(double x, double y);
1915static void wx_spline_draw_point_array(wxDCBase *dc);
1916
1917wxList wx_spline_point_list;
1918
1919#define half(z1, z2) ((z1+z2)/2.0)
1920#define THRESHOLD 5
1921
1922/* iterative version */
1923
1924void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1925 double b4)
1926{
1927 register double xmid, ymid;
1928 double x1, y1, x2, y2, x3, y3, x4, y4;
1929
1930 wx_clear_stack();
1931 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1932
1933 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1934 xmid = (double)half(x2, x3);
1935 ymid = (double)half(y2, y3);
1936 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1937 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1938 wx_spline_add_point( x1, y1 );
1939 wx_spline_add_point( xmid, ymid );
1940 } else {
1941 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1942 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1943 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1944 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1945 }
1946 }
1947}
1948
1949/* utilities used by spline drawing routines */
1950
1951typedef struct wx_spline_stack_struct {
1952 double x1, y1, x2, y2, x3, y3, x4, y4;
1953} Stack;
1954
1955#define SPLINE_STACK_DEPTH 20
1956static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1957static Stack *wx_stack_top;
1958static int wx_stack_count;
1959
1960void wx_clear_stack()
1961{
1962 wx_stack_top = wx_spline_stack;
1963 wx_stack_count = 0;
1964}
1965
1966void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1967{
1968 wx_stack_top->x1 = x1;
1969 wx_stack_top->y1 = y1;
1970 wx_stack_top->x2 = x2;
1971 wx_stack_top->y2 = y2;
1972 wx_stack_top->x3 = x3;
1973 wx_stack_top->y3 = y3;
1974 wx_stack_top->x4 = x4;
1975 wx_stack_top->y4 = y4;
1976 wx_stack_top++;
1977 wx_stack_count++;
1978}
1979
1980int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1981 double *x3, double *y3, double *x4, double *y4)
1982{
1983 if (wx_stack_count == 0)
1984 return (0);
1985 wx_stack_top--;
1986 wx_stack_count--;
1987 *x1 = wx_stack_top->x1;
1988 *y1 = wx_stack_top->y1;
1989 *x2 = wx_stack_top->x2;
1990 *y2 = wx_stack_top->y2;
1991 *x3 = wx_stack_top->x3;
1992 *y3 = wx_stack_top->y3;
1993 *x4 = wx_stack_top->x4;
1994 *y4 = wx_stack_top->y4;
1995 return (1);
1996}
1997
1998static bool wx_spline_add_point(double x, double y)
1999{
2000 wxPoint *point = new wxPoint ;
2001 point->x = (int) x;
2002 point->y = (int) y;
2003 wx_spline_point_list.Append((wxObject*)point);
68379eaf 2004 return true;
fe2e4366
VS
2005}
2006
2007static void wx_spline_draw_point_array(wxDCBase *dc)
2008{
2009 dc->DrawLines(&wx_spline_point_list, 0, 0 );
222ed1d6 2010 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
fe2e4366
VS
2011 while (node)
2012 {
b1d4dd7a 2013 wxPoint *point = (wxPoint *)node->GetData();
fe2e4366 2014 delete point;
222ed1d6 2015 wx_spline_point_list.Erase(node);
b1d4dd7a 2016 node = wx_spline_point_list.GetFirst();
fe2e4366
VS
2017 }
2018}
2019
2020void wxDCBase::DoDrawSpline( wxList *points )
2021{
2022 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2023
2024 wxPoint *p;
2025 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2026 double x1, y1, x2, y2;
2027
222ed1d6 2028 wxList::compatibility_iterator node = points->GetFirst();
ef419e3b 2029 if (!node)
410bb8c1
RD
2030 // empty list
2031 return;
e0d31471 2032
b1d4dd7a 2033 p = (wxPoint *)node->GetData();
fe2e4366
VS
2034
2035 x1 = p->x;
2036 y1 = p->y;
2037
b1d4dd7a
RL
2038 node = node->GetNext();
2039 p = (wxPoint *)node->GetData();
fe2e4366
VS
2040
2041 x2 = p->x;
2042 y2 = p->y;
2043 cx1 = (double)((x1 + x2) / 2);
2044 cy1 = (double)((y1 + y2) / 2);
2045 cx2 = (double)((cx1 + x2) / 2);
2046 cy2 = (double)((cy1 + y2) / 2);
2047
2048 wx_spline_add_point(x1, y1);
2049
28b4db7f
VZ
2050 while ((node = node->GetNext())
2051#if !wxUSE_STL
2052 != NULL
2053#endif // !wxUSE_STL
2054 )
fe2e4366 2055 {
b1d4dd7a 2056 p = (wxPoint *)node->GetData();
fe2e4366
VS
2057 x1 = x2;
2058 y1 = y2;
2059 x2 = p->x;
2060 y2 = p->y;
2061 cx4 = (double)(x1 + x2) / 2;
2062 cy4 = (double)(y1 + y2) / 2;
2063 cx3 = (double)(x1 + cx4) / 2;
2064 cy3 = (double)(y1 + cy4) / 2;
2065
2066 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
2067
2068 cx1 = cx4;
2069 cy1 = cy4;
2070 cx2 = (double)(cx1 + x2) / 2;
2071 cy2 = (double)(cy1 + y2) / 2;
2072 }
2073
2074 wx_spline_add_point( cx1, cy1 );
2075 wx_spline_add_point( x2, y2 );
2076
2077 wx_spline_draw_point_array( this );
2078}
2079
88ac883a 2080#endif // wxUSE_SPLINES
1e6feb95 2081
0919e93e
RD
2082// ----------------------------------------------------------------------------
2083// Partial Text Extents
2084// ----------------------------------------------------------------------------
2085
2086
174ee1b3 2087// Each element of the widths array will be the width of the string up to and
3103e8a9 2088// including the corresponding character in text. This is the generic
0919e93e 2089// implementation, the port-specific classes should do this with native APIs
174ee1b3
RD
2090// if available and if faster. Note: pango_layout_index_to_pos is much slower
2091// than calling GetTextExtent!!
2092
06fe86b7 2093#define FWC_SIZE 256
174ee1b3
RD
2094
2095class FontWidthCache
2096{
2097public:
2098 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
2099 ~FontWidthCache() { delete []m_widths; }
2aaa050c
VZ
2100
2101 void Reset()
2102 {
2103 if (!m_widths)
2104 m_widths = new int[FWC_SIZE];
2105
2106 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
2107 }
2108
174ee1b3
RD
2109 wxFont m_font;
2110 double m_scaleX;
2111 int *m_widths;
2112};
2113
2114static FontWidthCache s_fontWidthCache;
0919e93e
RD
2115
2116bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2117{
2118 int totalWidth = 0;
0919e93e 2119
18680f86 2120 const size_t len = text.length();
0919e93e 2121 widths.Empty();
174ee1b3 2122 widths.Add(0, len);
2aaa050c 2123
174ee1b3 2124 // reset the cache if font or horizontal scale have changed
c77a6796
VZ
2125 if ( !s_fontWidthCache.m_widths ||
2126 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
2127 (s_fontWidthCache.m_font != GetFont()) )
174ee1b3
RD
2128 {
2129 s_fontWidthCache.Reset();
2130 s_fontWidthCache.m_font = GetFont();
2131 s_fontWidthCache.m_scaleX = m_scaleX;
2132 }
2133
0919e93e
RD
2134 // Calculate the position of each character based on the widths of
2135 // the previous characters
c77a6796
VZ
2136 int w, h;
2137 for ( size_t i = 0; i < len; i++ )
174ee1b3
RD
2138 {
2139 const wxChar c = text[i];
2140 unsigned int c_int = (unsigned int)c;
2141
2aaa050c 2142 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
174ee1b3
RD
2143 {
2144 w = s_fontWidthCache.m_widths[c_int];
2145 }
2aaa050c 2146 else
174ee1b3
RD
2147 {
2148 GetTextExtent(c, &w, &h);
2149 if (c_int < FWC_SIZE)
2150 s_fontWidthCache.m_widths[c_int] = w;
2151 }
2152
0919e93e
RD
2153 totalWidth += w;
2154 widths[i] = totalWidth;
2155 }
2aaa050c 2156
0919e93e
RD
2157 return true;
2158}
2159
2160
1e6feb95
VZ
2161// ----------------------------------------------------------------------------
2162// enhanced text drawing
2163// ----------------------------------------------------------------------------
2164
2165void wxDCBase::GetMultiLineTextExtent(const wxString& text,
2166 wxCoord *x,
2167 wxCoord *y,
2168 wxCoord *h,
c94f845b 2169 const wxFont *font) const
1e6feb95 2170{
c7aaa64f
VS
2171 wxCoord widthTextMax = 0, widthLine,
2172 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
1e6feb95
VZ
2173
2174 wxString curLine;
2175 for ( const wxChar *pc = text; ; pc++ )
2176 {
2177 if ( *pc == _T('\n') || *pc == _T('\0') )
2178 {
2179 if ( curLine.empty() )
2180 {
2181 // we can't use GetTextExtent - it will return 0 for both width
2182 // and height and an empty line should count in height
2183 // calculation
2184
2185 // assume that this line has the same height as the previous
2186 // one
2187 if ( !heightLineDefault )
2188 heightLineDefault = heightLine;
2189
2190 if ( !heightLineDefault )
2191 {
2192 // but we don't know it yet - choose something reasonable
2193 GetTextExtent(_T("W"), NULL, &heightLineDefault,
2194 NULL, NULL, font);
2195 }
2196
2197 heightTextTotal += heightLineDefault;
2198 }
2199 else
2200 {
2201 GetTextExtent(curLine, &widthLine, &heightLine,
2202 NULL, NULL, font);
2203 if ( widthLine > widthTextMax )
2204 widthTextMax = widthLine;
2205 heightTextTotal += heightLine;
2206 }
2207
2208 if ( *pc == _T('\n') )
2209 {
2210 curLine.clear();
2211 }
2212 else
2213 {
2214 // the end of string
2215 break;
2216 }
2217 }
2218 else
2219 {
2220 curLine += *pc;
2221 }
2222 }
2223
2224 if ( x )
2225 *x = widthTextMax;
2226 if ( y )
2227 *y = heightTextTotal;
2228 if ( h )
2229 *h = heightLine;
2230}
2231
2232void wxDCBase::DrawLabel(const wxString& text,
2233 const wxBitmap& bitmap,
2234 const wxRect& rect,
2235 int alignment,
2236 int indexAccel,
2237 wxRect *rectBounding)
2238{
2239 // find the text position
2240 wxCoord widthText, heightText, heightLine;
2241 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
2242
2243 wxCoord width, height;
2244 if ( bitmap.Ok() )
2245 {
2246 width = widthText + bitmap.GetWidth();
2247 height = bitmap.GetHeight();
2248 }
2249 else // no bitmap
2250 {
2251 width = widthText;
2252 height = heightText;
2253 }
2254
2255 wxCoord x, y;
2256 if ( alignment & wxALIGN_RIGHT )
2257 {
2258 x = rect.GetRight() - width;
2259 }
2260 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2261 {
2262 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
2263 }
2264 else // alignment & wxALIGN_LEFT
2265 {
2266 x = rect.GetLeft();
2267 }
2268
2269 if ( alignment & wxALIGN_BOTTOM )
2270 {
2271 y = rect.GetBottom() - height;
2272 }
2273 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
2274 {
2275 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
2276 }
2277 else // alignment & wxALIGN_TOP
2278 {
2279 y = rect.GetTop();
2280 }
2281
2282 // draw the bitmap first
2283 wxCoord x0 = x,
2284 y0 = y,
2285 width0 = width;
2286 if ( bitmap.Ok() )
2287 {
68379eaf 2288 DrawBitmap(bitmap, x, y, true /* use mask */);
1e6feb95
VZ
2289
2290 wxCoord offset = bitmap.GetWidth() + 4;
2291 x += offset;
2292 width -= offset;
2293
2294 y += (height - heightText) / 2;
2295 }
2296
2297 // we will draw the underscore under the accel char later
2298 wxCoord startUnderscore = 0,
2299 endUnderscore = 0,
2300 yUnderscore = 0;
2301
2302 // split the string into lines and draw each of them separately
2303 wxString curLine;
c9f78968 2304 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2305 {
c9f78968 2306 if ( *pc == _T('\n') || pc == text.end() )
1e6feb95
VZ
2307 {
2308 int xRealStart = x; // init it here to avoid compielr warnings
2309
2310 if ( !curLine.empty() )
2311 {
2312 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2313 // wxALIGN_LEFT is 0
2314 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
2315 {
2316 wxCoord widthLine;
2317 GetTextExtent(curLine, &widthLine, NULL);
2318
2319 if ( alignment & wxALIGN_RIGHT )
2320 {
2321 xRealStart += width - widthLine;
2322 }
2323 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2324 {
2325 xRealStart += (width - widthLine) / 2;
2326 }
2327 }
2328 //else: left aligned, nothing to do
2329
2330 DrawText(curLine, xRealStart, y);
2331 }
2332
2333 y += heightLine;
2334
2335 // do we have underscore in this line? we can check yUnderscore
2336 // because it is set below to just y + heightLine if we do
2337 if ( y == yUnderscore )
2338 {
2339 // adjust the horz positions to account for the shift
2340 startUnderscore += xRealStart;
2341 endUnderscore += xRealStart;
2342 }
2343
c9f78968 2344 if ( pc == text.end() )
1e6feb95
VZ
2345 break;
2346
2347 curLine.clear();
2348 }
2349 else // not end of line
2350 {
9daaea28 2351 if ( pc - text.begin() == indexAccel )
1e6feb95
VZ
2352 {
2353 // remeber to draw underscore here
2354 GetTextExtent(curLine, &startUnderscore, NULL);
2355 curLine += *pc;
2356 GetTextExtent(curLine, &endUnderscore, NULL);
2357
2358 yUnderscore = y + heightLine;
2359 }
2360 else
2361 {
2362 curLine += *pc;
2363 }
2364 }
2365 }
2366
2367 // draw the underscore if found
2368 if ( startUnderscore != endUnderscore )
2369 {
2370 // it should be of the same colour as text
2371 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
2372
2373 yUnderscore--;
2374
2375 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
2376 }
2377
2378 // return bounding rect if requested
2379 if ( rectBounding )
2380 {
2381 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
2382 }
2383
2384 CalcBoundingBox(x0, y0);
2385 CalcBoundingBox(x0 + width0, y0 + height);
2386}
12bdd77c 2387
213ad8e7
VZ
2388
2389void wxDCBase::DoGradientFillLinear(const wxRect& rect,
2390 const wxColour& initialColour,
2391 const wxColour& destColour,
2392 wxDirection nDirection)
2393{
2394 // save old pen
2395 wxPen oldPen = m_pen;
a983a3cf 2396 wxBrush oldBrush = m_brush;
213ad8e7 2397
6dff0e29
BW
2398 wxUint8 nR1 = initialColour.Red();
2399 wxUint8 nG1 = initialColour.Green();
2400 wxUint8 nB1 = initialColour.Blue();
2401 wxUint8 nR2 = destColour.Red();
2402 wxUint8 nG2 = destColour.Green();
2403 wxUint8 nB2 = destColour.Blue();
213ad8e7
VZ
2404 wxUint8 nR, nG, nB;
2405
2406 if ( nDirection == wxEAST || nDirection == wxWEST )
2407 {
2408 wxInt32 x = rect.GetWidth();
2409 wxInt32 w = x; // width of area to shade
2410 wxInt32 xDelta = w/256; // height of one shade bend
2411 if (xDelta < 1)
2412 xDelta = 1;
2413
2414 while (x >= xDelta)
2415 {
2416 x -= xDelta;
2417 if (nR1 > nR2)
2418 nR = nR1 - (nR1-nR2)*(w-x)/w;
2419 else
2420 nR = nR1 + (nR2-nR1)*(w-x)/w;
2421
2422 if (nG1 > nG2)
2423 nG = nG1 - (nG1-nG2)*(w-x)/w;
2424 else
2425 nG = nG1 + (nG2-nG1)*(w-x)/w;
2426
2427 if (nB1 > nB2)
2428 nB = nB1 - (nB1-nB2)*(w-x)/w;
2429 else
2430 nB = nB1 + (nB2-nB1)*(w-x)/w;
2431
e3b81044 2432 wxColour colour(nR,nG,nB);
1dab6da9
BW
2433 SetPen(wxPen(colour, 1, wxSOLID));
2434 SetBrush(wxBrush(colour));
213ad8e7 2435 if(nDirection == wxEAST)
1dab6da9 2436 DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(),
213ad8e7
VZ
2437 xDelta, rect.GetHeight());
2438 else //nDirection == wxWEST
1dab6da9 2439 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
213ad8e7
VZ
2440 xDelta, rect.GetHeight());
2441 }
2442 }
2443 else // nDirection == wxNORTH || nDirection == wxSOUTH
2444 {
2445 wxInt32 y = rect.GetHeight();
2446 wxInt32 w = y; // height of area to shade
2447 wxInt32 yDelta = w/255; // height of one shade bend
2448 if (yDelta < 1)
2449 yDelta = 1;
2450
2451 while (y > 0)
2452 {
2453 y -= yDelta;
2454 if (nR1 > nR2)
2455 nR = nR1 - (nR1-nR2)*(w-y)/w;
2456 else
2457 nR = nR1 + (nR2-nR1)*(w-y)/w;
2458
2459 if (nG1 > nG2)
2460 nG = nG1 - (nG1-nG2)*(w-y)/w;
2461 else
2462 nG = nG1 + (nG2-nG1)*(w-y)/w;
2463
2464 if (nB1 > nB2)
2465 nB = nB1 - (nB1-nB2)*(w-y)/w;
2466 else
2467 nB = nB1 + (nB2-nB1)*(w-y)/w;
2468
e3b81044 2469 wxColour colour(nR,nG,nB);
1dab6da9
BW
2470 SetPen(wxPen(colour, 1, wxSOLID));
2471 SetBrush(wxBrush(colour));
213ad8e7
VZ
2472 if(nDirection == wxNORTH)
2473 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
2474 rect.GetWidth(), yDelta);
2475 else //nDirection == wxSOUTH
2476 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta,
2477 rect.GetWidth(), yDelta);
2478 }
2479 }
2480
2481 SetPen(oldPen);
a983a3cf 2482 SetBrush(oldBrush);
213ad8e7
VZ
2483}
2484
fb63a242 2485void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
213ad8e7
VZ
2486 const wxColour& initialColour,
2487 const wxColour& destColour,
2488 const wxPoint& circleCenter)
2489{
2490 //save the old pen color
2491 wxColour oldPenColour = m_pen.GetColour();
2492
2493 wxUint8 nR1 = destColour.Red();
2494 wxUint8 nG1 = destColour.Green();
2495 wxUint8 nB1 = destColour.Blue();
2496 wxUint8 nR2 = initialColour.Red();
2497 wxUint8 nG2 = initialColour.Green();
2498 wxUint8 nB2 = initialColour.Blue();
2499 wxUint8 nR, nG, nB;
2500
2501
213ad8e7
VZ
2502 //Radius
2503 wxInt32 cx = rect.GetWidth() / 2;
2504 wxInt32 cy = rect.GetHeight() / 2;
2505 wxInt32 nRadius;
2506 if (cx < cy)
2507 nRadius = cx;
2508 else
2509 nRadius = cy;
2510
2511 //Offset of circle
2512 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
2513 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
2514
e35d07b9 2515 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
213ad8e7 2516 {
e35d07b9 2517 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
213ad8e7
VZ
2518 {
2519 //get color difference
e35d07b9
VZ
2520 wxInt32 nGradient = ((nRadius -
2521 (wxInt32)sqrt(
2522 pow((double)(x - cx - nCircleOffX), 2) +
2523 pow((double)(y - cy - nCircleOffY), 2)
2524 )) * 100) / nRadius;
213ad8e7
VZ
2525
2526 //normalize Gradient
2527 if (nGradient < 0 )
2528 nGradient = 0;
2529
2530 //get dest colors
06052f3f
WS
2531 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2532 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2533 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
213ad8e7
VZ
2534
2535 //set the pixel
2536 m_pen.SetColour(wxColour(nR,nG,nB));
2537 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
2538 }
2539 }
2540 //return old pen color
2541 m_pen.SetColour(oldPenColour);
2542}
2543
12bdd77c 2544/*
77ffb593 2545Notes for wxWidgets DrawEllipticArcRot(...)
12bdd77c
JS
2546
2547wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2548It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2549which are also new.
2550
2551All methods are generic, so they can be implemented in wxDCBase.
2552DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2553methods like (WinCE) wxDC::DoDrawArc(...).
2554
2555CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2aaa050c 2556of an elliptic arc. The algorithm is pixel-based: In every row (in flat
12bdd77c
JS
2557parts) or every column (in steep parts) only one pixel is calculated.
2558Trigonometric calculation (sin, cos, tan, atan) is only done if the
2aaa050c 2559starting angle is not equal to the ending angle. The calculation of the
12bdd77c
JS
2560pixels is done using simple arithmetic only and should perform not too
2561bad even on devices without floating point processor. I didn't test this yet.
2562
2563Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2aaa050c 2564For instance: an ellipse rotated 180 degrees is drawn
12bdd77c
JS
2565slightly different from the original.
2566
2aaa050c
VZ
2567The points are then moved to an array and used to draw a polyline and/or polygon
2568(with center added, the pie).
12bdd77c
JS
2569The result looks quite similar to the native ellipse, only e few pixels differ.
2570
2571The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2572slower as DrawEllipse(...), which calls the native API.
2573An rotated ellipse outside the clipping region takes nearly the same time,
2574while an native ellipse outside takes nearly no time to draw.
2575
2aaa050c 2576If you draw an arc with this new method, you will see the starting and ending angles
12bdd77c
JS
2577are calculated properly.
2578If you use DrawEllipticArc(...), you will see they are only correct for circles
2579and not properly calculated for ellipses.
2580
2581Peter Lenhard
2582p.lenhard@t-online.de
2583*/
2584
2585#ifdef __WXWINCE__
2aaa050c
VZ
2586void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2587 wxCoord w, wxCoord h,
12bdd77c
JS
2588 double sa, double ea, double angle )
2589{
2590 wxList list;
2591
2592 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
2593 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
2594
2595 // Add center (for polygon/pie)
2596 list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) );
2597
2598 // copy list into array and delete list elements
2c3ebf8b 2599 int n = list.GetCount();
12bdd77c
JS
2600 wxPoint *points = new wxPoint[n];
2601 int i = 0;
2aaa050c 2602 wxNode* node = 0;
2c3ebf8b 2603 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
12bdd77c 2604 {
2c3ebf8b 2605 wxPoint *point = (wxPoint *)node->GetData();
12bdd77c
JS
2606 points[i].x = point->x;
2607 points[i].y = point->y;
2608 delete point;
2609 }
2610
2611 // first draw the pie without pen, if necessary
63b9e659 2612 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
2613 {
2614 wxPen tempPen( GetPen() );
2615 SetPen( *wxTRANSPARENT_PEN );
2616 DoDrawPolygon( n, points, 0, 0 );
2617 SetPen( tempPen );
2618 }
2619
2620 // then draw the arc without brush, if necessary
63b9e659 2621 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
2622 {
2623 // without center
2624 DoDrawLines( n-1, points, 0, 0 );
2625 }
2626
2627 delete [] points;
2628
2629} // DrawEllipticArcRot
2630
2631void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
2632{
2633 if( angle != 0.0 )
2634 {
e0d31471 2635 double pi(M_PI);
12bdd77c
JS
2636 double dSinA = -sin(angle*2.0*pi/360.0);
2637 double dCosA = cos(angle*2.0*pi/360.0);
2c3ebf8b 2638 for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() )
12bdd77c 2639 {
2c3ebf8b 2640 wxPoint* point = (wxPoint*)node->GetData();
2aaa050c 2641
12bdd77c
JS
2642 // transform coordinates, if necessary
2643 if( center.x ) point->x -= center.x;
2644 if( center.y ) point->y -= center.y;
2645
2646 // calculate rotation, rounding simply by implicit cast to integer
2647 int xTemp = point->x * dCosA - point->y * dSinA;
2648 point->y = point->x * dSinA + point->y * dCosA;
2649 point->x = xTemp;
2650
2651 // back transform coordinates, if necessary
2652 if( center.x ) point->x += center.x;
2653 if( center.y ) point->y += center.y;
2654 }
2655 }
2656}
2657
2aaa050c
VZ
2658void wxDCBase::CalculateEllipticPoints( wxList* points,
2659 wxCoord xStart, wxCoord yStart,
2660 wxCoord w, wxCoord h,
12bdd77c
JS
2661 double sa, double ea )
2662{
e0d31471 2663 double pi = M_PI;
12bdd77c
JS
2664 double sar = 0;
2665 double ear = 0;
2666 int xsa = 0;
2667 int ysa = 0;
2668 int xea = 0;
2669 int yea = 0;
2670 int sq = 0;
2671 int eq = 0;
2672 bool bUseAngles = false;
2673 if( w<0 ) w = -w;
2674 if( h<0 ) h = -h;
2675 // half-axes
2676 wxCoord a = w/2;
2677 wxCoord b = h/2;
2678 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2679 int decrX = 0;
2aaa050c 2680 if( 2*a == w ) decrX = 1;
12bdd77c 2681 int decrY = 0;
2aaa050c 2682 if( 2*b == h ) decrY = 1;
12bdd77c
JS
2683 // center
2684 wxCoord xCenter = xStart + a;
2685 wxCoord yCenter = yStart + b;
2686 // calculate data for start and end, if necessary
2687 if( sa != ea )
2688 {
2689 bUseAngles = true;
2690 // normalisation of angles
2691 while( sa<0 ) sa += 360;
2692 while( ea<0 ) ea += 360;
2693 while( sa>=360 ) sa -= 360;
2694 while( ea>=360 ) ea -= 360;
2695 // calculate quadrant numbers
2696 if( sa > 270 ) sq = 3;
2697 else if( sa > 180 ) sq = 2;
2698 else if( sa > 90 ) sq = 1;
2699 if( ea > 270 ) eq = 3;
2700 else if( ea > 180 ) eq = 2;
2701 else if( ea > 90 ) eq = 1;
2702 sar = sa * pi / 180.0;
2703 ear = ea * pi / 180.0;
2704 // correct angle circle -> ellipse
2705 sar = atan( -a/(double)b * tan( sar ) );
2aaa050c 2706 if ( sq == 1 || sq == 2 ) sar += pi;
12bdd77c
JS
2707 ear = atan( -a/(double)b * tan( ear ) );
2708 if ( eq == 1 || eq == 2 ) ear += pi;
2709 // coordinates of points
2710 xsa = xCenter + a * cos( sar );
2711 if( sq == 0 || sq == 3 ) xsa -= decrX;
2712 ysa = yCenter + b * sin( sar );
2713 if( sq == 2 || sq == 3 ) ysa -= decrY;
2714 xea = xCenter + a * cos( ear );
2715 if( eq == 0 || eq == 3 ) xea -= decrX;
2716 yea = yCenter + b * sin( ear );
2717 if( eq == 2 || eq == 3 ) yea -= decrY;
2718 } // if iUseAngles
2719 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2720 double c1 = b * b;
2721 double c2 = 2.0 / w;
2722 c2 *= c2;
2723 c2 *= c1;
2724 wxCoord x = 0;
2725 wxCoord y = b;
2726 long x2 = 1;
2727 long y2 = y*y;
2728 long y2_old = 0;
2729 long y_old = 0;
2730 // Lists for quadrant 1 to 4
2731 wxList pointsarray[4];
2732 // Calculate points for first quadrant and set in all quadrants
2733 for( x = 0; x <= a; ++x )
2734 {
2735 x2 = x2+x+x-1;
2736 y2_old = y2;
2737 y_old = y;
2738 bool bNewPoint = false;
2739 while( y2 > c1 - c2 * x2 && y > 0 )
2740 {
2741 bNewPoint = true;
2742 y2 = y2-y-y+1;
2743 --y;
2744 }
2aaa050c 2745 // old y now to big: set point with old y, old x
12bdd77c
JS
2746 if( bNewPoint && x>1)
2747 {
2748 int x1 = x - 1;
2749 // remove points on the same line
2750 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
2751 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) );
2752 pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
2753 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
2754 } // set point
2755 } // calculate point
2aaa050c 2756
12bdd77c
JS
2757 // Starting and/or ending points for the quadrants, first quadrant gets both.
2758 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
2759 pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) );
2760 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) );
2761 pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) );
2762 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
2763
2764 // copy quadrants in original list
2765 if( bUseAngles )
2766 {
2767 // Copy the right part of the points in the lists
2768 // and delete the wxPoints, because they do not leave this method.
2769 points->Append( (wxObject*) new wxPoint( xsa, ysa ) );
2770 int q = sq;
2771 bool bStarted = false;
2772 bool bReady = false;
2773 bool bForceTurn = ( sq == eq && sa > ea );
2774 while( !bReady )
2775 {
2c3ebf8b 2776 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c
JS
2777 {
2778 // once: go to starting point in start quadrant
2779 if( !bStarted &&
2aaa050c 2780 (
2c3ebf8b 2781 ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1
2aaa050c 2782 ||
2c3ebf8b 2783 ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2
12bdd77c 2784 )
2aaa050c 2785 )
12bdd77c
JS
2786 {
2787 bStarted = true;
2788 }
2789
2790 // copy point, if not at ending point
2791 if( bStarted )
2792 {
2793 if( q != eq || bForceTurn
2794 ||
2c3ebf8b 2795 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2aaa050c 2796 ||
2c3ebf8b 2797 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
12bdd77c
JS
2798 )
2799 {
2800 // copy point
2c3ebf8b 2801 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) );
12bdd77c
JS
2802 points->Append( (wxObject*) pPoint );
2803 }
2c3ebf8b 2804 else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea)
12bdd77c 2805 {
2aaa050c 2806 bReady = true;
12bdd77c
JS
2807 }
2808 }
2809 } // for node
2810 ++q;
2811 if( q > 3 ) q = 0;
2812 bForceTurn = false;
2813 bStarted = true;
2814 } // while not bReady
2815 points->Append( (wxObject*) new wxPoint( xea, yea ) );
2816
2817 // delete points
2818 for( q = 0; q < 4; ++q )
2819 {
2c3ebf8b 2820 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c 2821 {
2c3ebf8b 2822 wxPoint *p = (wxPoint *)node->GetData();
12bdd77c
JS
2823 delete p;
2824 }
2aaa050c 2825 }
12bdd77c
JS
2826 }
2827 else
2828 {
b1c6a00e 2829 wxNode* node;
12bdd77c 2830 // copy whole ellipse, wxPoints will be deleted outside
2c3ebf8b 2831 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
12bdd77c 2832 {
2c3ebf8b 2833 wxObject *p = node->GetData();
12bdd77c
JS
2834 points->Append( p );
2835 }
2c3ebf8b 2836 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
12bdd77c 2837 {
2c3ebf8b 2838 wxObject *p = node->GetData();
12bdd77c
JS
2839 points->Append( p );
2840 }
2c3ebf8b 2841 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
12bdd77c 2842 {
2c3ebf8b 2843 wxObject *p = node->GetData();
12bdd77c
JS
2844 points->Append( p );
2845 }
2c3ebf8b 2846 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
12bdd77c 2847 {
2c3ebf8b 2848 wxObject *p = node->GetData();
12bdd77c
JS
2849 points->Append( p );
2850 }
2851 } // not iUseAngles
2852} // CalculateEllipticPoints
2853
e3b81044 2854#endif // __WXWINCE__
2970ae54
RR
2855
2856#endif // wxUSE_NEW_DC