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