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