Compile with printarch off
[wxWidgets.git] / src / common / dcbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 05/25/99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/dc.h"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.h"
30 #include "wx/dcscreen.h"
31 #include "wx/dcprint.h"
32 #include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
33 #include "wx/prntbase.h"
34
35 #ifndef WX_PRECOMP
36 #include "wx/math.h"
37 #endif
38
39 #ifdef __WXMSW__
40 #include "wx/msw/dcclient.h"
41 #include "wx/msw/dcmemory.h"
42 #include "wx/msw/dcscreen.h"
43 #endif
44
45 #ifdef __WXGTK__
46 #include "wx/gtk/dcclient.h"
47 #include "wx/gtk/dcmemory.h"
48 #include "wx/gtk/dcscreen.h"
49 #endif
50
51 #ifdef __WXMAC__
52 #include "wx/mac/dcclient.h"
53 #include "wx/mac/dcmemory.h"
54 #include "wx/mac/dcscreen.h"
55 #endif
56
57 #ifdef __WXX11__
58 #include "wx/x11/dcclient.h"
59 #include "wx/x11/dcmemory.h"
60 #include "wx/x11/dcscreen.h"
61 #endif
62
63 //----------------------------------------------------------------------------
64 // wxDCFactory
65 //----------------------------------------------------------------------------
66
67 wxDCFactory *wxDCFactory::m_factory = NULL;
68
69 void wxDCFactory::SetDCFactory( wxDCFactory *factory )
70 {
71 if (wxDCFactory::m_factory)
72 delete wxDCFactory::m_factory;
73
74 wxDCFactory::m_factory = factory;
75 }
76
77 wxDCFactory *wxDCFactory::GetFactory()
78 {
79 if (!wxDCFactory::m_factory)
80 wxDCFactory::m_factory = new wxNativeDCFactory;
81
82 return wxDCFactory::m_factory;
83 }
84
85 //-----------------------------------------------------------------------------
86 // wxNativeDCFactory
87 //-----------------------------------------------------------------------------
88
89 wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
90 {
91 return new wxWindowDCImpl( owner );
92 }
93
94 wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
95 {
96 return new wxWindowDCImpl( owner, window );
97 }
98
99 wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
100 {
101 return new wxClientDCImpl( owner );
102 }
103
104 wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
105 {
106 return new wxClientDCImpl( owner, window );
107 }
108
109 wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
110 {
111 return new wxPaintDCImpl( owner );
112 }
113
114 wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
115 {
116 return new wxPaintDCImpl( owner, window );
117 }
118
119 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
120 {
121 return new wxMemoryDCImpl( owner );
122 }
123
124 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
125 {
126 return new wxMemoryDCImpl( owner, bitmap );
127 }
128
129 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
130 {
131 return new wxMemoryDCImpl( owner, dc );
132 }
133
134 wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
135 {
136 return new wxScreenDCImpl( owner );
137 }
138
139 #if wxUSE_PRINTING_ARCHITECTURE
140 wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
141 {
142 wxPrintFactory *factory = wxPrintFactory::GetFactory();
143 return factory->CreatePrinterDCImpl( owner, data );
144 }
145 #endif
146
147 //-----------------------------------------------------------------------------
148 // wxWindowDC
149 //-----------------------------------------------------------------------------
150
151 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
152
153 wxWindowDC::wxWindowDC()
154 {
155 }
156
157 wxWindowDC::wxWindowDC( wxWindow *win )
158 {
159 wxDCFactory *factory = wxDCFactory::GetFactory();
160 m_pimpl = factory->CreateWindowDC( this, win );
161 }
162
163 //-----------------------------------------------------------------------------
164 // wxClientDC
165 //-----------------------------------------------------------------------------
166
167 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
168
169 wxClientDC::wxClientDC()
170 {
171 }
172
173 wxClientDC::wxClientDC( wxWindow *win )
174 {
175 wxDCFactory *factory = wxDCFactory::GetFactory();
176 m_pimpl = factory->CreateClientDC( this, win );
177 }
178
179 //-----------------------------------------------------------------------------
180 // wxMemoryDC
181 //-----------------------------------------------------------------------------
182
183 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
184
185 wxMemoryDC::wxMemoryDC()
186 {
187 wxDCFactory *factory = wxDCFactory::GetFactory();
188 m_pimpl = factory->CreateMemoryDC( this );
189 }
190
191 wxMemoryDC::wxMemoryDC( wxBitmap& bitmap )
192 {
193 wxDCFactory *factory = wxDCFactory::GetFactory();
194 m_pimpl = factory->CreateMemoryDC( this, bitmap );
195 }
196
197 wxMemoryDC::wxMemoryDC( wxDC *dc )
198 {
199 wxDCFactory *factory = wxDCFactory::GetFactory();
200 m_pimpl = factory->CreateMemoryDC( this, dc );
201 }
202
203 void wxMemoryDC::SelectObject(wxBitmap& bmp)
204 {
205 // make sure that the given wxBitmap is not sharing its data with other
206 // wxBitmap instances as its contents will be modified by any drawing
207 // operation done on this DC
208 if (bmp.IsOk())
209 bmp.UnShare();
210
211 GetImpl()->DoSelect(bmp);
212 }
213
214 void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
215 {
216 GetImpl()->DoSelect(bmp);
217 }
218
219 const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
220 {
221 return GetImpl()->GetSelectedBitmap();
222 }
223
224 wxBitmap& wxMemoryDC::GetSelectedBitmap()
225 {
226 return GetImpl()->GetSelectedBitmap();
227 }
228
229
230 //-----------------------------------------------------------------------------
231 // wxPaintDC
232 //-----------------------------------------------------------------------------
233
234 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
235
236 wxPaintDC::wxPaintDC()
237 {
238 }
239
240 wxPaintDC::wxPaintDC( wxWindow *win )
241 {
242 wxDCFactory *factory = wxDCFactory::GetFactory();
243 m_pimpl = factory->CreatePaintDC( this, win );
244 }
245
246 //-----------------------------------------------------------------------------
247 // wxScreenDC
248 //-----------------------------------------------------------------------------
249
250 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
251
252 wxScreenDC::wxScreenDC()
253 {
254 wxDCFactory *factory = wxDCFactory::GetFactory();
255 m_pimpl = factory->CreateScreenDC( this );
256 }
257
258 //-----------------------------------------------------------------------------
259 // wxPrinterDC
260 //-----------------------------------------------------------------------------
261
262 #if wxUSE_PRINTING_ARCHITECTURE
263
264 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
265
266 wxPrinterDC::wxPrinterDC()
267 {
268 wxPrintData data; // Does this make sense?
269 wxDCFactory *factory = wxDCFactory::GetFactory();
270 m_pimpl = factory->CreatePrinterDC( this, data );
271 }
272
273 wxPrinterDC::wxPrinterDC( const wxPrintData &data )
274 {
275 wxDCFactory *factory = wxDCFactory::GetFactory();
276 m_pimpl = factory->CreatePrinterDC( this, data );
277 }
278
279 wxPrinterDC::~wxPrinterDC()
280 {
281 }
282
283 wxRect wxPrinterDC::GetPaperRect()
284 {
285 return GetImpl()->GetPaperRect();
286 }
287
288 int wxPrinterDC::GetResolution()
289 {
290 return GetImpl()->GetResolution();
291 }
292
293 #endif
294
295 //-----------------------------------------------------------------------------
296 // wxDCImpl
297 //-----------------------------------------------------------------------------
298
299 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
300
301 wxDCImpl::wxDCImpl( wxDC *owner )
302 : m_window(NULL)
303 , m_colour(wxColourDisplay())
304 , m_ok(true)
305 , m_clipping(false)
306 , m_isInteractive(0)
307 , m_isBBoxValid(false)
308 , m_logicalOriginX(0), m_logicalOriginY(0)
309 , m_deviceOriginX(0), m_deviceOriginY(0)
310 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
311 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
312 , m_userScaleX(1.0), m_userScaleY(1.0)
313 , m_scaleX(1.0), m_scaleY(1.0)
314 , m_signX(1), m_signY(1)
315 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
316 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
317 , m_logicalFunction(wxCOPY)
318 , m_backgroundMode(wxTRANSPARENT)
319 , m_mappingMode(wxMM_TEXT)
320 , m_pen()
321 , m_brush()
322 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
323 , m_textForegroundColour(*wxBLACK)
324 , m_textBackgroundColour(*wxWHITE)
325 , m_font()
326 #if wxUSE_PALETTE
327 , m_palette()
328 , m_hasCustomPalette(false)
329 #endif // wxUSE_PALETTE
330 {
331 m_owner = owner;
332
333 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
334 (double)wxGetDisplaySizeMM().GetWidth();
335 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
336 (double)wxGetDisplaySizeMM().GetHeight();
337
338 ResetBoundingBox();
339 ResetClipping();
340 }
341
342 wxDCImpl::~wxDCImpl()
343 {
344 }
345
346 // ----------------------------------------------------------------------------
347 // coordinate conversions and transforms
348 // ----------------------------------------------------------------------------
349
350 wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
351 {
352 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
353 }
354
355 wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
356 {
357 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
358 }
359
360 wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
361 {
362 return wxRound((double)(x) / m_scaleX);
363 }
364
365 wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
366 {
367 return wxRound((double)(y) / m_scaleY);
368 }
369
370 wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
371 {
372 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
373 }
374
375 wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
376 {
377 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY;
378 }
379
380 wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
381 {
382 return wxRound((double)(x) * m_scaleX);
383 }
384
385 wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
386 {
387 return wxRound((double)(y) * m_scaleY);
388 }
389
390 void wxDCImpl::ComputeScaleAndOrigin()
391 {
392 m_scaleX = m_logicalScaleX * m_userScaleX;
393 m_scaleY = m_logicalScaleY * m_userScaleY;
394 }
395
396 void wxDCImpl::SetMapMode( int mode )
397 {
398 switch (mode)
399 {
400 case wxMM_TWIPS:
401 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
402 break;
403 case wxMM_POINTS:
404 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
405 break;
406 case wxMM_METRIC:
407 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
408 break;
409 case wxMM_LOMETRIC:
410 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
411 break;
412 default:
413 case wxMM_TEXT:
414 SetLogicalScale( 1.0, 1.0 );
415 break;
416 }
417 m_mappingMode = mode;
418 }
419
420 void wxDCImpl::SetUserScale( double x, double y )
421 {
422 // allow negative ? -> no
423 m_userScaleX = x;
424 m_userScaleY = y;
425 ComputeScaleAndOrigin();
426 }
427
428 void wxDCImpl::SetLogicalScale( double x, double y )
429 {
430 // allow negative ?
431 m_logicalScaleX = x;
432 m_logicalScaleY = y;
433 ComputeScaleAndOrigin();
434 }
435
436 void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
437 {
438 m_logicalOriginX = x * m_signX;
439 m_logicalOriginY = y * m_signY;
440 ComputeScaleAndOrigin();
441 }
442
443 void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
444 {
445 m_deviceOriginX = x;
446 m_deviceOriginY = y;
447 ComputeScaleAndOrigin();
448 }
449
450 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
451 {
452 m_deviceLocalOriginX = x;
453 m_deviceLocalOriginY = y;
454 ComputeScaleAndOrigin();
455 }
456
457 void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
458 {
459 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
460 // wxWidgets 2.9: no longer override it
461 m_signX = (xLeftRight ? 1 : -1);
462 m_signY = (yBottomUp ? -1 : 1);
463 ComputeScaleAndOrigin();
464 }
465
466
467 // Each element of the widths array will be the width of the string up to and
468 // including the corresponding character in text. This is the generic
469 // implementation, the port-specific classes should do this with native APIs
470 // if available and if faster. Note: pango_layout_index_to_pos is much slower
471 // than calling GetTextExtent!!
472
473 #define FWC_SIZE 256
474
475 class FontWidthCache
476 {
477 public:
478 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
479 ~FontWidthCache() { delete []m_widths; }
480
481 void Reset()
482 {
483 if (!m_widths)
484 m_widths = new int[FWC_SIZE];
485
486 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
487 }
488
489 wxFont m_font;
490 double m_scaleX;
491 int *m_widths;
492 };
493
494 static FontWidthCache s_fontWidthCache;
495
496 bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
497 {
498 int totalWidth = 0;
499
500 const size_t len = text.length();
501 widths.Empty();
502 widths.Add(0, len);
503
504 // reset the cache if font or horizontal scale have changed
505 if ( !s_fontWidthCache.m_widths ||
506 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
507 (s_fontWidthCache.m_font != GetFont()) )
508 {
509 s_fontWidthCache.Reset();
510 s_fontWidthCache.m_font = GetFont();
511 s_fontWidthCache.m_scaleX = m_scaleX;
512 }
513
514 // Calculate the position of each character based on the widths of
515 // the previous characters
516 int w, h;
517 for ( size_t i = 0; i < len; i++ )
518 {
519 const wxChar c = text[i];
520 unsigned int c_int = (unsigned int)c;
521
522 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
523 {
524 w = s_fontWidthCache.m_widths[c_int];
525 }
526 else
527 {
528 DoGetTextExtent(c, &w, &h);
529 if (c_int < FWC_SIZE)
530 s_fontWidthCache.m_widths[c_int] = w;
531 }
532
533 totalWidth += w;
534 widths[i] = totalWidth;
535 }
536
537 return true;
538 }
539
540 void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
541 wxCoord *x,
542 wxCoord *y,
543 wxCoord *h,
544 const wxFont *font) const
545 {
546 wxCoord widthTextMax = 0, widthLine,
547 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
548
549 wxString curLine;
550 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
551 {
552 if ( pc == text.end() || *pc == _T('\n') )
553 {
554 if ( curLine.empty() )
555 {
556 // we can't use GetTextExtent - it will return 0 for both width
557 // and height and an empty line should count in height
558 // calculation
559
560 // assume that this line has the same height as the previous
561 // one
562 if ( !heightLineDefault )
563 heightLineDefault = heightLine;
564
565 if ( !heightLineDefault )
566 {
567 // but we don't know it yet - choose something reasonable
568 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
569 NULL, NULL, font);
570 }
571
572 heightTextTotal += heightLineDefault;
573 }
574 else
575 {
576 DoGetTextExtent(curLine, &widthLine, &heightLine,
577 NULL, NULL, font);
578 if ( widthLine > widthTextMax )
579 widthTextMax = widthLine;
580 heightTextTotal += heightLine;
581 }
582
583 if ( pc == text.end() )
584 {
585 break;
586 }
587 else // '\n'
588 {
589 curLine.clear();
590 }
591 }
592 else
593 {
594 curLine += *pc;
595 }
596 }
597
598 if ( x )
599 *x = widthTextMax;
600 if ( y )
601 *y = heightTextTotal;
602 if ( h )
603 *h = heightLine;
604 }
605
606 void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
607 wxCoord width, wxCoord height)
608 {
609 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
610
611 wxCoord x2 = x1 + width,
612 y2 = y1 + height;
613
614 // the pen width is calibrated to give 3 for width == height == 10
615 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
616
617 // we're drawing a scaled version of wx/generic/tick.xpm here
618 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
619 y3 = y1 + height / 2; // y of the left tick branch
620 DoDrawLine(x1, y3, x3, y2);
621 DoDrawLine(x3, y2, x2, y1);
622
623 CalcBoundingBox(x1, y1);
624 CalcBoundingBox(x2, y2);
625 }
626
627 bool
628 wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
629 wxCoord dstWidth, wxCoord dstHeight,
630 wxDC *source,
631 wxCoord xsrc, wxCoord ysrc,
632 wxCoord srcWidth, wxCoord srcHeight,
633 int rop,
634 bool useMask,
635 wxCoord xsrcMask,
636 wxCoord ysrcMask)
637 {
638 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
639 _T("invalid blit size") );
640
641 // emulate the stretching by modifying the DC scale
642 double xscale = (double)srcWidth/dstWidth,
643 yscale = (double)srcHeight/dstHeight;
644
645 double xscaleOld, yscaleOld;
646 GetUserScale(&xscaleOld, &yscaleOld);
647 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
648
649 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
650 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
651 source,
652 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
653
654 SetUserScale(xscaleOld, yscaleOld);
655
656 return rc;
657 }
658
659 void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
660 {
661 int n = list->GetCount();
662 wxPoint *points = new wxPoint[n];
663
664 int i = 0;
665 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
666 {
667 wxPoint *point = node->GetData();
668 points[i].x = point->x;
669 points[i].y = point->y;
670 }
671
672 DoDrawLines(n, points, xoffset, yoffset);
673
674 delete [] points;
675 }
676
677 void wxDCImpl::DrawPolygon(const wxPointList *list,
678 wxCoord xoffset, wxCoord yoffset,
679 int fillStyle)
680 {
681 int n = list->GetCount();
682 wxPoint *points = new wxPoint[n];
683
684 int i = 0;
685 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
686 {
687 wxPoint *point = node->GetData();
688 points[i].x = point->x;
689 points[i].y = point->y;
690 }
691
692 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
693
694 delete [] points;
695 }
696
697 void
698 wxDCImpl::DoDrawPolyPolygon(int n,
699 int count[],
700 wxPoint points[],
701 wxCoord xoffset, wxCoord yoffset,
702 int fillStyle)
703 {
704 if ( n == 1 )
705 {
706 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
707 return;
708 }
709
710 int i, j, lastOfs;
711 wxPoint* pts;
712 wxPen pen;
713
714 for (i = j = lastOfs = 0; i < n; i++)
715 {
716 lastOfs = j;
717 j += count[i];
718 }
719 pts = new wxPoint[j+n-1];
720 for (i = 0; i < j; i++)
721 pts[i] = points[i];
722 for (i = 2; i <= n; i++)
723 {
724 lastOfs -= count[n-i];
725 pts[j++] = pts[lastOfs];
726 }
727
728 pen = GetPen();
729 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
730 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
731 SetPen(pen);
732 for (i = j = 0; i < n; i++)
733 {
734 DoDrawLines(count[i], pts+j, xoffset, yoffset);
735 j += count[i];
736 }
737 delete[] pts;
738 }
739
740 #if wxUSE_SPLINES
741
742 void wxDCImpl::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
743 {
744 wxPointList point_list;
745
746 wxPoint *point1 = new wxPoint;
747 point1->x = x1; point1->y = y1;
748 point_list.Append( point1 );
749
750 wxPoint *point2 = new wxPoint;
751 point2->x = x2; point2->y = y2;
752 point_list.Append( point2 );
753
754 wxPoint *point3 = new wxPoint;
755 point3->x = x3; point3->y = y3;
756 point_list.Append( point3 );
757
758 DoDrawSpline(&point_list);
759
760 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
761 {
762 wxPoint *p = node->GetData();
763 delete p;
764 }
765 }
766
767 void wxDCImpl::DoDrawSpline(int n, wxPoint points[])
768 {
769 wxPointList list;
770 for (int i =0; i < n; i++)
771 list.Append( &points[i] );
772
773 DoDrawSpline(&list);
774 }
775
776 // ----------------------------------- spline code ----------------------------------------
777
778 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
779 double a3, double b3, double a4, double b4);
780 void wx_clear_stack();
781 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
782 double *y3, double *x4, double *y4);
783 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
784 double x4, double y4);
785 static bool wx_spline_add_point(double x, double y);
786 static void wx_spline_draw_point_array(wxDC *dc);
787
788 wxPointList wx_spline_point_list;
789
790 #define half(z1, z2) ((z1+z2)/2.0)
791 #define THRESHOLD 5
792
793 /* iterative version */
794
795 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
796 double b4)
797 {
798 register double xmid, ymid;
799 double x1, y1, x2, y2, x3, y3, x4, y4;
800
801 wx_clear_stack();
802 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
803
804 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
805 xmid = (double)half(x2, x3);
806 ymid = (double)half(y2, y3);
807 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
808 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
809 wx_spline_add_point( x1, y1 );
810 wx_spline_add_point( xmid, ymid );
811 } else {
812 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
813 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
814 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
815 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
816 }
817 }
818 }
819
820 /* utilities used by spline drawing routines */
821
822 typedef struct wx_spline_stack_struct {
823 double x1, y1, x2, y2, x3, y3, x4, y4;
824 } Stack;
825
826 #define SPLINE_STACK_DEPTH 20
827 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
828 static Stack *wx_stack_top;
829 static int wx_stack_count;
830
831 void wx_clear_stack()
832 {
833 wx_stack_top = wx_spline_stack;
834 wx_stack_count = 0;
835 }
836
837 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
838 {
839 wx_stack_top->x1 = x1;
840 wx_stack_top->y1 = y1;
841 wx_stack_top->x2 = x2;
842 wx_stack_top->y2 = y2;
843 wx_stack_top->x3 = x3;
844 wx_stack_top->y3 = y3;
845 wx_stack_top->x4 = x4;
846 wx_stack_top->y4 = y4;
847 wx_stack_top++;
848 wx_stack_count++;
849 }
850
851 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
852 double *x3, double *y3, double *x4, double *y4)
853 {
854 if (wx_stack_count == 0)
855 return (0);
856 wx_stack_top--;
857 wx_stack_count--;
858 *x1 = wx_stack_top->x1;
859 *y1 = wx_stack_top->y1;
860 *x2 = wx_stack_top->x2;
861 *y2 = wx_stack_top->y2;
862 *x3 = wx_stack_top->x3;
863 *y3 = wx_stack_top->y3;
864 *x4 = wx_stack_top->x4;
865 *y4 = wx_stack_top->y4;
866 return (1);
867 }
868
869 static bool wx_spline_add_point(double x, double y)
870 {
871 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
872 wx_spline_point_list.Append(point );
873 return true;
874 }
875
876 static void wx_spline_draw_point_array(wxDC *dc)
877 {
878 dc->DrawLines(&wx_spline_point_list, 0, 0 );
879 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
880 while (node)
881 {
882 wxPoint *point = node->GetData();
883 delete point;
884 wx_spline_point_list.Erase(node);
885 node = wx_spline_point_list.GetFirst();
886 }
887 }
888
889 void wxDCImpl::DoDrawSpline( const wxPointList *points )
890 {
891 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
892
893 wxPoint *p;
894 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
895 double x1, y1, x2, y2;
896
897 wxPointList::compatibility_iterator node = points->GetFirst();
898 if (!node)
899 // empty list
900 return;
901
902 p = (wxPoint *)node->GetData();
903
904 x1 = p->x;
905 y1 = p->y;
906
907 node = node->GetNext();
908 p = node->GetData();
909
910 x2 = p->x;
911 y2 = p->y;
912 cx1 = (double)((x1 + x2) / 2);
913 cy1 = (double)((y1 + y2) / 2);
914 cx2 = (double)((cx1 + x2) / 2);
915 cy2 = (double)((cy1 + y2) / 2);
916
917 wx_spline_add_point(x1, y1);
918
919 while ((node = node->GetNext())
920 #if !wxUSE_STL
921 != NULL
922 #endif // !wxUSE_STL
923 )
924 {
925 p = node->GetData();
926 x1 = x2;
927 y1 = y2;
928 x2 = p->x;
929 y2 = p->y;
930 cx4 = (double)(x1 + x2) / 2;
931 cy4 = (double)(y1 + y2) / 2;
932 cx3 = (double)(x1 + cx4) / 2;
933 cy3 = (double)(y1 + cy4) / 2;
934
935 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
936
937 cx1 = cx4;
938 cy1 = cy4;
939 cx2 = (double)(cx1 + x2) / 2;
940 cy2 = (double)(cy1 + y2) / 2;
941 }
942
943 wx_spline_add_point( cx1, cy1 );
944 wx_spline_add_point( x2, y2 );
945
946 wx_spline_draw_point_array( m_owner );
947 }
948
949 #endif // wxUSE_SPLINES
950
951
952
953 void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
954 const wxColour& initialColour,
955 const wxColour& destColour,
956 wxDirection nDirection)
957 {
958 // save old pen
959 wxPen oldPen = m_pen;
960 wxBrush oldBrush = m_brush;
961
962 wxUint8 nR1 = initialColour.Red();
963 wxUint8 nG1 = initialColour.Green();
964 wxUint8 nB1 = initialColour.Blue();
965 wxUint8 nR2 = destColour.Red();
966 wxUint8 nG2 = destColour.Green();
967 wxUint8 nB2 = destColour.Blue();
968 wxUint8 nR, nG, nB;
969
970 if ( nDirection == wxEAST || nDirection == wxWEST )
971 {
972 wxInt32 x = rect.GetWidth();
973 wxInt32 w = x; // width of area to shade
974 wxInt32 xDelta = w/256; // height of one shade bend
975 if (xDelta < 1)
976 xDelta = 1;
977
978 while (x >= xDelta)
979 {
980 x -= xDelta;
981 if (nR1 > nR2)
982 nR = nR1 - (nR1-nR2)*(w-x)/w;
983 else
984 nR = nR1 + (nR2-nR1)*(w-x)/w;
985
986 if (nG1 > nG2)
987 nG = nG1 - (nG1-nG2)*(w-x)/w;
988 else
989 nG = nG1 + (nG2-nG1)*(w-x)/w;
990
991 if (nB1 > nB2)
992 nB = nB1 - (nB1-nB2)*(w-x)/w;
993 else
994 nB = nB1 + (nB2-nB1)*(w-x)/w;
995
996 wxColour colour(nR,nG,nB);
997 SetPen(wxPen(colour, 1, wxSOLID));
998 SetBrush(wxBrush(colour));
999 if(nDirection == wxEAST)
1000 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
1001 xDelta, rect.GetHeight());
1002 else //nDirection == wxWEST
1003 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1004 xDelta, rect.GetHeight());
1005 }
1006 }
1007 else // nDirection == wxNORTH || nDirection == wxSOUTH
1008 {
1009 wxInt32 y = rect.GetHeight();
1010 wxInt32 w = y; // height of area to shade
1011 wxInt32 yDelta = w/255; // height of one shade bend
1012 if (yDelta < 1)
1013 yDelta = 1;
1014
1015 while (y > 0)
1016 {
1017 y -= yDelta;
1018 if (nR1 > nR2)
1019 nR = nR1 - (nR1-nR2)*(w-y)/w;
1020 else
1021 nR = nR1 + (nR2-nR1)*(w-y)/w;
1022
1023 if (nG1 > nG2)
1024 nG = nG1 - (nG1-nG2)*(w-y)/w;
1025 else
1026 nG = nG1 + (nG2-nG1)*(w-y)/w;
1027
1028 if (nB1 > nB2)
1029 nB = nB1 - (nB1-nB2)*(w-y)/w;
1030 else
1031 nB = nB1 + (nB2-nB1)*(w-y)/w;
1032
1033 wxColour colour(nR,nG,nB);
1034 SetPen(wxPen(colour, 1, wxSOLID));
1035 SetBrush(wxBrush(colour));
1036 if(nDirection == wxNORTH)
1037 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1038 rect.GetWidth(), yDelta);
1039 else //nDirection == wxSOUTH
1040 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
1041 rect.GetWidth(), yDelta);
1042 }
1043 }
1044
1045 SetPen(oldPen);
1046 SetBrush(oldBrush);
1047 }
1048
1049 void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
1050 const wxColour& initialColour,
1051 const wxColour& destColour,
1052 const wxPoint& circleCenter)
1053 {
1054 //save the old pen color
1055 wxColour oldPenColour = m_pen.GetColour();
1056
1057 wxUint8 nR1 = destColour.Red();
1058 wxUint8 nG1 = destColour.Green();
1059 wxUint8 nB1 = destColour.Blue();
1060 wxUint8 nR2 = initialColour.Red();
1061 wxUint8 nG2 = initialColour.Green();
1062 wxUint8 nB2 = initialColour.Blue();
1063 wxUint8 nR, nG, nB;
1064
1065
1066 //Radius
1067 wxInt32 cx = rect.GetWidth() / 2;
1068 wxInt32 cy = rect.GetHeight() / 2;
1069 wxInt32 nRadius;
1070 if (cx < cy)
1071 nRadius = cx;
1072 else
1073 nRadius = cy;
1074
1075 //Offset of circle
1076 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1077 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1078
1079 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1080 {
1081 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1082 {
1083 //get color difference
1084 wxInt32 nGradient = ((nRadius -
1085 (wxInt32)sqrt(
1086 pow((double)(x - cx - nCircleOffX), 2) +
1087 pow((double)(y - cy - nCircleOffY), 2)
1088 )) * 100) / nRadius;
1089
1090 //normalize Gradient
1091 if (nGradient < 0 )
1092 nGradient = 0;
1093
1094 //get dest colors
1095 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1096 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1097 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1098
1099 //set the pixel
1100 m_pen.SetColour(wxColour(nR,nG,nB));
1101 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
1102 }
1103 }
1104 //return old pen color
1105 m_pen.SetColour(oldPenColour);
1106 }
1107
1108 //-----------------------------------------------------------------------------
1109 // wxDC
1110 //-----------------------------------------------------------------------------
1111
1112 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1113
1114 void wxDC::DrawLabel(const wxString& text,
1115 const wxBitmap& bitmap,
1116 const wxRect& rect,
1117 int alignment,
1118 int indexAccel,
1119 wxRect *rectBounding)
1120 {
1121 // find the text position
1122 wxCoord widthText, heightText, heightLine;
1123 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1124
1125 wxCoord width, height;
1126 if ( bitmap.Ok() )
1127 {
1128 width = widthText + bitmap.GetWidth();
1129 height = bitmap.GetHeight();
1130 }
1131 else // no bitmap
1132 {
1133 width = widthText;
1134 height = heightText;
1135 }
1136
1137 wxCoord x, y;
1138 if ( alignment & wxALIGN_RIGHT )
1139 {
1140 x = rect.GetRight() - width;
1141 }
1142 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1143 {
1144 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1145 }
1146 else // alignment & wxALIGN_LEFT
1147 {
1148 x = rect.GetLeft();
1149 }
1150
1151 if ( alignment & wxALIGN_BOTTOM )
1152 {
1153 y = rect.GetBottom() - height;
1154 }
1155 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1156 {
1157 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1158 }
1159 else // alignment & wxALIGN_TOP
1160 {
1161 y = rect.GetTop();
1162 }
1163
1164 // draw the bitmap first
1165 wxCoord x0 = x,
1166 y0 = y,
1167 width0 = width;
1168 if ( bitmap.Ok() )
1169 {
1170 DrawBitmap(bitmap, x, y, true /* use mask */);
1171
1172 wxCoord offset = bitmap.GetWidth() + 4;
1173 x += offset;
1174 width -= offset;
1175
1176 y += (height - heightText) / 2;
1177 }
1178
1179 // we will draw the underscore under the accel char later
1180 wxCoord startUnderscore = 0,
1181 endUnderscore = 0,
1182 yUnderscore = 0;
1183
1184 // split the string into lines and draw each of them separately
1185 wxString curLine;
1186 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1187 {
1188 if ( *pc == _T('\n') || pc == text.end() )
1189 {
1190 int xRealStart = x; // init it here to avoid compielr warnings
1191
1192 if ( !curLine.empty() )
1193 {
1194 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1195 // wxALIGN_LEFT is 0
1196 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1197 {
1198 wxCoord widthLine;
1199 GetTextExtent(curLine, &widthLine, NULL);
1200
1201 if ( alignment & wxALIGN_RIGHT )
1202 {
1203 xRealStart += width - widthLine;
1204 }
1205 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1206 {
1207 xRealStart += (width - widthLine) / 2;
1208 }
1209 }
1210 //else: left aligned, nothing to do
1211
1212 DrawText(curLine, xRealStart, y);
1213 }
1214
1215 y += heightLine;
1216
1217 // do we have underscore in this line? we can check yUnderscore
1218 // because it is set below to just y + heightLine if we do
1219 if ( y == yUnderscore )
1220 {
1221 // adjust the horz positions to account for the shift
1222 startUnderscore += xRealStart;
1223 endUnderscore += xRealStart;
1224 }
1225
1226 if ( pc == text.end() )
1227 break;
1228
1229 curLine.clear();
1230 }
1231 else // not end of line
1232 {
1233 if ( pc - text.begin() == indexAccel )
1234 {
1235 // remeber to draw underscore here
1236 GetTextExtent(curLine, &startUnderscore, NULL);
1237 curLine += *pc;
1238 GetTextExtent(curLine, &endUnderscore, NULL);
1239
1240 yUnderscore = y + heightLine;
1241 }
1242 else
1243 {
1244 curLine += *pc;
1245 }
1246 }
1247 }
1248
1249 // draw the underscore if found
1250 if ( startUnderscore != endUnderscore )
1251 {
1252 // it should be of the same colour as text
1253 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1254
1255 yUnderscore--;
1256
1257 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1258 }
1259
1260 // return bounding rect if requested
1261 if ( rectBounding )
1262 {
1263 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1264 }
1265
1266 CalcBoundingBox(x0, y0);
1267 CalcBoundingBox(x0 + width0, y0 + height);
1268 }
1269
1270 #if WXWIN_COMPATIBILITY_2_8
1271 // for compatibility with the old code when wxCoord was long everywhere
1272 void wxDC::GetTextExtent(const wxString& string,
1273 long *x, long *y,
1274 long *descent,
1275 long *externalLeading,
1276 const wxFont *theFont) const
1277 {
1278 wxCoord x2, y2, descent2, externalLeading2;
1279 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1280 &descent2, &externalLeading2,
1281 theFont);
1282 if ( x )
1283 *x = x2;
1284 if ( y )
1285 *y = y2;
1286 if ( descent )
1287 *descent = descent2;
1288 if ( externalLeading )
1289 *externalLeading = externalLeading2;
1290 }
1291
1292 void wxDC::GetLogicalOrigin(long *x, long *y) const
1293 {
1294 wxCoord x2, y2;
1295 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1296 if ( x )
1297 *x = x2;
1298 if ( y )
1299 *y = y2;
1300 }
1301
1302 void wxDC::GetDeviceOrigin(long *x, long *y) const
1303 {
1304 wxCoord x2, y2;
1305 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1306 if ( x )
1307 *x = x2;
1308 if ( y )
1309 *y = y2;
1310 }
1311
1312 void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1313 {
1314 wxCoord xx,yy,ww,hh;
1315 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1316 if (x) *x = xx;
1317 if (y) *y = yy;
1318 if (w) *w = ww;
1319 if (h) *h = hh;
1320 }
1321
1322 #endif // WXWIN_COMPATIBILITY_2_8