]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcbase.cpp
restored expanders
[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_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_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 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
618 class FontWidthCache
619 {
620 public:
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
637 static FontWidthCache s_fontWidthCache;
638
639 bool 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
683 void 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
750 void 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
771 bool
772 wxImplDC::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
803 void 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
821 void 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
841 void
842 wxImplDC::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 *"?)
887 void 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
912 void 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
925 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
926 double a3, double b3, double a4, double b4);
927 void wx_clear_stack();
928 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
929 double *y3, double *x4, double *y4);
930 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
931 double x4, double y4);
932 static bool wx_spline_add_point(double x, double y);
933 static void wx_spline_draw_point_array(wxDCBase *dc);
934
935 wxList wx_spline_point_list;
936
937 #define half(z1, z2) ((z1+z2)/2.0)
938 #define THRESHOLD 5
939
940 /* iterative version */
941
942 void 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
969 typedef struct wx_spline_stack_struct {
970 double x1, y1, x2, y2, x3, y3, x4, y4;
971 } Stack;
972
973 #define SPLINE_STACK_DEPTH 20
974 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
975 static Stack *wx_stack_top;
976 static int wx_stack_count;
977
978 void wx_clear_stack()
979 {
980 wx_stack_top = wx_spline_stack;
981 wx_stack_count = 0;
982 }
983
984 void 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
998 int 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
1016 static 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
1025 static 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
1038 void 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
1101 void 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
1258 void 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
1354 void 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
1417 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1418
1419 #if WXWIN_COMPATIBILITY_2_8
1420 // for compatibility with the old code when wxCoord was long everywhere
1421 void 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
1441 void 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
1451 void 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
1461 void 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
1477 // bool wxDCBase::sm_cacheing = false;
1478
1479 IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
1480
1481 // ============================================================================
1482 // implementation
1483 // ============================================================================
1484
1485 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
1486 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
1487
1488 wxDCBase::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
1526 wxDCBase::~wxDCBase()
1527 {
1528 }
1529
1530 #if WXWIN_COMPATIBILITY_2_6
1531 void wxDCBase::BeginDrawing()
1532 {
1533 }
1534
1535 void wxDCBase::EndDrawing()
1536 {
1537 }
1538 #endif // WXWIN_COMPATIBILITY_2_6
1539
1540 #if WXWIN_COMPATIBILITY_2_8
1541 // for compatibility with the old code when wxCoord was long everywhere
1542 void wxDCBase::GetTextExtent(const wxString& string,
1543 long *x, long *y,
1544 long *descent,
1545 long *externalLeading,
1546 const wxFont *theFont) const
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
1562 void 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
1572 void 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
1582 void 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
1595 // ----------------------------------------------------------------------------
1596 // coordinate conversions and transforms
1597 // ----------------------------------------------------------------------------
1598
1599 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1600 {
1601 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
1602 }
1603
1604 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1605 {
1606 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
1607 }
1608
1609 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1610 {
1611 return wxRound((double)(x) / m_scaleX);
1612 }
1613
1614 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1615 {
1616 return wxRound((double)(y) / m_scaleY);
1617 }
1618
1619 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1620 {
1621 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
1622 }
1623
1624 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1625 {
1626 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
1627 }
1628
1629 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1630 {
1631 return wxRound((double)(x) * m_scaleX);
1632 }
1633
1634 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1635 {
1636 return wxRound((double)(y) * m_scaleY);
1637 }
1638
1639 void wxDCBase::ComputeScaleAndOrigin()
1640 {
1641 m_scaleX = m_logicalScaleX * m_userScaleX;
1642 m_scaleY = m_logicalScaleY * m_userScaleY;
1643 }
1644
1645 void 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
1669 void wxDCBase::SetUserScale( double x, double y )
1670 {
1671 // allow negative ? -> no
1672 m_userScaleX = x;
1673 m_userScaleY = y;
1674 ComputeScaleAndOrigin();
1675 }
1676
1677 void wxDCBase::SetLogicalScale( double x, double y )
1678 {
1679 // allow negative ?
1680 m_logicalScaleX = x;
1681 m_logicalScaleY = y;
1682 ComputeScaleAndOrigin();
1683 }
1684
1685 void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
1686 {
1687 m_logicalOriginX = x * m_signX;
1688 m_logicalOriginY = y * m_signY;
1689 ComputeScaleAndOrigin();
1690 }
1691
1692 void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
1693 {
1694 m_deviceOriginX = x;
1695 m_deviceOriginY = y;
1696 ComputeScaleAndOrigin();
1697 }
1698
1699 void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
1700 {
1701 m_deviceLocalOriginX = x;
1702 m_deviceLocalOriginY = y;
1703 ComputeScaleAndOrigin();
1704 }
1705
1706 void 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
1714 // ----------------------------------------------------------------------------
1715 // special symbols
1716 // ----------------------------------------------------------------------------
1717
1718 void 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
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));
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
1740 // ----------------------------------------------------------------------------
1741 // stubs for functions not implemented in all ports
1742 // ----------------------------------------------------------------------------
1743
1744 bool
1745 wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
1746 wxCoord dstWidth, wxCoord dstHeight,
1747 wxDC *source,
1748 wxCoord xsrc, wxCoord ysrc,
1749 wxCoord srcWidth, wxCoord srcHeight,
1750 int rop,
1751 bool useMask,
1752 wxCoord xsrcMask,
1753 wxCoord ysrcMask)
1754 {
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;
1774 }
1775
1776 // ----------------------------------------------------------------------------
1777 // line/polygons
1778 // ----------------------------------------------------------------------------
1779
1780 void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
1781 {
1782 int n = list->GetCount();
1783 wxPoint *points = new wxPoint[n];
1784
1785 int i = 0;
1786 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
1787 {
1788 wxPoint *point = (wxPoint *)node->GetData();
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
1799 void wxDCBase::DrawPolygon(const wxList *list,
1800 wxCoord xoffset, wxCoord yoffset,
1801 int fillStyle)
1802 {
1803 int n = list->GetCount();
1804 wxPoint *points = new wxPoint[n];
1805
1806 int i = 0;
1807 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
1808 {
1809 wxPoint *point = (wxPoint *)node->GetData();
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
1819 void
1820 wxDCBase::DoDrawPolyPolygon(int n,
1821 int count[],
1822 wxPoint points[],
1823 wxCoord xoffset, wxCoord yoffset,
1824 int fillStyle)
1825 {
1826 if ( n == 1 )
1827 {
1828 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
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;
1839 j += count[i];
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 {
1846 lastOfs -= count[n-i];
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 {
1856 DoDrawLines(count[i], pts+j, xoffset, yoffset);
1857 j += count[i];
1858 }
1859 delete[] pts;
1860 }
1861
1862 // ----------------------------------------------------------------------------
1863 // splines
1864 // ----------------------------------------------------------------------------
1865
1866 #if wxUSE_SPLINES
1867
1868 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
1869 void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
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
1887 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
1888 {
1889 wxPoint *p = (wxPoint *)node->GetData();
1890 delete p;
1891 }
1892 }
1893
1894 void 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
1905 // ----------------------------------- spline code ----------------------------------------
1906
1907 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1908 double a3, double b3, double a4, double b4);
1909 void wx_clear_stack();
1910 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1911 double *y3, double *x4, double *y4);
1912 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1913 double x4, double y4);
1914 static bool wx_spline_add_point(double x, double y);
1915 static void wx_spline_draw_point_array(wxDCBase *dc);
1916
1917 wxList wx_spline_point_list;
1918
1919 #define half(z1, z2) ((z1+z2)/2.0)
1920 #define THRESHOLD 5
1921
1922 /* iterative version */
1923
1924 void 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
1951 typedef struct wx_spline_stack_struct {
1952 double x1, y1, x2, y2, x3, y3, x4, y4;
1953 } Stack;
1954
1955 #define SPLINE_STACK_DEPTH 20
1956 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1957 static Stack *wx_stack_top;
1958 static int wx_stack_count;
1959
1960 void wx_clear_stack()
1961 {
1962 wx_stack_top = wx_spline_stack;
1963 wx_stack_count = 0;
1964 }
1965
1966 void 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
1980 int 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
1998 static 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);
2004 return true;
2005 }
2006
2007 static void wx_spline_draw_point_array(wxDCBase *dc)
2008 {
2009 dc->DrawLines(&wx_spline_point_list, 0, 0 );
2010 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
2011 while (node)
2012 {
2013 wxPoint *point = (wxPoint *)node->GetData();
2014 delete point;
2015 wx_spline_point_list.Erase(node);
2016 node = wx_spline_point_list.GetFirst();
2017 }
2018 }
2019
2020 void 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
2028 wxList::compatibility_iterator node = points->GetFirst();
2029 if (!node)
2030 // empty list
2031 return;
2032
2033 p = (wxPoint *)node->GetData();
2034
2035 x1 = p->x;
2036 y1 = p->y;
2037
2038 node = node->GetNext();
2039 p = (wxPoint *)node->GetData();
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
2050 while ((node = node->GetNext())
2051 #if !wxUSE_STL
2052 != NULL
2053 #endif // !wxUSE_STL
2054 )
2055 {
2056 p = (wxPoint *)node->GetData();
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
2080 #endif // wxUSE_SPLINES
2081
2082 // ----------------------------------------------------------------------------
2083 // Partial Text Extents
2084 // ----------------------------------------------------------------------------
2085
2086
2087 // Each element of the widths array will be the width of the string up to and
2088 // including the corresponding character in text. This is the generic
2089 // implementation, the port-specific classes should do this with native APIs
2090 // if available and if faster. Note: pango_layout_index_to_pos is much slower
2091 // than calling GetTextExtent!!
2092
2093 #define FWC_SIZE 256
2094
2095 class FontWidthCache
2096 {
2097 public:
2098 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
2099 ~FontWidthCache() { delete []m_widths; }
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
2109 wxFont m_font;
2110 double m_scaleX;
2111 int *m_widths;
2112 };
2113
2114 static FontWidthCache s_fontWidthCache;
2115
2116 bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2117 {
2118 int totalWidth = 0;
2119
2120 const size_t len = text.length();
2121 widths.Empty();
2122 widths.Add(0, len);
2123
2124 // reset the cache if font or horizontal scale have changed
2125 if ( !s_fontWidthCache.m_widths ||
2126 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
2127 (s_fontWidthCache.m_font != GetFont()) )
2128 {
2129 s_fontWidthCache.Reset();
2130 s_fontWidthCache.m_font = GetFont();
2131 s_fontWidthCache.m_scaleX = m_scaleX;
2132 }
2133
2134 // Calculate the position of each character based on the widths of
2135 // the previous characters
2136 int w, h;
2137 for ( size_t i = 0; i < len; i++ )
2138 {
2139 const wxChar c = text[i];
2140 unsigned int c_int = (unsigned int)c;
2141
2142 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
2143 {
2144 w = s_fontWidthCache.m_widths[c_int];
2145 }
2146 else
2147 {
2148 GetTextExtent(c, &w, &h);
2149 if (c_int < FWC_SIZE)
2150 s_fontWidthCache.m_widths[c_int] = w;
2151 }
2152
2153 totalWidth += w;
2154 widths[i] = totalWidth;
2155 }
2156
2157 return true;
2158 }
2159
2160
2161 // ----------------------------------------------------------------------------
2162 // enhanced text drawing
2163 // ----------------------------------------------------------------------------
2164
2165 void wxDCBase::GetMultiLineTextExtent(const wxString& text,
2166 wxCoord *x,
2167 wxCoord *y,
2168 wxCoord *h,
2169 const wxFont *font) const
2170 {
2171 wxCoord widthTextMax = 0, widthLine,
2172 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
2173
2174 wxString curLine;
2175 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2176 {
2177 if ( pc == text.end() || *pc == _T('\n') )
2178 {
2179 if ( curLine.empty() )
2180 {
2181 // we can't use GetTextExtent - it will return 0 for both width
2182 // and height and an empty line should count in height
2183 // calculation
2184
2185 // assume that this line has the same height as the previous
2186 // one
2187 if ( !heightLineDefault )
2188 heightLineDefault = heightLine;
2189
2190 if ( !heightLineDefault )
2191 {
2192 // but we don't know it yet - choose something reasonable
2193 GetTextExtent(_T("W"), NULL, &heightLineDefault,
2194 NULL, NULL, font);
2195 }
2196
2197 heightTextTotal += heightLineDefault;
2198 }
2199 else
2200 {
2201 GetTextExtent(curLine, &widthLine, &heightLine,
2202 NULL, NULL, font);
2203 if ( widthLine > widthTextMax )
2204 widthTextMax = widthLine;
2205 heightTextTotal += heightLine;
2206 }
2207
2208 if ( pc == text.end() )
2209 {
2210 break;
2211 }
2212 else // '\n'
2213 {
2214 curLine.clear();
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
2231 void 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 {
2287 DrawBitmap(bitmap, x, y, true /* use mask */);
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;
2303 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2304 {
2305 if ( pc == text.end() || *pc == _T('\n') )
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
2343 if ( pc == text.end() )
2344 break;
2345
2346 curLine.clear();
2347 }
2348 else // not end of line
2349 {
2350 if ( pc - text.begin() == indexAccel )
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 }
2386
2387
2388 void 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;
2395 wxBrush oldBrush = m_brush;
2396
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();
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
2431 wxColour colour(nR,nG,nB);
2432 SetPen(wxPen(colour, 1, wxSOLID));
2433 SetBrush(wxBrush(colour));
2434 if(nDirection == wxEAST)
2435 DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(),
2436 xDelta, rect.GetHeight());
2437 else //nDirection == wxWEST
2438 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
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
2468 wxColour colour(nR,nG,nB);
2469 SetPen(wxPen(colour, 1, wxSOLID));
2470 SetBrush(wxBrush(colour));
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);
2481 SetBrush(oldBrush);
2482 }
2483
2484 void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
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
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
2514 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
2515 {
2516 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
2517 {
2518 //get color difference
2519 wxInt32 nGradient = ((nRadius -
2520 (wxInt32)sqrt(
2521 pow((double)(x - cx - nCircleOffX), 2) +
2522 pow((double)(y - cy - nCircleOffY), 2)
2523 )) * 100) / nRadius;
2524
2525 //normalize Gradient
2526 if (nGradient < 0 )
2527 nGradient = 0;
2528
2529 //get dest colors
2530 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2531 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2532 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
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
2543 /*
2544 Notes for wxWidgets DrawEllipticArcRot(...)
2545
2546 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2547 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2548 which are also new.
2549
2550 All methods are generic, so they can be implemented in wxDCBase.
2551 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2552 methods like (WinCE) wxDC::DoDrawArc(...).
2553
2554 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2555 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2556 parts) or every column (in steep parts) only one pixel is calculated.
2557 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2558 starting angle is not equal to the ending angle. The calculation of the
2559 pixels is done using simple arithmetic only and should perform not too
2560 bad even on devices without floating point processor. I didn't test this yet.
2561
2562 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2563 For instance: an ellipse rotated 180 degrees is drawn
2564 slightly different from the original.
2565
2566 The points are then moved to an array and used to draw a polyline and/or polygon
2567 (with center added, the pie).
2568 The result looks quite similar to the native ellipse, only e few pixels differ.
2569
2570 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2571 slower as DrawEllipse(...), which calls the native API.
2572 An rotated ellipse outside the clipping region takes nearly the same time,
2573 while an native ellipse outside takes nearly no time to draw.
2574
2575 If you draw an arc with this new method, you will see the starting and ending angles
2576 are calculated properly.
2577 If you use DrawEllipticArc(...), you will see they are only correct for circles
2578 and not properly calculated for ellipses.
2579
2580 Peter Lenhard
2581 p.lenhard@t-online.de
2582 */
2583
2584 #ifdef __WXWINCE__
2585 void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2586 wxCoord w, wxCoord h,
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
2598 int n = list.GetCount();
2599 wxPoint *points = new wxPoint[n];
2600 int i = 0;
2601 wxNode* node = 0;
2602 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
2603 {
2604 wxPoint *point = (wxPoint *)node->GetData();
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
2611 if( GetBrush() != *wxTRANSPARENT_BRUSH )
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
2620 if( GetPen() != *wxTRANSPARENT_PEN )
2621 {
2622 // without center
2623 DoDrawLines( n-1, points, 0, 0 );
2624 }
2625
2626 delete [] points;
2627
2628 } // DrawEllipticArcRot
2629
2630 void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
2631 {
2632 if( angle != 0.0 )
2633 {
2634 double pi(M_PI);
2635 double dSinA = -sin(angle*2.0*pi/360.0);
2636 double dCosA = cos(angle*2.0*pi/360.0);
2637 for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() )
2638 {
2639 wxPoint* point = (wxPoint*)node->GetData();
2640
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
2657 void wxDCBase::CalculateEllipticPoints( wxList* points,
2658 wxCoord xStart, wxCoord yStart,
2659 wxCoord w, wxCoord h,
2660 double sa, double ea )
2661 {
2662 double pi = M_PI;
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;
2679 if( 2*a == w ) decrX = 1;
2680 int decrY = 0;
2681 if( 2*b == h ) decrY = 1;
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 ) );
2705 if ( sq == 1 || sq == 2 ) sar += pi;
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 }
2744 // old y now to big: set point with old y, old x
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
2755
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 {
2775 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
2776 {
2777 // once: go to starting point in start quadrant
2778 if( !bStarted &&
2779 (
2780 ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1
2781 ||
2782 ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2
2783 )
2784 )
2785 {
2786 bStarted = true;
2787 }
2788
2789 // copy point, if not at ending point
2790 if( bStarted )
2791 {
2792 if( q != eq || bForceTurn
2793 ||
2794 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2795 ||
2796 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
2797 )
2798 {
2799 // copy point
2800 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) );
2801 points->Append( (wxObject*) pPoint );
2802 }
2803 else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea)
2804 {
2805 bReady = true;
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 {
2819 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
2820 {
2821 wxPoint *p = (wxPoint *)node->GetData();
2822 delete p;
2823 }
2824 }
2825 }
2826 else
2827 {
2828 wxNode* node;
2829 // copy whole ellipse, wxPoints will be deleted outside
2830 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
2831 {
2832 wxObject *p = node->GetData();
2833 points->Append( p );
2834 }
2835 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
2836 {
2837 wxObject *p = node->GetData();
2838 points->Append( p );
2839 }
2840 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
2841 {
2842 wxObject *p = node->GetData();
2843 points->Append( p );
2844 }
2845 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
2846 {
2847 wxObject *p = node->GetData();
2848 points->Append( p );
2849 }
2850 } // not iUseAngles
2851 } // CalculateEllipticPoints
2852
2853 #endif // __WXWINCE__
2854
2855 #endif // wxUSE_NEW_DC