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