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