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