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