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