]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcbase.cpp
Fix bug in Unix wxFileSystemWatcher implementation when watch is deleted.
[wxWidgets.git] / src / common / dcbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 05/25/99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/dc.h"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.h"
30 #include "wx/dcscreen.h"
31 #include "wx/dcprint.h"
32 #include "wx/prntbase.h"
33 #include "wx/scopeguard.h"
34
35 #ifndef WX_PRECOMP
36 #include "wx/math.h"
37 #include "wx/module.h"
38 #include "wx/window.h"
39 #endif
40
41 #ifdef __WXMSW__
42 #include "wx/msw/dcclient.h"
43 #include "wx/msw/dcmemory.h"
44 #include "wx/msw/dcscreen.h"
45 #endif
46
47 #ifdef __WXGTK3__
48 #include "wx/gtk/dc.h"
49 #elif defined __WXGTK20__
50 #include "wx/gtk/dcclient.h"
51 #include "wx/gtk/dcmemory.h"
52 #include "wx/gtk/dcscreen.h"
53 #elif defined(__WXGTK__)
54 #include "wx/gtk1/dcclient.h"
55 #include "wx/gtk1/dcmemory.h"
56 #include "wx/gtk1/dcscreen.h"
57 #endif
58
59 #ifdef __WXMAC__
60 #include "wx/osx/dcclient.h"
61 #include "wx/osx/dcmemory.h"
62 #include "wx/osx/dcscreen.h"
63 #endif
64
65 #ifdef __WXPM__
66 #include "wx/os2/dcclient.h"
67 #include "wx/os2/dcmemory.h"
68 #include "wx/os2/dcscreen.h"
69 #endif
70
71 #ifdef __WXCOCOA__
72 #include "wx/cocoa/dcclient.h"
73 #include "wx/cocoa/dcmemory.h"
74 #include "wx/cocoa/dcscreen.h"
75 #endif
76
77 #ifdef __WXMOTIF__
78 #include "wx/motif/dcclient.h"
79 #include "wx/motif/dcmemory.h"
80 #include "wx/motif/dcscreen.h"
81 #endif
82
83 #ifdef __WXX11__
84 #include "wx/x11/dcclient.h"
85 #include "wx/x11/dcmemory.h"
86 #include "wx/x11/dcscreen.h"
87 #endif
88
89 #ifdef __WXDFB__
90 #include "wx/dfb/dcclient.h"
91 #include "wx/dfb/dcmemory.h"
92 #include "wx/dfb/dcscreen.h"
93 #endif
94
95 //----------------------------------------------------------------------------
96 // wxDCFactory
97 //----------------------------------------------------------------------------
98
99 wxDCFactory *wxDCFactory::m_factory = NULL;
100
101 void wxDCFactory::Set(wxDCFactory *factory)
102 {
103 delete m_factory;
104
105 m_factory = factory;
106 }
107
108 wxDCFactory *wxDCFactory::Get()
109 {
110 if ( !m_factory )
111 m_factory = new wxNativeDCFactory;
112
113 return m_factory;
114 }
115
116 class wxDCFactoryCleanupModule : public wxModule
117 {
118 public:
119 virtual bool OnInit() { return true; }
120 virtual void OnExit() { wxDCFactory::Set(NULL); }
121
122 private:
123 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule)
124 };
125
126 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule)
127
128 //-----------------------------------------------------------------------------
129 // wxNativeDCFactory
130 //-----------------------------------------------------------------------------
131
132 wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
133 {
134 wxDCImpl * const impl = new wxWindowDCImpl( owner, window );
135 impl->InheritAttributes(window);
136 return impl;
137 }
138
139 wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
140 {
141 wxDCImpl * const impl = new wxClientDCImpl( owner, window );
142 impl->InheritAttributes(window);
143 return impl;
144 }
145
146 wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
147 {
148 wxDCImpl * const impl = new wxPaintDCImpl( owner, window );
149 impl->InheritAttributes(window);
150 return impl;
151 }
152
153 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
154 {
155 return new wxMemoryDCImpl( owner );
156 }
157
158 wxDCImpl* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC *owner, wxBitmap& bitmap)
159 {
160 // the bitmap may be modified when it's selected into a memory DC so make
161 // sure changing this bitmap doesn't affect any other shallow copies of it
162 // (see wxMemoryDC::SelectObject())
163 //
164 // notice that we don't provide any ctor equivalent to SelectObjectAsSource
165 // method because this should be rarely needed and easy to work around by
166 // using the default ctor and calling SelectObjectAsSource itself
167 if ( bitmap.IsOk() )
168 bitmap.UnShare();
169
170 return new wxMemoryDCImpl(owner, bitmap);
171 }
172
173 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
174 {
175 return new wxMemoryDCImpl( owner, dc );
176 }
177
178 wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
179 {
180 return new wxScreenDCImpl( owner );
181 }
182
183 #if wxUSE_PRINTING_ARCHITECTURE
184 wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
185 {
186 wxPrintFactory *factory = wxPrintFactory::GetFactory();
187 return factory->CreatePrinterDCImpl( owner, data );
188 }
189 #endif
190
191 //-----------------------------------------------------------------------------
192 // wxWindowDC
193 //-----------------------------------------------------------------------------
194
195 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC)
196
197 wxWindowDC::wxWindowDC(wxWindow *win)
198 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win))
199 {
200 }
201
202 //-----------------------------------------------------------------------------
203 // wxClientDC
204 //-----------------------------------------------------------------------------
205
206 IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC)
207
208 wxClientDC::wxClientDC(wxWindow *win)
209 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win))
210 {
211 }
212
213 //-----------------------------------------------------------------------------
214 // wxMemoryDC
215 //-----------------------------------------------------------------------------
216
217 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
218
219 wxMemoryDC::wxMemoryDC()
220 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
221 {
222 }
223
224 wxMemoryDC::wxMemoryDC(wxBitmap& bitmap)
225 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap))
226 {
227 }
228
229 wxMemoryDC::wxMemoryDC(wxDC *dc)
230 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc))
231 {
232 }
233
234 void wxMemoryDC::SelectObject(wxBitmap& bmp)
235 {
236 if ( bmp.IsSameAs(GetSelectedBitmap()) )
237 {
238 // Nothing to do, this bitmap is already selected.
239 return;
240 }
241
242 // make sure that the given wxBitmap is not sharing its data with other
243 // wxBitmap instances as its contents will be modified by any drawing
244 // operation done on this DC
245 if (bmp.IsOk())
246 bmp.UnShare();
247
248 GetImpl()->DoSelect(bmp);
249 }
250
251 void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
252 {
253 GetImpl()->DoSelect(bmp);
254 }
255
256 const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
257 {
258 return GetImpl()->GetSelectedBitmap();
259 }
260
261 wxBitmap& wxMemoryDC::GetSelectedBitmap()
262 {
263 return GetImpl()->GetSelectedBitmap();
264 }
265
266
267 //-----------------------------------------------------------------------------
268 // wxPaintDC
269 //-----------------------------------------------------------------------------
270
271 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC)
272
273 wxPaintDC::wxPaintDC(wxWindow *win)
274 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win))
275 {
276 }
277
278 //-----------------------------------------------------------------------------
279 // wxScreenDC
280 //-----------------------------------------------------------------------------
281
282 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
283
284 wxScreenDC::wxScreenDC()
285 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
286 {
287 }
288
289 //-----------------------------------------------------------------------------
290 // wxPrinterDC
291 //-----------------------------------------------------------------------------
292
293 #if wxUSE_PRINTING_ARCHITECTURE
294
295 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
296
297 wxPrinterDC::wxPrinterDC()
298 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
299 {
300 }
301
302 wxPrinterDC::wxPrinterDC(const wxPrintData& data)
303 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data))
304 {
305 }
306
307 wxRect wxPrinterDC::GetPaperRect() const
308 {
309 return GetImpl()->GetPaperRect();
310 }
311
312 int wxPrinterDC::GetResolution() const
313 {
314 return GetImpl()->GetResolution();
315 }
316
317 #endif // wxUSE_PRINTING_ARCHITECTURE
318
319 //-----------------------------------------------------------------------------
320 // wxDCImpl
321 //-----------------------------------------------------------------------------
322
323 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
324
325 wxDCImpl::wxDCImpl( wxDC *owner )
326 : m_window(NULL)
327 , m_colour(wxColourDisplay())
328 , m_ok(true)
329 , m_clipping(false)
330 , m_isInteractive(0)
331 , m_isBBoxValid(false)
332 , m_logicalOriginX(0), m_logicalOriginY(0)
333 , m_deviceOriginX(0), m_deviceOriginY(0)
334 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
335 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
336 , m_userScaleX(1.0), m_userScaleY(1.0)
337 , m_scaleX(1.0), m_scaleY(1.0)
338 , m_signX(1), m_signY(1)
339 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
340 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
341 , m_logicalFunction(wxCOPY)
342 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT)
343 , m_mappingMode(wxMM_TEXT)
344 , m_pen()
345 , m_brush()
346 , m_backgroundBrush()
347 , m_textForegroundColour(*wxBLACK)
348 , m_textBackgroundColour(*wxWHITE)
349 , m_font()
350 #if wxUSE_PALETTE
351 , m_palette()
352 , m_hasCustomPalette(false)
353 #endif // wxUSE_PALETTE
354 {
355 m_owner = owner;
356
357 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
358 (double)wxGetDisplaySizeMM().GetWidth();
359 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
360 (double)wxGetDisplaySizeMM().GetHeight();
361
362 ResetBoundingBox();
363 ResetClipping();
364 }
365
366 wxDCImpl::~wxDCImpl()
367 {
368 }
369
370 // ----------------------------------------------------------------------------
371 // clipping
372 // ----------------------------------------------------------------------------
373
374 void wxDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
375 {
376 if ( m_clipping )
377 {
378 m_clipX1 = wxMax( m_clipX1, x );
379 m_clipY1 = wxMax( m_clipY1, y );
380 m_clipX2 = wxMin( m_clipX2, (x + w) );
381 m_clipY2 = wxMin( m_clipY2, (y + h) );
382 }
383 else
384 {
385 m_clipping = true;
386
387 m_clipX1 = x;
388 m_clipY1 = y;
389 m_clipX2 = x + w;
390 m_clipY2 = y + h;
391 }
392 }
393
394 // ----------------------------------------------------------------------------
395 // coordinate conversions and transforms
396 // ----------------------------------------------------------------------------
397
398 wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
399 {
400 return wxRound( (double)((x - m_deviceOriginX - m_deviceLocalOriginX) * m_signX) / m_scaleX ) + m_logicalOriginX ;
401 }
402
403 wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
404 {
405 return wxRound( (double)((y - m_deviceOriginY - m_deviceLocalOriginY) * m_signY) / m_scaleY ) + m_logicalOriginY ;
406 }
407
408 wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
409 {
410 return wxRound((double)(x) / m_scaleX);
411 }
412
413 wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
414 {
415 return wxRound((double)(y) / m_scaleY);
416 }
417
418 wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
419 {
420 return wxRound( (double)((x - m_logicalOriginX) * m_signX) * m_scaleX) + m_deviceOriginX + m_deviceLocalOriginX;
421 }
422
423 wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
424 {
425 return wxRound( (double)((y - m_logicalOriginY) * m_signY) * m_scaleY) + m_deviceOriginY + m_deviceLocalOriginY;
426 }
427
428 wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
429 {
430 return wxRound((double)(x) * m_scaleX);
431 }
432
433 wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
434 {
435 return wxRound((double)(y) * m_scaleY);
436 }
437
438 void wxDCImpl::ComputeScaleAndOrigin()
439 {
440 m_scaleX = m_logicalScaleX * m_userScaleX;
441 m_scaleY = m_logicalScaleY * m_userScaleY;
442 }
443
444 void wxDCImpl::SetMapMode( wxMappingMode mode )
445 {
446 switch (mode)
447 {
448 case wxMM_TWIPS:
449 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
450 break;
451 case wxMM_POINTS:
452 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
453 break;
454 case wxMM_METRIC:
455 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
456 break;
457 case wxMM_LOMETRIC:
458 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
459 break;
460 default:
461 case wxMM_TEXT:
462 SetLogicalScale( 1.0, 1.0 );
463 break;
464 }
465 m_mappingMode = mode;
466 }
467
468 void wxDCImpl::SetUserScale( double x, double y )
469 {
470 // allow negative ? -> no
471 m_userScaleX = x;
472 m_userScaleY = y;
473 ComputeScaleAndOrigin();
474 }
475
476 void wxDCImpl::SetLogicalScale( double x, double y )
477 {
478 // allow negative ?
479 m_logicalScaleX = x;
480 m_logicalScaleY = y;
481 ComputeScaleAndOrigin();
482 }
483
484 void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
485 {
486 m_logicalOriginX = x * m_signX;
487 m_logicalOriginY = y * m_signY;
488 ComputeScaleAndOrigin();
489 }
490
491 void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
492 {
493 m_deviceOriginX = x;
494 m_deviceOriginY = y;
495 ComputeScaleAndOrigin();
496 }
497
498 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
499 {
500 m_deviceLocalOriginX = x;
501 m_deviceLocalOriginY = y;
502 ComputeScaleAndOrigin();
503 }
504
505 void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
506 {
507 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
508 // wxWidgets 2.9: no longer override it
509 m_signX = (xLeftRight ? 1 : -1);
510 m_signY = (yBottomUp ? -1 : 1);
511 ComputeScaleAndOrigin();
512 }
513
514
515 // Each element of the widths array will be the width of the string up to and
516 // including the corresponding character in text. This is the generic
517 // implementation, the port-specific classes should do this with native APIs
518 // if available and if faster. Note: pango_layout_index_to_pos is much slower
519 // than calling GetTextExtent!!
520
521 #define FWC_SIZE 256
522
523 class FontWidthCache
524 {
525 public:
526 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
527 ~FontWidthCache() { delete []m_widths; }
528
529 void Reset()
530 {
531 if (!m_widths)
532 m_widths = new int[FWC_SIZE];
533
534 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
535 }
536
537 wxFont m_font;
538 double m_scaleX;
539 int *m_widths;
540 };
541
542 static FontWidthCache s_fontWidthCache;
543
544 bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
545 {
546 int totalWidth = 0;
547
548 const size_t len = text.length();
549 widths.Empty();
550 widths.Add(0, len);
551
552 // reset the cache if font or horizontal scale have changed
553 if ( !s_fontWidthCache.m_widths ||
554 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
555 (s_fontWidthCache.m_font != GetFont()) )
556 {
557 s_fontWidthCache.Reset();
558 s_fontWidthCache.m_font = GetFont();
559 s_fontWidthCache.m_scaleX = m_scaleX;
560 }
561
562 // Calculate the position of each character based on the widths of
563 // the previous characters
564 int w, h;
565 for ( size_t i = 0; i < len; i++ )
566 {
567 const wxChar c = text[i];
568 unsigned int c_int = (unsigned int)c;
569
570 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
571 {
572 w = s_fontWidthCache.m_widths[c_int];
573 }
574 else
575 {
576 DoGetTextExtent(c, &w, &h);
577 if (c_int < FWC_SIZE)
578 s_fontWidthCache.m_widths[c_int] = w;
579 }
580
581 totalWidth += w;
582 widths[i] = totalWidth;
583 }
584
585 return true;
586 }
587
588 void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
589 wxCoord *x,
590 wxCoord *y,
591 wxCoord *h,
592 const wxFont *font) const
593 {
594 wxCoord widthTextMax = 0, widthLine,
595 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
596
597 wxString curLine;
598 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
599 {
600 if ( pc == text.end() || *pc == wxT('\n') )
601 {
602 if ( curLine.empty() )
603 {
604 // we can't use GetTextExtent - it will return 0 for both width
605 // and height and an empty line should count in height
606 // calculation
607
608 // assume that this line has the same height as the previous
609 // one
610 if ( !heightLineDefault )
611 heightLineDefault = heightLine;
612
613 if ( !heightLineDefault )
614 {
615 // but we don't know it yet - choose something reasonable
616 DoGetTextExtent(wxT("W"), NULL, &heightLineDefault,
617 NULL, NULL, font);
618 }
619
620 heightTextTotal += heightLineDefault;
621 }
622 else
623 {
624 DoGetTextExtent(curLine, &widthLine, &heightLine,
625 NULL, NULL, font);
626 if ( widthLine > widthTextMax )
627 widthTextMax = widthLine;
628 heightTextTotal += heightLine;
629 }
630
631 if ( pc == text.end() )
632 {
633 break;
634 }
635 else // '\n'
636 {
637 curLine.clear();
638 }
639 }
640 else
641 {
642 curLine += *pc;
643 }
644 }
645
646 if ( x )
647 *x = widthTextMax;
648 if ( y )
649 *y = heightTextTotal;
650 if ( h )
651 *h = heightLine;
652 }
653
654 void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
655 wxCoord width, wxCoord height)
656 {
657 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
658
659 wxCoord x2 = x1 + width,
660 y2 = y1 + height;
661
662 // the pen width is calibrated to give 3 for width == height == 10
663 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
664
665 // we're drawing a scaled version of wx/generic/tick.xpm here
666 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
667 y3 = y1 + height / 2; // y of the left tick branch
668 DoDrawLine(x1, y3, x3, y2);
669 DoDrawLine(x3, y2, x2, y1);
670
671 CalcBoundingBox(x1, y1);
672 CalcBoundingBox(x2, y2);
673 }
674
675 bool
676 wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
677 wxCoord dstWidth, wxCoord dstHeight,
678 wxDC *source,
679 wxCoord xsrc, wxCoord ysrc,
680 wxCoord srcWidth, wxCoord srcHeight,
681 wxRasterOperationMode rop,
682 bool useMask,
683 wxCoord xsrcMask,
684 wxCoord ysrcMask)
685 {
686 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
687 wxT("invalid blit size") );
688
689 // emulate the stretching by modifying the DC scale
690 double xscale = (double)srcWidth/dstWidth,
691 yscale = (double)srcHeight/dstHeight;
692
693 double xscaleOld, yscaleOld;
694 GetUserScale(&xscaleOld, &yscaleOld);
695 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
696
697 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
698 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
699 source,
700 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
701
702 SetUserScale(xscaleOld, yscaleOld);
703
704 return rc;
705 }
706
707 void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
708 {
709 int n = list->GetCount();
710 wxPoint *points = new wxPoint[n];
711
712 int i = 0;
713 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
714 {
715 wxPoint *point = node->GetData();
716 points[i].x = point->x;
717 points[i].y = point->y;
718 }
719
720 DoDrawLines(n, points, xoffset, yoffset);
721
722 delete [] points;
723 }
724
725 void wxDCImpl::DrawPolygon(const wxPointList *list,
726 wxCoord xoffset, wxCoord yoffset,
727 wxPolygonFillMode fillStyle)
728 {
729 int n = list->GetCount();
730 wxPoint *points = new wxPoint[n];
731
732 int i = 0;
733 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
734 {
735 wxPoint *point = node->GetData();
736 points[i].x = point->x;
737 points[i].y = point->y;
738 }
739
740 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
741
742 delete [] points;
743 }
744
745 void
746 wxDCImpl::DoDrawPolyPolygon(int n,
747 int count[],
748 wxPoint points[],
749 wxCoord xoffset, wxCoord yoffset,
750 wxPolygonFillMode fillStyle)
751 {
752 if ( n == 1 )
753 {
754 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
755 return;
756 }
757
758 int i, j, lastOfs;
759 wxPoint* pts;
760
761 for (i = j = lastOfs = 0; i < n; i++)
762 {
763 lastOfs = j;
764 j += count[i];
765 }
766 pts = new wxPoint[j+n-1];
767 for (i = 0; i < j; i++)
768 pts[i] = points[i];
769 for (i = 2; i <= n; i++)
770 {
771 lastOfs -= count[n-i];
772 pts[j++] = pts[lastOfs];
773 }
774
775 {
776 wxDCPenChanger setTransp(*m_owner, *wxTRANSPARENT_PEN);
777 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
778 }
779
780 for (i = j = 0; i < n; i++)
781 {
782 DoDrawLines(count[i], pts+j, xoffset, yoffset);
783 j += count[i];
784 }
785 delete[] pts;
786 }
787
788 #if wxUSE_SPLINES
789
790 void wxDCImpl::DrawSpline(wxCoord x1, wxCoord y1,
791 wxCoord x2, wxCoord y2,
792 wxCoord x3, wxCoord y3)
793 {
794 wxPoint points[] = { wxPoint(x1, y1), wxPoint(x2, y2), wxPoint(x3, y3) };
795 DrawSpline(WXSIZEOF(points), points);
796 }
797
798 void wxDCImpl::DrawSpline(int n, wxPoint points[])
799 {
800 wxPointList list;
801 for ( int i = 0; i < n; i++ )
802 list.Append(&points[i]);
803
804 DrawSpline(&list);
805 }
806
807 // ----------------------------------- spline code ----------------------------------------
808
809 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
810 double a3, double b3, double a4, double b4);
811 void wx_clear_stack();
812 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
813 double *y3, double *x4, double *y4);
814 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
815 double x4, double y4);
816 static bool wx_spline_add_point(double x, double y);
817 static void wx_spline_draw_point_array(wxDC *dc);
818
819 static wxPointList wx_spline_point_list;
820
821 #define half(z1, z2) ((z1+z2)/2.0)
822 #define THRESHOLD 5
823
824 /* iterative version */
825
826 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
827 double b4)
828 {
829 register double xmid, ymid;
830 double x1, y1, x2, y2, x3, y3, x4, y4;
831
832 wx_clear_stack();
833 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
834
835 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
836 xmid = (double)half(x2, x3);
837 ymid = (double)half(y2, y3);
838 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
839 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
840 wx_spline_add_point( x1, y1 );
841 wx_spline_add_point( xmid, ymid );
842 } else {
843 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
844 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
845 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
846 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
847 }
848 }
849 }
850
851 /* utilities used by spline drawing routines */
852
853 typedef struct wx_spline_stack_struct {
854 double x1, y1, x2, y2, x3, y3, x4, y4;
855 } Stack;
856
857 #define SPLINE_STACK_DEPTH 20
858 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
859 static Stack *wx_stack_top;
860 static int wx_stack_count;
861
862 void wx_clear_stack()
863 {
864 wx_stack_top = wx_spline_stack;
865 wx_stack_count = 0;
866 }
867
868 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
869 {
870 wx_stack_top->x1 = x1;
871 wx_stack_top->y1 = y1;
872 wx_stack_top->x2 = x2;
873 wx_stack_top->y2 = y2;
874 wx_stack_top->x3 = x3;
875 wx_stack_top->y3 = y3;
876 wx_stack_top->x4 = x4;
877 wx_stack_top->y4 = y4;
878 wx_stack_top++;
879 wx_stack_count++;
880 }
881
882 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
883 double *x3, double *y3, double *x4, double *y4)
884 {
885 if (wx_stack_count == 0)
886 return (0);
887 wx_stack_top--;
888 wx_stack_count--;
889 *x1 = wx_stack_top->x1;
890 *y1 = wx_stack_top->y1;
891 *x2 = wx_stack_top->x2;
892 *y2 = wx_stack_top->y2;
893 *x3 = wx_stack_top->x3;
894 *y3 = wx_stack_top->y3;
895 *x4 = wx_stack_top->x4;
896 *y4 = wx_stack_top->y4;
897 return (1);
898 }
899
900 static bool wx_spline_add_point(double x, double y)
901 {
902 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
903 wx_spline_point_list.Append(point );
904 return true;
905 }
906
907 static void wx_spline_draw_point_array(wxDC *dc)
908 {
909 dc->DrawLines(&wx_spline_point_list, 0, 0 );
910 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
911 while (node)
912 {
913 wxPoint *point = node->GetData();
914 delete point;
915 wx_spline_point_list.Erase(node);
916 node = wx_spline_point_list.GetFirst();
917 }
918 }
919
920 void wxDCImpl::DoDrawSpline( const wxPointList *points )
921 {
922 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
923
924 wxPoint *p;
925 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
926 double x1, y1, x2, y2;
927
928 wxPointList::compatibility_iterator node = points->GetFirst();
929 if (!node)
930 // empty list
931 return;
932
933 p = (wxPoint *)node->GetData();
934
935 x1 = p->x;
936 y1 = p->y;
937
938 node = node->GetNext();
939 p = node->GetData();
940
941 x2 = p->x;
942 y2 = p->y;
943 cx1 = (double)((x1 + x2) / 2);
944 cy1 = (double)((y1 + y2) / 2);
945 cx2 = (double)((cx1 + x2) / 2);
946 cy2 = (double)((cy1 + y2) / 2);
947
948 wx_spline_add_point(x1, y1);
949
950 while ((node = node->GetNext())
951 #if !wxUSE_STD_CONTAINERS
952 != NULL
953 #endif // !wxUSE_STD_CONTAINERS
954 )
955 {
956 p = node->GetData();
957 x1 = x2;
958 y1 = y2;
959 x2 = p->x;
960 y2 = p->y;
961 cx4 = (double)(x1 + x2) / 2;
962 cy4 = (double)(y1 + y2) / 2;
963 cx3 = (double)(x1 + cx4) / 2;
964 cy3 = (double)(y1 + cy4) / 2;
965
966 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
967
968 cx1 = cx4;
969 cy1 = cy4;
970 cx2 = (double)(cx1 + x2) / 2;
971 cy2 = (double)(cy1 + y2) / 2;
972 }
973
974 wx_spline_add_point( cx1, cy1 );
975 wx_spline_add_point( x2, y2 );
976
977 wx_spline_draw_point_array( m_owner );
978 }
979
980 #endif // wxUSE_SPLINES
981
982
983
984 void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
985 const wxColour& initialColour,
986 const wxColour& destColour,
987 wxDirection nDirection)
988 {
989 // save old pen
990 wxPen oldPen = m_pen;
991 wxBrush oldBrush = m_brush;
992
993 wxUint8 nR1 = initialColour.Red();
994 wxUint8 nG1 = initialColour.Green();
995 wxUint8 nB1 = initialColour.Blue();
996 wxUint8 nR2 = destColour.Red();
997 wxUint8 nG2 = destColour.Green();
998 wxUint8 nB2 = destColour.Blue();
999 wxUint8 nR, nG, nB;
1000
1001 if ( nDirection == wxEAST || nDirection == wxWEST )
1002 {
1003 wxInt32 x = rect.GetWidth();
1004 wxInt32 w = x; // width of area to shade
1005 wxInt32 xDelta = w/256; // height of one shade bend
1006 if (xDelta < 1)
1007 xDelta = 1;
1008
1009 while (x >= xDelta)
1010 {
1011 x -= xDelta;
1012 if (nR1 > nR2)
1013 nR = nR1 - (nR1-nR2)*(w-x)/w;
1014 else
1015 nR = nR1 + (nR2-nR1)*(w-x)/w;
1016
1017 if (nG1 > nG2)
1018 nG = nG1 - (nG1-nG2)*(w-x)/w;
1019 else
1020 nG = nG1 + (nG2-nG1)*(w-x)/w;
1021
1022 if (nB1 > nB2)
1023 nB = nB1 - (nB1-nB2)*(w-x)/w;
1024 else
1025 nB = nB1 + (nB2-nB1)*(w-x)/w;
1026
1027 wxColour colour(nR,nG,nB);
1028 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
1029 SetBrush(wxBrush(colour));
1030 if(nDirection == wxEAST)
1031 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
1032 xDelta, rect.GetHeight());
1033 else //nDirection == wxWEST
1034 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1035 xDelta, rect.GetHeight());
1036 }
1037 }
1038 else // nDirection == wxNORTH || nDirection == wxSOUTH
1039 {
1040 wxInt32 y = rect.GetHeight();
1041 wxInt32 w = y; // height of area to shade
1042 wxInt32 yDelta = w/255; // height of one shade bend
1043 if (yDelta < 1)
1044 yDelta = 1;
1045
1046 while (y > 0)
1047 {
1048 y -= yDelta;
1049 if (nR1 > nR2)
1050 nR = nR1 - (nR1-nR2)*(w-y)/w;
1051 else
1052 nR = nR1 + (nR2-nR1)*(w-y)/w;
1053
1054 if (nG1 > nG2)
1055 nG = nG1 - (nG1-nG2)*(w-y)/w;
1056 else
1057 nG = nG1 + (nG2-nG1)*(w-y)/w;
1058
1059 if (nB1 > nB2)
1060 nB = nB1 - (nB1-nB2)*(w-y)/w;
1061 else
1062 nB = nB1 + (nB2-nB1)*(w-y)/w;
1063
1064 wxColour colour(nR,nG,nB);
1065 SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID));
1066 SetBrush(wxBrush(colour));
1067 if(nDirection == wxNORTH)
1068 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1069 rect.GetWidth(), yDelta);
1070 else //nDirection == wxSOUTH
1071 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
1072 rect.GetWidth(), yDelta);
1073 }
1074 }
1075
1076 SetPen(oldPen);
1077 SetBrush(oldBrush);
1078 }
1079
1080 void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
1081 const wxColour& initialColour,
1082 const wxColour& destColour,
1083 const wxPoint& circleCenter)
1084 {
1085 // save the old pen and ensure it is restored on exit
1086 const wxPen penOrig = m_pen;
1087 wxON_BLOCK_EXIT_SET(m_pen, penOrig);
1088
1089 wxUint8 nR1 = destColour.Red();
1090 wxUint8 nG1 = destColour.Green();
1091 wxUint8 nB1 = destColour.Blue();
1092 wxUint8 nR2 = initialColour.Red();
1093 wxUint8 nG2 = initialColour.Green();
1094 wxUint8 nB2 = initialColour.Blue();
1095 wxUint8 nR, nG, nB;
1096
1097
1098 //Radius
1099 double cx = rect.GetWidth() / 2;
1100 double cy = rect.GetHeight() / 2;
1101 double dRadius;
1102 if (cx < cy)
1103 dRadius = cx;
1104 else
1105 dRadius = cy;
1106
1107 //Offset of circle
1108 double ptX, ptY;
1109 ptX = circleCenter.x;
1110 ptY = circleCenter.y;
1111 double nCircleOffX = ptX - cx;
1112 double nCircleOffY = ptY - cy;
1113
1114 double dGradient;
1115 double dx, dy;
1116
1117 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1118 {
1119 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1120 {
1121 //get color difference
1122 dx = x;
1123 dy = y;
1124
1125 dGradient = ((dRadius - sqrt( (dx - cx - nCircleOffX) * (dx - cx - nCircleOffX)
1126 +(dy - cy - nCircleOffY) * (dy - cy - nCircleOffY)
1127 )
1128 ) * 100
1129 ) / dRadius;
1130
1131 //normalize Gradient
1132 if (dGradient < 0)
1133 dGradient = 0.0;
1134
1135 //get dest colors
1136 nR = (wxUint8)(nR1 + ((nR2 - nR1) * dGradient / 100));
1137 nG = (wxUint8)(nG1 + ((nG2 - nG1) * dGradient / 100));
1138 nB = (wxUint8)(nB1 + ((nB2 - nB1) * dGradient / 100));
1139
1140 //set the pixel
1141 SetPen(wxColour(nR,nG,nB));
1142 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
1143 }
1144 }
1145 }
1146
1147 void wxDCImpl::InheritAttributes(wxWindow *win)
1148 {
1149 wxCHECK_RET( win, "window can't be NULL" );
1150
1151 SetFont(win->GetFont());
1152 SetTextForeground(win->GetForegroundColour());
1153 SetTextBackground(win->GetBackgroundColour());
1154 SetBackground(win->GetBackgroundColour());
1155 SetLayoutDirection(win->GetLayoutDirection());
1156 }
1157
1158 void wxDCImpl::DoGetFontMetrics(int *height,
1159 int *ascent,
1160 int *descent,
1161 int *internalLeading,
1162 int *externalLeading,
1163 int *averageWidth) const
1164 {
1165 // Average width is typically the same as width of 'x'.
1166 wxCoord h, d;
1167 DoGetTextExtent("x", averageWidth, &h, &d, externalLeading);
1168
1169 if ( height )
1170 *height = h;
1171 if ( ascent )
1172 *ascent = h - d;
1173 if ( descent )
1174 *descent = d;
1175 if ( internalLeading )
1176 *internalLeading = 0;
1177 }
1178
1179 //-----------------------------------------------------------------------------
1180 // wxDC
1181 //-----------------------------------------------------------------------------
1182
1183 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1184
1185 void wxDC::CopyAttributes(const wxDC& dc)
1186 {
1187 SetFont(dc.GetFont());
1188 SetTextForeground(dc.GetTextForeground());
1189 SetTextBackground(dc.GetTextBackground());
1190 SetBackground(dc.GetBackground());
1191 SetLayoutDirection(dc.GetLayoutDirection());
1192 }
1193
1194 void wxDC::DrawLabel(const wxString& text,
1195 const wxBitmap& bitmap,
1196 const wxRect& rect,
1197 int alignment,
1198 int indexAccel,
1199 wxRect *rectBounding)
1200 {
1201 // find the text position
1202 wxCoord widthText, heightText, heightLine;
1203 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1204
1205 wxCoord width, height;
1206 if ( bitmap.IsOk() )
1207 {
1208 width = widthText + bitmap.GetWidth();
1209 height = bitmap.GetHeight();
1210 }
1211 else // no bitmap
1212 {
1213 width = widthText;
1214 height = heightText;
1215 }
1216
1217 wxCoord x, y;
1218 if ( alignment & wxALIGN_RIGHT )
1219 {
1220 x = rect.GetRight() - width;
1221 }
1222 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1223 {
1224 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1225 }
1226 else // alignment & wxALIGN_LEFT
1227 {
1228 x = rect.GetLeft();
1229 }
1230
1231 if ( alignment & wxALIGN_BOTTOM )
1232 {
1233 y = rect.GetBottom() - height;
1234 }
1235 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1236 {
1237 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1238 }
1239 else // alignment & wxALIGN_TOP
1240 {
1241 y = rect.GetTop();
1242 }
1243
1244 // draw the bitmap first
1245 wxCoord x0 = x,
1246 y0 = y,
1247 width0 = width;
1248 if ( bitmap.IsOk() )
1249 {
1250 DrawBitmap(bitmap, x, y, true /* use mask */);
1251
1252 wxCoord offset = bitmap.GetWidth() + 4;
1253 x += offset;
1254 width -= offset;
1255
1256 y += (height - heightText) / 2;
1257 }
1258
1259 // we will draw the underscore under the accel char later
1260 wxCoord startUnderscore = 0,
1261 endUnderscore = 0,
1262 yUnderscore = 0;
1263
1264 // split the string into lines and draw each of them separately
1265 //
1266 // NB: while wxDC::DrawText() on some platforms supports drawing multi-line
1267 // strings natively, this is not the case for all of them, notably not
1268 // wxMSW which uses this function for multi-line texts, so we may only
1269 // call DrawText() for single-line strings from here to avoid infinite
1270 // recursion.
1271 wxString curLine;
1272 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1273 {
1274 if ( pc == text.end() || *pc == '\n' )
1275 {
1276 int xRealStart = x; // init it here to avoid compielr warnings
1277
1278 if ( !curLine.empty() )
1279 {
1280 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1281 // wxALIGN_LEFT is 0
1282 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1283 {
1284 wxCoord widthLine;
1285 GetTextExtent(curLine, &widthLine, NULL);
1286
1287 if ( alignment & wxALIGN_RIGHT )
1288 {
1289 xRealStart += width - widthLine;
1290 }
1291 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1292 {
1293 xRealStart += (width - widthLine) / 2;
1294 }
1295 }
1296 //else: left aligned, nothing to do
1297
1298 DrawText(curLine, xRealStart, y);
1299 }
1300
1301 y += heightLine;
1302
1303 // do we have underscore in this line? we can check yUnderscore
1304 // because it is set below to just y + heightLine if we do
1305 if ( y == yUnderscore )
1306 {
1307 // adjust the horz positions to account for the shift
1308 startUnderscore += xRealStart;
1309 endUnderscore += xRealStart;
1310 }
1311
1312 if ( pc == text.end() )
1313 break;
1314
1315 curLine.clear();
1316 }
1317 else // not end of line
1318 {
1319 if ( pc - text.begin() == indexAccel )
1320 {
1321 // remember to draw underscore here
1322 GetTextExtent(curLine, &startUnderscore, NULL);
1323 curLine += *pc;
1324 GetTextExtent(curLine, &endUnderscore, NULL);
1325
1326 yUnderscore = y + heightLine;
1327 }
1328 else
1329 {
1330 curLine += *pc;
1331 }
1332 }
1333 }
1334
1335 // draw the underscore if found
1336 if ( startUnderscore != endUnderscore )
1337 {
1338 // it should be of the same colour as text
1339 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID));
1340
1341 // This adjustment is relatively arbitrary: we need to draw the
1342 // underline slightly higher to avoid overflowing the character cell
1343 // but whether we should do it 1, 2 or 3 pixels higher is not clear.
1344 //
1345 // The currently used value seems to be compatible with native MSW
1346 // behaviour, i.e. it results in the same appearance of the owner-drawn
1347 // and normal labels.
1348 yUnderscore -= 2;
1349
1350 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1351 }
1352
1353 // return bounding rect if requested
1354 if ( rectBounding )
1355 {
1356 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1357 }
1358
1359 CalcBoundingBox(x0, y0);
1360 CalcBoundingBox(x0 + width0, y0 + height);
1361 }
1362
1363 #if WXWIN_COMPATIBILITY_2_8
1364 // for compatibility with the old code when wxCoord was long everywhere
1365 void wxDC::GetTextExtent(const wxString& string,
1366 long *x, long *y,
1367 long *descent,
1368 long *externalLeading,
1369 const wxFont *theFont) const
1370 {
1371 wxCoord x2, y2, descent2, externalLeading2;
1372 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1373 &descent2, &externalLeading2,
1374 theFont);
1375 if ( x )
1376 *x = x2;
1377 if ( y )
1378 *y = y2;
1379 if ( descent )
1380 *descent = descent2;
1381 if ( externalLeading )
1382 *externalLeading = externalLeading2;
1383 }
1384
1385 void wxDC::GetLogicalOrigin(long *x, long *y) const
1386 {
1387 wxCoord x2, y2;
1388 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1389 if ( x )
1390 *x = x2;
1391 if ( y )
1392 *y = y2;
1393 }
1394
1395 void wxDC::GetDeviceOrigin(long *x, long *y) const
1396 {
1397 wxCoord x2, y2;
1398 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1399 if ( x )
1400 *x = x2;
1401 if ( y )
1402 *y = y2;
1403 }
1404
1405 void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1406 {
1407 wxCoord xx,yy,ww,hh;
1408 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1409 if (x) *x = xx;
1410 if (y) *y = yy;
1411 if (w) *w = ww;
1412 if (h) *h = hh;
1413 }
1414
1415 void wxDC::DrawObject(wxDrawObject* drawobject)
1416 {
1417 drawobject->Draw(*this);
1418 CalcBoundingBox(drawobject->MinX(),drawobject->MinY());
1419 CalcBoundingBox(drawobject->MaxX(),drawobject->MaxY());
1420 }
1421
1422 #endif // WXWIN_COMPATIBILITY_2_8
1423
1424 /*
1425 Notes for wxWidgets DrawEllipticArcRot(...)
1426
1427 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1428 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1429 which are also new.
1430
1431 All methods are generic, so they can be implemented in wxDCBase.
1432 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1433 methods like (WinCE) wxDC::DoDrawArc(...).
1434
1435 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1436 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1437 parts) or every column (in steep parts) only one pixel is calculated.
1438 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1439 starting angle is not equal to the ending angle. The calculation of the
1440 pixels is done using simple arithmetic only and should perform not too
1441 bad even on devices without floating point processor. I didn't test this yet.
1442
1443 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1444 For instance: an ellipse rotated 180 degrees is drawn
1445 slightly different from the original.
1446
1447 The points are then moved to an array and used to draw a polyline and/or polygon
1448 (with center added, the pie).
1449 The result looks quite similar to the native ellipse, only e few pixels differ.
1450
1451 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1452 slower as DrawEllipse(...), which calls the native API.
1453 An rotated ellipse outside the clipping region takes nearly the same time,
1454 while an native ellipse outside takes nearly no time to draw.
1455
1456 If you draw an arc with this new method, you will see the starting and ending angles
1457 are calculated properly.
1458 If you use DrawEllipticArc(...), you will see they are only correct for circles
1459 and not properly calculated for ellipses.
1460
1461 Peter Lenhard
1462 p.lenhard@t-online.de
1463 */
1464
1465 #ifdef __WXWINCE__
1466 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
1467 wxCoord w, wxCoord h,
1468 double sa, double ea, double angle )
1469 {
1470 wxPointList list;
1471
1472 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
1473 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
1474
1475 // Add center (for polygon/pie)
1476 list.Append( new wxPoint( x+w/2, y+h/2 ) );
1477
1478 // copy list into array and delete list elements
1479 int n = list.GetCount();
1480 wxPoint *points = new wxPoint[n];
1481 int i = 0;
1482 wxPointList::compatibility_iterator node;
1483 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
1484 {
1485 wxPoint *point = node->GetData();
1486 points[i].x = point->x;
1487 points[i].y = point->y;
1488 delete point;
1489 }
1490
1491 // first draw the pie without pen, if necessary
1492 if( GetBrush() != *wxTRANSPARENT_BRUSH )
1493 {
1494 wxPen tempPen( GetPen() );
1495 SetPen( *wxTRANSPARENT_PEN );
1496 DoDrawPolygon( n, points, 0, 0 );
1497 SetPen( tempPen );
1498 }
1499
1500 // then draw the arc without brush, if necessary
1501 if( GetPen() != *wxTRANSPARENT_PEN )
1502 {
1503 // without center
1504 DoDrawLines( n-1, points, 0, 0 );
1505 }
1506
1507 delete [] points;
1508
1509 } // DrawEllipticArcRot
1510
1511 void wxDCImpl::Rotate( wxPointList* points, double angle, wxPoint center )
1512 {
1513 if( angle != 0.0 )
1514 {
1515 double pi(M_PI);
1516 double dSinA = -sin(angle*2.0*pi/360.0);
1517 double dCosA = cos(angle*2.0*pi/360.0);
1518 wxPointList::compatibility_iterator node;
1519 for ( node = points->GetFirst(); node; node = node->GetNext() )
1520 {
1521 wxPoint* point = node->GetData();
1522
1523 // transform coordinates, if necessary
1524 if( center.x ) point->x -= center.x;
1525 if( center.y ) point->y -= center.y;
1526
1527 // calculate rotation, rounding simply by implicit cast to integer
1528 int xTemp = point->x * dCosA - point->y * dSinA;
1529 point->y = point->x * dSinA + point->y * dCosA;
1530 point->x = xTemp;
1531
1532 // back transform coordinates, if necessary
1533 if( center.x ) point->x += center.x;
1534 if( center.y ) point->y += center.y;
1535 }
1536 }
1537 }
1538
1539 void wxDCImpl::CalculateEllipticPoints( wxPointList* points,
1540 wxCoord xStart, wxCoord yStart,
1541 wxCoord w, wxCoord h,
1542 double sa, double ea )
1543 {
1544 double pi = M_PI;
1545 double sar = 0;
1546 double ear = 0;
1547 int xsa = 0;
1548 int ysa = 0;
1549 int xea = 0;
1550 int yea = 0;
1551 int sq = 0;
1552 int eq = 0;
1553 bool bUseAngles = false;
1554 if( w<0 ) w = -w;
1555 if( h<0 ) h = -h;
1556 // half-axes
1557 wxCoord a = w/2;
1558 wxCoord b = h/2;
1559 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1560 int decrX = 0;
1561 if( 2*a == w ) decrX = 1;
1562 int decrY = 0;
1563 if( 2*b == h ) decrY = 1;
1564 // center
1565 wxCoord xCenter = xStart + a;
1566 wxCoord yCenter = yStart + b;
1567 // calculate data for start and end, if necessary
1568 if( sa != ea )
1569 {
1570 bUseAngles = true;
1571 // normalisation of angles
1572 while( sa<0 ) sa += 360;
1573 while( ea<0 ) ea += 360;
1574 while( sa>=360 ) sa -= 360;
1575 while( ea>=360 ) ea -= 360;
1576 // calculate quadrant numbers
1577 if( sa > 270 ) sq = 3;
1578 else if( sa > 180 ) sq = 2;
1579 else if( sa > 90 ) sq = 1;
1580 if( ea > 270 ) eq = 3;
1581 else if( ea > 180 ) eq = 2;
1582 else if( ea > 90 ) eq = 1;
1583 sar = sa * pi / 180.0;
1584 ear = ea * pi / 180.0;
1585 // correct angle circle -> ellipse
1586 sar = atan( -a/(double)b * tan( sar ) );
1587 if ( sq == 1 || sq == 2 ) sar += pi;
1588 ear = atan( -a/(double)b * tan( ear ) );
1589 if ( eq == 1 || eq == 2 ) ear += pi;
1590 // coordinates of points
1591 xsa = xCenter + a * cos( sar );
1592 if( sq == 0 || sq == 3 ) xsa -= decrX;
1593 ysa = yCenter + b * sin( sar );
1594 if( sq == 2 || sq == 3 ) ysa -= decrY;
1595 xea = xCenter + a * cos( ear );
1596 if( eq == 0 || eq == 3 ) xea -= decrX;
1597 yea = yCenter + b * sin( ear );
1598 if( eq == 2 || eq == 3 ) yea -= decrY;
1599 } // if iUseAngles
1600 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1601 double c1 = b * b;
1602 double c2 = 2.0 / w;
1603 c2 *= c2;
1604 c2 *= c1;
1605 wxCoord x = 0;
1606 wxCoord y = b;
1607 long x2 = 1;
1608 long y2 = y*y;
1609 long y2_old = 0;
1610 long y_old = 0;
1611 // Lists for quadrant 1 to 4
1612 wxPointList pointsarray[4];
1613 // Calculate points for first quadrant and set in all quadrants
1614 for( x = 0; x <= a; ++x )
1615 {
1616 x2 = x2+x+x-1;
1617 y2_old = y2;
1618 y_old = y;
1619 bool bNewPoint = false;
1620 while( y2 > c1 - c2 * x2 && y > 0 )
1621 {
1622 bNewPoint = true;
1623 y2 = y2-y-y+1;
1624 --y;
1625 }
1626 // old y now too big: set point with old y, old x
1627 if( bNewPoint && x>1)
1628 {
1629 int x1 = x - 1;
1630 // remove points on the same line
1631 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
1632 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
1633 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
1634 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
1635 } // set point
1636 } // calculate point
1637
1638 // Starting and/or ending points for the quadrants, first quadrant gets both.
1639 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
1640 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
1641 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
1642 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
1643 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
1644
1645 // copy quadrants in original list
1646 if( bUseAngles )
1647 {
1648 // Copy the right part of the points in the lists
1649 // and delete the wxPoints, because they do not leave this method.
1650 points->Append( new wxPoint( xsa, ysa ) );
1651 int q = sq;
1652 bool bStarted = false;
1653 bool bReady = false;
1654 bool bForceTurn = ( sq == eq && sa > ea );
1655 while( !bReady )
1656 {
1657 wxPointList::compatibility_iterator node;
1658 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1659 {
1660 // once: go to starting point in start quadrant
1661 if( !bStarted &&
1662 (
1663 node->GetData()->x < xsa+1 && q <= 1
1664 ||
1665 node->GetData()->x > xsa-1 && q >= 2
1666 )
1667 )
1668 {
1669 bStarted = true;
1670 }
1671
1672 // copy point, if not at ending point
1673 if( bStarted )
1674 {
1675 if( q != eq || bForceTurn
1676 ||
1677 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
1678 ||
1679 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
1680 )
1681 {
1682 // copy point
1683 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
1684 points->Append( pPoint );
1685 }
1686 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
1687 {
1688 bReady = true;
1689 }
1690 }
1691 } // for node
1692 ++q;
1693 if( q > 3 ) q = 0;
1694 bForceTurn = false;
1695 bStarted = true;
1696 } // while not bReady
1697 points->Append( new wxPoint( xea, yea ) );
1698
1699 // delete points
1700 for( q = 0; q < 4; ++q )
1701 {
1702 wxPointList::compatibility_iterator node;
1703 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
1704 {
1705 wxPoint *p = node->GetData();
1706 delete p;
1707 }
1708 }
1709 }
1710 else
1711 {
1712 wxPointList::compatibility_iterator node;
1713 // copy whole ellipse, wxPoints will be deleted outside
1714 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
1715 {
1716 wxPoint *p = node->GetData();
1717 points->Append( p );
1718 }
1719 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
1720 {
1721 wxPoint *p = node->GetData();
1722 points->Append( p );
1723 }
1724 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
1725 {
1726 wxPoint *p = node->GetData();
1727 points->Append( p );
1728 }
1729 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
1730 {
1731 wxPoint *p = node->GetData();
1732 points->Append( p );
1733 }
1734 } // not iUseAngles
1735 } // CalculateEllipticPoints
1736
1737 #endif // __WXWINCE__
1738
1739 float wxDCImpl::GetFontPointSizeAdjustment(float dpi)
1740 {
1741 // wxMSW has long-standing bug where wxFont point size is interpreted as
1742 // "pixel size corresponding to given point size *on screen*". In other
1743 // words, on a typical 600dpi printer and a typical 96dpi screen, fonts
1744 // are ~6 times smaller when printing. Unfortunately, this bug is so severe
1745 // that *all* printing code has to account for it and consequently, other
1746 // ports need to emulate this bug too:
1747 const wxSize screenPPI = wxGetDisplayPPI();
1748 return float(screenPPI.y) / dpi;
1749 }