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