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