]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
update button style to include BS_MULTILINE when a multiline label is set
[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;
86501081 2175 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2176 {
86501081 2177 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
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
86501081 2208 if ( pc == text.end() )
1e6feb95 2209 {
86501081 2210 break;
1e6feb95 2211 }
86501081 2212 else // '\n'
1e6feb95 2213 {
86501081 2214 curLine.clear();
1e6feb95
VZ
2215 }
2216 }
2217 else
2218 {
2219 curLine += *pc;
2220 }
2221 }
2222
2223 if ( x )
2224 *x = widthTextMax;
2225 if ( y )
2226 *y = heightTextTotal;
2227 if ( h )
2228 *h = heightLine;
2229}
2230
2231void wxDCBase::DrawLabel(const wxString& text,
2232 const wxBitmap& bitmap,
2233 const wxRect& rect,
2234 int alignment,
2235 int indexAccel,
2236 wxRect *rectBounding)
2237{
2238 // find the text position
2239 wxCoord widthText, heightText, heightLine;
2240 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
2241
2242 wxCoord width, height;
2243 if ( bitmap.Ok() )
2244 {
2245 width = widthText + bitmap.GetWidth();
2246 height = bitmap.GetHeight();
2247 }
2248 else // no bitmap
2249 {
2250 width = widthText;
2251 height = heightText;
2252 }
2253
2254 wxCoord x, y;
2255 if ( alignment & wxALIGN_RIGHT )
2256 {
2257 x = rect.GetRight() - width;
2258 }
2259 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2260 {
2261 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
2262 }
2263 else // alignment & wxALIGN_LEFT
2264 {
2265 x = rect.GetLeft();
2266 }
2267
2268 if ( alignment & wxALIGN_BOTTOM )
2269 {
2270 y = rect.GetBottom() - height;
2271 }
2272 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
2273 {
2274 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
2275 }
2276 else // alignment & wxALIGN_TOP
2277 {
2278 y = rect.GetTop();
2279 }
2280
2281 // draw the bitmap first
2282 wxCoord x0 = x,
2283 y0 = y,
2284 width0 = width;
2285 if ( bitmap.Ok() )
2286 {
68379eaf 2287 DrawBitmap(bitmap, x, y, true /* use mask */);
1e6feb95
VZ
2288
2289 wxCoord offset = bitmap.GetWidth() + 4;
2290 x += offset;
2291 width -= offset;
2292
2293 y += (height - heightText) / 2;
2294 }
2295
2296 // we will draw the underscore under the accel char later
2297 wxCoord startUnderscore = 0,
2298 endUnderscore = 0,
2299 yUnderscore = 0;
2300
2301 // split the string into lines and draw each of them separately
2302 wxString curLine;
c9f78968 2303 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2304 {
f5595af6 2305 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
2306 {
2307 int xRealStart = x; // init it here to avoid compielr warnings
2308
2309 if ( !curLine.empty() )
2310 {
2311 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2312 // wxALIGN_LEFT is 0
2313 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
2314 {
2315 wxCoord widthLine;
2316 GetTextExtent(curLine, &widthLine, NULL);
2317
2318 if ( alignment & wxALIGN_RIGHT )
2319 {
2320 xRealStart += width - widthLine;
2321 }
2322 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2323 {
2324 xRealStart += (width - widthLine) / 2;
2325 }
2326 }
2327 //else: left aligned, nothing to do
2328
2329 DrawText(curLine, xRealStart, y);
2330 }
2331
2332 y += heightLine;
2333
2334 // do we have underscore in this line? we can check yUnderscore
2335 // because it is set below to just y + heightLine if we do
2336 if ( y == yUnderscore )
2337 {
2338 // adjust the horz positions to account for the shift
2339 startUnderscore += xRealStart;
2340 endUnderscore += xRealStart;
2341 }
2342
c9f78968 2343 if ( pc == text.end() )
1e6feb95
VZ
2344 break;
2345
2346 curLine.clear();
2347 }
2348 else // not end of line
2349 {
9daaea28 2350 if ( pc - text.begin() == indexAccel )
1e6feb95
VZ
2351 {
2352 // remeber to draw underscore here
2353 GetTextExtent(curLine, &startUnderscore, NULL);
2354 curLine += *pc;
2355 GetTextExtent(curLine, &endUnderscore, NULL);
2356
2357 yUnderscore = y + heightLine;
2358 }
2359 else
2360 {
2361 curLine += *pc;
2362 }
2363 }
2364 }
2365
2366 // draw the underscore if found
2367 if ( startUnderscore != endUnderscore )
2368 {
2369 // it should be of the same colour as text
2370 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
2371
2372 yUnderscore--;
2373
2374 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
2375 }
2376
2377 // return bounding rect if requested
2378 if ( rectBounding )
2379 {
2380 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
2381 }
2382
2383 CalcBoundingBox(x0, y0);
2384 CalcBoundingBox(x0 + width0, y0 + height);
2385}
12bdd77c 2386
213ad8e7
VZ
2387
2388void wxDCBase::DoGradientFillLinear(const wxRect& rect,
2389 const wxColour& initialColour,
2390 const wxColour& destColour,
2391 wxDirection nDirection)
2392{
2393 // save old pen
2394 wxPen oldPen = m_pen;
a983a3cf 2395 wxBrush oldBrush = m_brush;
213ad8e7 2396
6dff0e29
BW
2397 wxUint8 nR1 = initialColour.Red();
2398 wxUint8 nG1 = initialColour.Green();
2399 wxUint8 nB1 = initialColour.Blue();
2400 wxUint8 nR2 = destColour.Red();
2401 wxUint8 nG2 = destColour.Green();
2402 wxUint8 nB2 = destColour.Blue();
213ad8e7
VZ
2403 wxUint8 nR, nG, nB;
2404
2405 if ( nDirection == wxEAST || nDirection == wxWEST )
2406 {
2407 wxInt32 x = rect.GetWidth();
2408 wxInt32 w = x; // width of area to shade
2409 wxInt32 xDelta = w/256; // height of one shade bend
2410 if (xDelta < 1)
2411 xDelta = 1;
2412
2413 while (x >= xDelta)
2414 {
2415 x -= xDelta;
2416 if (nR1 > nR2)
2417 nR = nR1 - (nR1-nR2)*(w-x)/w;
2418 else
2419 nR = nR1 + (nR2-nR1)*(w-x)/w;
2420
2421 if (nG1 > nG2)
2422 nG = nG1 - (nG1-nG2)*(w-x)/w;
2423 else
2424 nG = nG1 + (nG2-nG1)*(w-x)/w;
2425
2426 if (nB1 > nB2)
2427 nB = nB1 - (nB1-nB2)*(w-x)/w;
2428 else
2429 nB = nB1 + (nB2-nB1)*(w-x)/w;
2430
e3b81044 2431 wxColour colour(nR,nG,nB);
1dab6da9
BW
2432 SetPen(wxPen(colour, 1, wxSOLID));
2433 SetBrush(wxBrush(colour));
213ad8e7 2434 if(nDirection == wxEAST)
1dab6da9 2435 DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(),
213ad8e7
VZ
2436 xDelta, rect.GetHeight());
2437 else //nDirection == wxWEST
1dab6da9 2438 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
213ad8e7
VZ
2439 xDelta, rect.GetHeight());
2440 }
2441 }
2442 else // nDirection == wxNORTH || nDirection == wxSOUTH
2443 {
2444 wxInt32 y = rect.GetHeight();
2445 wxInt32 w = y; // height of area to shade
2446 wxInt32 yDelta = w/255; // height of one shade bend
2447 if (yDelta < 1)
2448 yDelta = 1;
2449
2450 while (y > 0)
2451 {
2452 y -= yDelta;
2453 if (nR1 > nR2)
2454 nR = nR1 - (nR1-nR2)*(w-y)/w;
2455 else
2456 nR = nR1 + (nR2-nR1)*(w-y)/w;
2457
2458 if (nG1 > nG2)
2459 nG = nG1 - (nG1-nG2)*(w-y)/w;
2460 else
2461 nG = nG1 + (nG2-nG1)*(w-y)/w;
2462
2463 if (nB1 > nB2)
2464 nB = nB1 - (nB1-nB2)*(w-y)/w;
2465 else
2466 nB = nB1 + (nB2-nB1)*(w-y)/w;
2467
e3b81044 2468 wxColour colour(nR,nG,nB);
1dab6da9
BW
2469 SetPen(wxPen(colour, 1, wxSOLID));
2470 SetBrush(wxBrush(colour));
213ad8e7
VZ
2471 if(nDirection == wxNORTH)
2472 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
2473 rect.GetWidth(), yDelta);
2474 else //nDirection == wxSOUTH
2475 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta,
2476 rect.GetWidth(), yDelta);
2477 }
2478 }
2479
2480 SetPen(oldPen);
a983a3cf 2481 SetBrush(oldBrush);
213ad8e7
VZ
2482}
2483
fb63a242 2484void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
213ad8e7
VZ
2485 const wxColour& initialColour,
2486 const wxColour& destColour,
2487 const wxPoint& circleCenter)
2488{
2489 //save the old pen color
2490 wxColour oldPenColour = m_pen.GetColour();
2491
2492 wxUint8 nR1 = destColour.Red();
2493 wxUint8 nG1 = destColour.Green();
2494 wxUint8 nB1 = destColour.Blue();
2495 wxUint8 nR2 = initialColour.Red();
2496 wxUint8 nG2 = initialColour.Green();
2497 wxUint8 nB2 = initialColour.Blue();
2498 wxUint8 nR, nG, nB;
2499
2500
213ad8e7
VZ
2501 //Radius
2502 wxInt32 cx = rect.GetWidth() / 2;
2503 wxInt32 cy = rect.GetHeight() / 2;
2504 wxInt32 nRadius;
2505 if (cx < cy)
2506 nRadius = cx;
2507 else
2508 nRadius = cy;
2509
2510 //Offset of circle
2511 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
2512 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
2513
e35d07b9 2514 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
213ad8e7 2515 {
e35d07b9 2516 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
213ad8e7
VZ
2517 {
2518 //get color difference
e35d07b9
VZ
2519 wxInt32 nGradient = ((nRadius -
2520 (wxInt32)sqrt(
2521 pow((double)(x - cx - nCircleOffX), 2) +
2522 pow((double)(y - cy - nCircleOffY), 2)
2523 )) * 100) / nRadius;
213ad8e7
VZ
2524
2525 //normalize Gradient
2526 if (nGradient < 0 )
2527 nGradient = 0;
2528
2529 //get dest colors
06052f3f
WS
2530 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2531 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2532 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
213ad8e7
VZ
2533
2534 //set the pixel
2535 m_pen.SetColour(wxColour(nR,nG,nB));
2536 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
2537 }
2538 }
2539 //return old pen color
2540 m_pen.SetColour(oldPenColour);
2541}
2542
12bdd77c 2543/*
77ffb593 2544Notes for wxWidgets DrawEllipticArcRot(...)
12bdd77c
JS
2545
2546wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2547It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2548which are also new.
2549
2550All methods are generic, so they can be implemented in wxDCBase.
2551DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2552methods like (WinCE) wxDC::DoDrawArc(...).
2553
2554CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2aaa050c 2555of an elliptic arc. The algorithm is pixel-based: In every row (in flat
12bdd77c
JS
2556parts) or every column (in steep parts) only one pixel is calculated.
2557Trigonometric calculation (sin, cos, tan, atan) is only done if the
2aaa050c 2558starting angle is not equal to the ending angle. The calculation of the
12bdd77c
JS
2559pixels is done using simple arithmetic only and should perform not too
2560bad even on devices without floating point processor. I didn't test this yet.
2561
2562Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2aaa050c 2563For instance: an ellipse rotated 180 degrees is drawn
12bdd77c
JS
2564slightly different from the original.
2565
2aaa050c
VZ
2566The points are then moved to an array and used to draw a polyline and/or polygon
2567(with center added, the pie).
12bdd77c
JS
2568The result looks quite similar to the native ellipse, only e few pixels differ.
2569
2570The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2571slower as DrawEllipse(...), which calls the native API.
2572An rotated ellipse outside the clipping region takes nearly the same time,
2573while an native ellipse outside takes nearly no time to draw.
2574
2aaa050c 2575If you draw an arc with this new method, you will see the starting and ending angles
12bdd77c
JS
2576are calculated properly.
2577If you use DrawEllipticArc(...), you will see they are only correct for circles
2578and not properly calculated for ellipses.
2579
2580Peter Lenhard
2581p.lenhard@t-online.de
2582*/
2583
2584#ifdef __WXWINCE__
2aaa050c
VZ
2585void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2586 wxCoord w, wxCoord h,
12bdd77c
JS
2587 double sa, double ea, double angle )
2588{
2589 wxList list;
2590
2591 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
2592 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
2593
2594 // Add center (for polygon/pie)
2595 list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) );
2596
2597 // copy list into array and delete list elements
2c3ebf8b 2598 int n = list.GetCount();
12bdd77c
JS
2599 wxPoint *points = new wxPoint[n];
2600 int i = 0;
2aaa050c 2601 wxNode* node = 0;
2c3ebf8b 2602 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
12bdd77c 2603 {
2c3ebf8b 2604 wxPoint *point = (wxPoint *)node->GetData();
12bdd77c
JS
2605 points[i].x = point->x;
2606 points[i].y = point->y;
2607 delete point;
2608 }
2609
2610 // first draw the pie without pen, if necessary
63b9e659 2611 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
2612 {
2613 wxPen tempPen( GetPen() );
2614 SetPen( *wxTRANSPARENT_PEN );
2615 DoDrawPolygon( n, points, 0, 0 );
2616 SetPen( tempPen );
2617 }
2618
2619 // then draw the arc without brush, if necessary
63b9e659 2620 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
2621 {
2622 // without center
2623 DoDrawLines( n-1, points, 0, 0 );
2624 }
2625
2626 delete [] points;
2627
2628} // DrawEllipticArcRot
2629
2630void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
2631{
2632 if( angle != 0.0 )
2633 {
e0d31471 2634 double pi(M_PI);
12bdd77c
JS
2635 double dSinA = -sin(angle*2.0*pi/360.0);
2636 double dCosA = cos(angle*2.0*pi/360.0);
2c3ebf8b 2637 for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() )
12bdd77c 2638 {
2c3ebf8b 2639 wxPoint* point = (wxPoint*)node->GetData();
2aaa050c 2640
12bdd77c
JS
2641 // transform coordinates, if necessary
2642 if( center.x ) point->x -= center.x;
2643 if( center.y ) point->y -= center.y;
2644
2645 // calculate rotation, rounding simply by implicit cast to integer
2646 int xTemp = point->x * dCosA - point->y * dSinA;
2647 point->y = point->x * dSinA + point->y * dCosA;
2648 point->x = xTemp;
2649
2650 // back transform coordinates, if necessary
2651 if( center.x ) point->x += center.x;
2652 if( center.y ) point->y += center.y;
2653 }
2654 }
2655}
2656
2aaa050c
VZ
2657void wxDCBase::CalculateEllipticPoints( wxList* points,
2658 wxCoord xStart, wxCoord yStart,
2659 wxCoord w, wxCoord h,
12bdd77c
JS
2660 double sa, double ea )
2661{
e0d31471 2662 double pi = M_PI;
12bdd77c
JS
2663 double sar = 0;
2664 double ear = 0;
2665 int xsa = 0;
2666 int ysa = 0;
2667 int xea = 0;
2668 int yea = 0;
2669 int sq = 0;
2670 int eq = 0;
2671 bool bUseAngles = false;
2672 if( w<0 ) w = -w;
2673 if( h<0 ) h = -h;
2674 // half-axes
2675 wxCoord a = w/2;
2676 wxCoord b = h/2;
2677 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2678 int decrX = 0;
2aaa050c 2679 if( 2*a == w ) decrX = 1;
12bdd77c 2680 int decrY = 0;
2aaa050c 2681 if( 2*b == h ) decrY = 1;
12bdd77c
JS
2682 // center
2683 wxCoord xCenter = xStart + a;
2684 wxCoord yCenter = yStart + b;
2685 // calculate data for start and end, if necessary
2686 if( sa != ea )
2687 {
2688 bUseAngles = true;
2689 // normalisation of angles
2690 while( sa<0 ) sa += 360;
2691 while( ea<0 ) ea += 360;
2692 while( sa>=360 ) sa -= 360;
2693 while( ea>=360 ) ea -= 360;
2694 // calculate quadrant numbers
2695 if( sa > 270 ) sq = 3;
2696 else if( sa > 180 ) sq = 2;
2697 else if( sa > 90 ) sq = 1;
2698 if( ea > 270 ) eq = 3;
2699 else if( ea > 180 ) eq = 2;
2700 else if( ea > 90 ) eq = 1;
2701 sar = sa * pi / 180.0;
2702 ear = ea * pi / 180.0;
2703 // correct angle circle -> ellipse
2704 sar = atan( -a/(double)b * tan( sar ) );
2aaa050c 2705 if ( sq == 1 || sq == 2 ) sar += pi;
12bdd77c
JS
2706 ear = atan( -a/(double)b * tan( ear ) );
2707 if ( eq == 1 || eq == 2 ) ear += pi;
2708 // coordinates of points
2709 xsa = xCenter + a * cos( sar );
2710 if( sq == 0 || sq == 3 ) xsa -= decrX;
2711 ysa = yCenter + b * sin( sar );
2712 if( sq == 2 || sq == 3 ) ysa -= decrY;
2713 xea = xCenter + a * cos( ear );
2714 if( eq == 0 || eq == 3 ) xea -= decrX;
2715 yea = yCenter + b * sin( ear );
2716 if( eq == 2 || eq == 3 ) yea -= decrY;
2717 } // if iUseAngles
2718 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2719 double c1 = b * b;
2720 double c2 = 2.0 / w;
2721 c2 *= c2;
2722 c2 *= c1;
2723 wxCoord x = 0;
2724 wxCoord y = b;
2725 long x2 = 1;
2726 long y2 = y*y;
2727 long y2_old = 0;
2728 long y_old = 0;
2729 // Lists for quadrant 1 to 4
2730 wxList pointsarray[4];
2731 // Calculate points for first quadrant and set in all quadrants
2732 for( x = 0; x <= a; ++x )
2733 {
2734 x2 = x2+x+x-1;
2735 y2_old = y2;
2736 y_old = y;
2737 bool bNewPoint = false;
2738 while( y2 > c1 - c2 * x2 && y > 0 )
2739 {
2740 bNewPoint = true;
2741 y2 = y2-y-y+1;
2742 --y;
2743 }
2aaa050c 2744 // old y now to big: set point with old y, old x
12bdd77c
JS
2745 if( bNewPoint && x>1)
2746 {
2747 int x1 = x - 1;
2748 // remove points on the same line
2749 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
2750 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) );
2751 pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
2752 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
2753 } // set point
2754 } // calculate point
2aaa050c 2755
12bdd77c
JS
2756 // Starting and/or ending points for the quadrants, first quadrant gets both.
2757 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
2758 pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) );
2759 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) );
2760 pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) );
2761 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
2762
2763 // copy quadrants in original list
2764 if( bUseAngles )
2765 {
2766 // Copy the right part of the points in the lists
2767 // and delete the wxPoints, because they do not leave this method.
2768 points->Append( (wxObject*) new wxPoint( xsa, ysa ) );
2769 int q = sq;
2770 bool bStarted = false;
2771 bool bReady = false;
2772 bool bForceTurn = ( sq == eq && sa > ea );
2773 while( !bReady )
2774 {
2c3ebf8b 2775 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c
JS
2776 {
2777 // once: go to starting point in start quadrant
2778 if( !bStarted &&
2aaa050c 2779 (
2c3ebf8b 2780 ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1
2aaa050c 2781 ||
2c3ebf8b 2782 ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2
12bdd77c 2783 )
2aaa050c 2784 )
12bdd77c
JS
2785 {
2786 bStarted = true;
2787 }
2788
2789 // copy point, if not at ending point
2790 if( bStarted )
2791 {
2792 if( q != eq || bForceTurn
2793 ||
2c3ebf8b 2794 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2aaa050c 2795 ||
2c3ebf8b 2796 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
12bdd77c
JS
2797 )
2798 {
2799 // copy point
2c3ebf8b 2800 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) );
12bdd77c
JS
2801 points->Append( (wxObject*) pPoint );
2802 }
2c3ebf8b 2803 else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea)
12bdd77c 2804 {
2aaa050c 2805 bReady = true;
12bdd77c
JS
2806 }
2807 }
2808 } // for node
2809 ++q;
2810 if( q > 3 ) q = 0;
2811 bForceTurn = false;
2812 bStarted = true;
2813 } // while not bReady
2814 points->Append( (wxObject*) new wxPoint( xea, yea ) );
2815
2816 // delete points
2817 for( q = 0; q < 4; ++q )
2818 {
2c3ebf8b 2819 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c 2820 {
2c3ebf8b 2821 wxPoint *p = (wxPoint *)node->GetData();
12bdd77c
JS
2822 delete p;
2823 }
2aaa050c 2824 }
12bdd77c
JS
2825 }
2826 else
2827 {
b1c6a00e 2828 wxNode* node;
12bdd77c 2829 // copy whole ellipse, wxPoints will be deleted outside
2c3ebf8b 2830 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
12bdd77c 2831 {
2c3ebf8b 2832 wxObject *p = node->GetData();
12bdd77c
JS
2833 points->Append( p );
2834 }
2c3ebf8b 2835 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
12bdd77c 2836 {
2c3ebf8b 2837 wxObject *p = node->GetData();
12bdd77c
JS
2838 points->Append( p );
2839 }
2c3ebf8b 2840 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
12bdd77c 2841 {
2c3ebf8b 2842 wxObject *p = node->GetData();
12bdd77c
JS
2843 points->Append( p );
2844 }
2c3ebf8b 2845 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
12bdd77c 2846 {
2c3ebf8b 2847 wxObject *p = node->GetData();
12bdd77c
JS
2848 points->Append( p );
2849 }
2850 } // not iUseAngles
2851} // CalculateEllipticPoints
2852
e3b81044 2853#endif // __WXWINCE__
2970ae54
RR
2854
2855#endif // wxUSE_NEW_DC