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