DC reorganization
[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/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
33 #include "wx/prntbase.h"
34
35 #ifndef WX_PRECOMP
36 #include "wx/math.h"
37 #endif
38
39 #if wxUSE_NEW_DC
40
41 #ifdef __WXMSW__
42 #include "wx/msw/dcclient.h"
43 #include "wx/msw/dcmemory.h"
44 #include "wx/msw/dcscreen.h"
45 #endif
46
47 #ifdef __WXGTK__
48 #include "wx/gtk/dcclient.h"
49 #include "wx/gtk/dcmemory.h"
50 #include "wx/gtk/dcscreen.h"
51 #endif
52
53 #ifdef __WXMAC__
54 #include "wx/mac/dcclient.h"
55 #include "wx/mac/dcmemory.h"
56 #include "wx/mac/dcscreen.h"
57 #endif
58
59 //----------------------------------------------------------------------------
60 // wxDCFactory
61 //----------------------------------------------------------------------------
62
63 wxDCFactory *wxDCFactory::m_factory = NULL;
64
65 void wxDCFactory::SetDCFactory( wxDCFactory *factory )
66 {
67 if (wxDCFactory::m_factory)
68 delete wxDCFactory::m_factory;
69
70 wxDCFactory::m_factory = factory;
71 }
72
73 wxDCFactory *wxDCFactory::GetFactory()
74 {
75 if (!wxDCFactory::m_factory)
76 wxDCFactory::m_factory = new wxNativeDCFactory;
77
78 return wxDCFactory::m_factory;
79 }
80
81 //-----------------------------------------------------------------------------
82 // wxNativeDCFactory
83 //-----------------------------------------------------------------------------
84
85 wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
86 {
87 return new wxWindowDCImpl( owner );
88 }
89
90 wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
91 {
92 return new wxWindowDCImpl( owner, window );
93 }
94
95 wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
96 {
97 return new wxClientDCImpl( owner );
98 }
99
100 wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
101 {
102 return new wxClientDCImpl( owner, window );
103 }
104
105 wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
106 {
107 return new wxPaintDCImpl( owner );
108 }
109
110 wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
111 {
112 return new wxPaintDCImpl( owner, window );
113 }
114
115 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
116 {
117 return new wxMemoryDCImpl( owner );
118 }
119
120 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
121 {
122 return new wxMemoryDCImpl( owner, bitmap );
123 }
124
125 wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
126 {
127 return new wxMemoryDCImpl( owner, dc );
128 }
129
130 wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
131 {
132 return new wxScreenDCImpl( owner );
133 }
134
135 wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
136 {
137 wxPrintFactory *factory = wxPrintFactory::GetFactory();
138 return factory->CreatePrinterDCImpl( owner, data );
139 }
140
141 //-----------------------------------------------------------------------------
142 // wxWindowDC
143 //-----------------------------------------------------------------------------
144
145 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
146
147 wxWindowDC::wxWindowDC()
148 {
149 }
150
151 wxWindowDC::wxWindowDC( wxWindow *win )
152 {
153 wxDCFactory *factory = wxDCFactory::GetFactory();
154 m_pimpl = factory->CreateWindowDC( this, win );
155 }
156
157 //-----------------------------------------------------------------------------
158 // wxClientDC
159 //-----------------------------------------------------------------------------
160
161 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
162
163 wxClientDC::wxClientDC()
164 {
165 }
166
167 wxClientDC::wxClientDC( wxWindow *win )
168 {
169 wxDCFactory *factory = wxDCFactory::GetFactory();
170 m_pimpl = factory->CreateClientDC( this, win );
171 }
172
173 //-----------------------------------------------------------------------------
174 // wxMemoryDC
175 //-----------------------------------------------------------------------------
176
177 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
178
179 wxMemoryDC::wxMemoryDC()
180 {
181 wxDCFactory *factory = wxDCFactory::GetFactory();
182 m_pimpl = factory->CreateMemoryDC( this );
183 }
184
185 wxMemoryDC::wxMemoryDC( wxBitmap& bitmap )
186 {
187 wxDCFactory *factory = wxDCFactory::GetFactory();
188 m_pimpl = factory->CreateMemoryDC( this, bitmap );
189 }
190
191 wxMemoryDC::wxMemoryDC( wxDC *dc )
192 {
193 wxDCFactory *factory = wxDCFactory::GetFactory();
194 m_pimpl = factory->CreateMemoryDC( this, dc );
195 }
196
197 void wxMemoryDC::SelectObject(wxBitmap& bmp)
198 {
199 // make sure that the given wxBitmap is not sharing its data with other
200 // wxBitmap instances as its contents will be modified by any drawing
201 // operation done on this DC
202 if (bmp.IsOk())
203 bmp.UnShare();
204
205 GetImpl()->DoSelect(bmp);
206 }
207
208 void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
209 {
210 GetImpl()->DoSelect(bmp);
211 }
212
213 const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
214 {
215 return GetImpl()->GetSelectedBitmap();
216 }
217
218 wxBitmap& wxMemoryDC::GetSelectedBitmap()
219 {
220 return GetImpl()->GetSelectedBitmap();
221 }
222
223
224 //-----------------------------------------------------------------------------
225 // wxPaintDC
226 //-----------------------------------------------------------------------------
227
228 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
229
230 wxPaintDC::wxPaintDC()
231 {
232 }
233
234 wxPaintDC::wxPaintDC( wxWindow *win )
235 {
236 wxDCFactory *factory = wxDCFactory::GetFactory();
237 m_pimpl = factory->CreatePaintDC( this, win );
238 }
239
240 //-----------------------------------------------------------------------------
241 // wxScreenDC
242 //-----------------------------------------------------------------------------
243
244 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
245
246 wxScreenDC::wxScreenDC()
247 {
248 wxDCFactory *factory = wxDCFactory::GetFactory();
249 m_pimpl = factory->CreateScreenDC( this );
250 }
251
252 //-----------------------------------------------------------------------------
253 // wxPrinterDC
254 //-----------------------------------------------------------------------------
255
256 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
257
258 wxPrinterDC::wxPrinterDC()
259 {
260 wxPrintData data; // Does this make sense?
261 wxDCFactory *factory = wxDCFactory::GetFactory();
262 m_pimpl = factory->CreatePrinterDC( this, data );
263 }
264
265 wxPrinterDC::wxPrinterDC( const wxPrintData &data )
266 {
267 wxDCFactory *factory = wxDCFactory::GetFactory();
268 m_pimpl = factory->CreatePrinterDC( this, data );
269 }
270
271 wxPrinterDC::~wxPrinterDC()
272 {
273 }
274
275 wxRect wxPrinterDC::GetPaperRect()
276 {
277 return GetImpl()->GetPaperRect();
278 }
279
280 int wxPrinterDC::GetResolution()
281 {
282 return GetImpl()->GetResolution();
283 }
284
285
286 //-----------------------------------------------------------------------------
287 // wxDCImpl
288 //-----------------------------------------------------------------------------
289
290 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
291
292 wxDCImpl::wxDCImpl( wxDC *owner )
293 : m_window(NULL)
294 , m_colour(wxColourDisplay())
295 , m_ok(true)
296 , m_clipping(false)
297 , m_isInteractive(0)
298 , m_isBBoxValid(false)
299 , m_logicalOriginX(0), m_logicalOriginY(0)
300 , m_deviceOriginX(0), m_deviceOriginY(0)
301 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
302 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
303 , m_userScaleX(1.0), m_userScaleY(1.0)
304 , m_scaleX(1.0), m_scaleY(1.0)
305 , m_signX(1), m_signY(1)
306 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
307 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
308 , m_logicalFunction(wxCOPY)
309 , m_backgroundMode(wxTRANSPARENT)
310 , m_mappingMode(wxMM_TEXT)
311 , m_pen()
312 , m_brush()
313 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
314 , m_textForegroundColour(*wxBLACK)
315 , m_textBackgroundColour(*wxWHITE)
316 , m_font()
317 #if wxUSE_PALETTE
318 , m_palette()
319 , m_hasCustomPalette(false)
320 #endif // wxUSE_PALETTE
321 {
322 m_owner = owner;
323
324 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
325 (double)wxGetDisplaySizeMM().GetWidth();
326 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
327 (double)wxGetDisplaySizeMM().GetHeight();
328
329 ResetBoundingBox();
330 ResetClipping();
331 }
332
333 wxDCImpl::~wxDCImpl()
334 {
335 }
336
337 // ----------------------------------------------------------------------------
338 // coordinate conversions and transforms
339 // ----------------------------------------------------------------------------
340
341 wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
342 {
343 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
344 }
345
346 wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
347 {
348 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
349 }
350
351 wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
352 {
353 return wxRound((double)(x) / m_scaleX);
354 }
355
356 wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
357 {
358 return wxRound((double)(y) / m_scaleY);
359 }
360
361 wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
362 {
363 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
364 }
365
366 wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
367 {
368 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY;
369 }
370
371 wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
372 {
373 return wxRound((double)(x) * m_scaleX);
374 }
375
376 wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
377 {
378 return wxRound((double)(y) * m_scaleY);
379 }
380
381 void wxDCImpl::ComputeScaleAndOrigin()
382 {
383 m_scaleX = m_logicalScaleX * m_userScaleX;
384 m_scaleY = m_logicalScaleY * m_userScaleY;
385 }
386
387 void wxDCImpl::SetMapMode( int mode )
388 {
389 switch (mode)
390 {
391 case wxMM_TWIPS:
392 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
393 break;
394 case wxMM_POINTS:
395 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
396 break;
397 case wxMM_METRIC:
398 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
399 break;
400 case wxMM_LOMETRIC:
401 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
402 break;
403 default:
404 case wxMM_TEXT:
405 SetLogicalScale( 1.0, 1.0 );
406 break;
407 }
408 m_mappingMode = mode;
409 }
410
411 void wxDCImpl::SetUserScale( double x, double y )
412 {
413 // allow negative ? -> no
414 m_userScaleX = x;
415 m_userScaleY = y;
416 ComputeScaleAndOrigin();
417 }
418
419 void wxDCImpl::SetLogicalScale( double x, double y )
420 {
421 // allow negative ?
422 m_logicalScaleX = x;
423 m_logicalScaleY = y;
424 ComputeScaleAndOrigin();
425 }
426
427 void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
428 {
429 m_logicalOriginX = x * m_signX;
430 m_logicalOriginY = y * m_signY;
431 ComputeScaleAndOrigin();
432 }
433
434 void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
435 {
436 m_deviceOriginX = x;
437 m_deviceOriginY = y;
438 ComputeScaleAndOrigin();
439 }
440
441 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
442 {
443 m_deviceLocalOriginX = x;
444 m_deviceLocalOriginY = y;
445 ComputeScaleAndOrigin();
446 }
447
448 void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
449 {
450 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
451 // wxWidgets 2.9: no longer override it
452 m_signX = (xLeftRight ? 1 : -1);
453 m_signY = (yBottomUp ? -1 : 1);
454 ComputeScaleAndOrigin();
455 }
456
457
458 // Each element of the widths array will be the width of the string up to and
459 // including the corresponding character in text. This is the generic
460 // implementation, the port-specific classes should do this with native APIs
461 // if available and if faster. Note: pango_layout_index_to_pos is much slower
462 // than calling GetTextExtent!!
463
464 #define FWC_SIZE 256
465
466 class FontWidthCache
467 {
468 public:
469 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
470 ~FontWidthCache() { delete []m_widths; }
471
472 void Reset()
473 {
474 if (!m_widths)
475 m_widths = new int[FWC_SIZE];
476
477 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
478 }
479
480 wxFont m_font;
481 double m_scaleX;
482 int *m_widths;
483 };
484
485 static FontWidthCache s_fontWidthCache;
486
487 bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
488 {
489 int totalWidth = 0;
490
491 const size_t len = text.length();
492 widths.Empty();
493 widths.Add(0, len);
494
495 // reset the cache if font or horizontal scale have changed
496 if ( !s_fontWidthCache.m_widths ||
497 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
498 (s_fontWidthCache.m_font != GetFont()) )
499 {
500 s_fontWidthCache.Reset();
501 s_fontWidthCache.m_font = GetFont();
502 s_fontWidthCache.m_scaleX = m_scaleX;
503 }
504
505 // Calculate the position of each character based on the widths of
506 // the previous characters
507 int w, h;
508 for ( size_t i = 0; i < len; i++ )
509 {
510 const wxChar c = text[i];
511 unsigned int c_int = (unsigned int)c;
512
513 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
514 {
515 w = s_fontWidthCache.m_widths[c_int];
516 }
517 else
518 {
519 DoGetTextExtent(c, &w, &h);
520 if (c_int < FWC_SIZE)
521 s_fontWidthCache.m_widths[c_int] = w;
522 }
523
524 totalWidth += w;
525 widths[i] = totalWidth;
526 }
527
528 return true;
529 }
530
531 void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
532 wxCoord *x,
533 wxCoord *y,
534 wxCoord *h,
535 const wxFont *font) const
536 {
537 wxCoord widthTextMax = 0, widthLine,
538 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
539
540 wxString curLine;
541 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
542 {
543 if ( pc == text.end() || *pc == _T('\n') )
544 {
545 if ( curLine.empty() )
546 {
547 // we can't use GetTextExtent - it will return 0 for both width
548 // and height and an empty line should count in height
549 // calculation
550
551 // assume that this line has the same height as the previous
552 // one
553 if ( !heightLineDefault )
554 heightLineDefault = heightLine;
555
556 if ( !heightLineDefault )
557 {
558 // but we don't know it yet - choose something reasonable
559 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
560 NULL, NULL, font);
561 }
562
563 heightTextTotal += heightLineDefault;
564 }
565 else
566 {
567 DoGetTextExtent(curLine, &widthLine, &heightLine,
568 NULL, NULL, font);
569 if ( widthLine > widthTextMax )
570 widthTextMax = widthLine;
571 heightTextTotal += heightLine;
572 }
573
574 if ( pc == text.end() )
575 {
576 break;
577 }
578 else // '\n'
579 {
580 curLine.clear();
581 }
582 }
583 else
584 {
585 curLine += *pc;
586 }
587 }
588
589 if ( x )
590 *x = widthTextMax;
591 if ( y )
592 *y = heightTextTotal;
593 if ( h )
594 *h = heightLine;
595 }
596
597 void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
598 wxCoord width, wxCoord height)
599 {
600 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
601
602 wxCoord x2 = x1 + width,
603 y2 = y1 + height;
604
605 // the pen width is calibrated to give 3 for width == height == 10
606 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
607
608 // we're drawing a scaled version of wx/generic/tick.xpm here
609 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
610 y3 = y1 + height / 2; // y of the left tick branch
611 DoDrawLine(x1, y3, x3, y2);
612 DoDrawLine(x3, y2, x2, y1);
613
614 CalcBoundingBox(x1, y1);
615 CalcBoundingBox(x2, y2);
616 }
617
618 bool
619 wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
620 wxCoord dstWidth, wxCoord dstHeight,
621 wxDC *source,
622 wxCoord xsrc, wxCoord ysrc,
623 wxCoord srcWidth, wxCoord srcHeight,
624 int rop,
625 bool useMask,
626 wxCoord xsrcMask,
627 wxCoord ysrcMask)
628 {
629 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
630 _T("invalid blit size") );
631
632 // emulate the stretching by modifying the DC scale
633 double xscale = (double)srcWidth/dstWidth,
634 yscale = (double)srcHeight/dstHeight;
635
636 double xscaleOld, yscaleOld;
637 GetUserScale(&xscaleOld, &yscaleOld);
638 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
639
640 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
641 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
642 source,
643 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
644
645 SetUserScale(xscaleOld, yscaleOld);
646
647 return rc;
648 }
649
650 void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
651 {
652 int n = list->GetCount();
653 wxPoint *points = new wxPoint[n];
654
655 int i = 0;
656 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
657 {
658 wxPoint *point = node->GetData();
659 points[i].x = point->x;
660 points[i].y = point->y;
661 }
662
663 DoDrawLines(n, points, xoffset, yoffset);
664
665 delete [] points;
666 }
667
668 void wxDCImpl::DrawPolygon(const wxPointList *list,
669 wxCoord xoffset, wxCoord yoffset,
670 int fillStyle)
671 {
672 int n = list->GetCount();
673 wxPoint *points = new wxPoint[n];
674
675 int i = 0;
676 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
677 {
678 wxPoint *point = node->GetData();
679 points[i].x = point->x;
680 points[i].y = point->y;
681 }
682
683 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
684
685 delete [] points;
686 }
687
688 void
689 wxDCImpl::DoDrawPolyPolygon(int n,
690 int count[],
691 wxPoint points[],
692 wxCoord xoffset, wxCoord yoffset,
693 int fillStyle)
694 {
695 if ( n == 1 )
696 {
697 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
698 return;
699 }
700
701 int i, j, lastOfs;
702 wxPoint* pts;
703 wxPen pen;
704
705 for (i = j = lastOfs = 0; i < n; i++)
706 {
707 lastOfs = j;
708 j += count[i];
709 }
710 pts = new wxPoint[j+n-1];
711 for (i = 0; i < j; i++)
712 pts[i] = points[i];
713 for (i = 2; i <= n; i++)
714 {
715 lastOfs -= count[n-i];
716 pts[j++] = pts[lastOfs];
717 }
718
719 pen = GetPen();
720 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
721 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
722 SetPen(pen);
723 for (i = j = 0; i < n; i++)
724 {
725 DoDrawLines(count[i], pts+j, xoffset, yoffset);
726 j += count[i];
727 }
728 delete[] pts;
729 }
730
731 #if wxUSE_SPLINES
732
733 void wxDCImpl::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
734 {
735 wxPointList point_list;
736
737 wxPoint *point1 = new wxPoint;
738 point1->x = x1; point1->y = y1;
739 point_list.Append( point1 );
740
741 wxPoint *point2 = new wxPoint;
742 point2->x = x2; point2->y = y2;
743 point_list.Append( point2 );
744
745 wxPoint *point3 = new wxPoint;
746 point3->x = x3; point3->y = y3;
747 point_list.Append( point3 );
748
749 DoDrawSpline(&point_list);
750
751 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
752 {
753 wxPoint *p = node->GetData();
754 delete p;
755 }
756 }
757
758 void wxDCImpl::DoDrawSpline(int n, wxPoint points[])
759 {
760 wxPointList list;
761 for (int i =0; i < n; i++)
762 list.Append( &points[i] );
763
764 DoDrawSpline(&list);
765 }
766
767 // ----------------------------------- spline code ----------------------------------------
768
769 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
770 double a3, double b3, double a4, double b4);
771 void wx_clear_stack();
772 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
773 double *y3, double *x4, double *y4);
774 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
775 double x4, double y4);
776 static bool wx_spline_add_point(double x, double y);
777 static void wx_spline_draw_point_array(wxDC *dc);
778
779 wxPointList wx_spline_point_list;
780
781 #define half(z1, z2) ((z1+z2)/2.0)
782 #define THRESHOLD 5
783
784 /* iterative version */
785
786 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
787 double b4)
788 {
789 register double xmid, ymid;
790 double x1, y1, x2, y2, x3, y3, x4, y4;
791
792 wx_clear_stack();
793 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
794
795 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
796 xmid = (double)half(x2, x3);
797 ymid = (double)half(y2, y3);
798 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
799 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
800 wx_spline_add_point( x1, y1 );
801 wx_spline_add_point( xmid, ymid );
802 } else {
803 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
804 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
805 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
806 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
807 }
808 }
809 }
810
811 /* utilities used by spline drawing routines */
812
813 typedef struct wx_spline_stack_struct {
814 double x1, y1, x2, y2, x3, y3, x4, y4;
815 } Stack;
816
817 #define SPLINE_STACK_DEPTH 20
818 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
819 static Stack *wx_stack_top;
820 static int wx_stack_count;
821
822 void wx_clear_stack()
823 {
824 wx_stack_top = wx_spline_stack;
825 wx_stack_count = 0;
826 }
827
828 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
829 {
830 wx_stack_top->x1 = x1;
831 wx_stack_top->y1 = y1;
832 wx_stack_top->x2 = x2;
833 wx_stack_top->y2 = y2;
834 wx_stack_top->x3 = x3;
835 wx_stack_top->y3 = y3;
836 wx_stack_top->x4 = x4;
837 wx_stack_top->y4 = y4;
838 wx_stack_top++;
839 wx_stack_count++;
840 }
841
842 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
843 double *x3, double *y3, double *x4, double *y4)
844 {
845 if (wx_stack_count == 0)
846 return (0);
847 wx_stack_top--;
848 wx_stack_count--;
849 *x1 = wx_stack_top->x1;
850 *y1 = wx_stack_top->y1;
851 *x2 = wx_stack_top->x2;
852 *y2 = wx_stack_top->y2;
853 *x3 = wx_stack_top->x3;
854 *y3 = wx_stack_top->y3;
855 *x4 = wx_stack_top->x4;
856 *y4 = wx_stack_top->y4;
857 return (1);
858 }
859
860 static bool wx_spline_add_point(double x, double y)
861 {
862 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
863 wx_spline_point_list.Append(point );
864 return true;
865 }
866
867 static void wx_spline_draw_point_array(wxDC *dc)
868 {
869 dc->DrawLines(&wx_spline_point_list, 0, 0 );
870 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
871 while (node)
872 {
873 wxPoint *point = node->GetData();
874 delete point;
875 wx_spline_point_list.Erase(node);
876 node = wx_spline_point_list.GetFirst();
877 }
878 }
879
880 void wxDCImpl::DoDrawSpline( const wxPointList *points )
881 {
882 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
883
884 wxPoint *p;
885 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
886 double x1, y1, x2, y2;
887
888 wxPointList::compatibility_iterator node = points->GetFirst();
889 if (!node)
890 // empty list
891 return;
892
893 p = (wxPoint *)node->GetData();
894
895 x1 = p->x;
896 y1 = p->y;
897
898 node = node->GetNext();
899 p = node->GetData();
900
901 x2 = p->x;
902 y2 = p->y;
903 cx1 = (double)((x1 + x2) / 2);
904 cy1 = (double)((y1 + y2) / 2);
905 cx2 = (double)((cx1 + x2) / 2);
906 cy2 = (double)((cy1 + y2) / 2);
907
908 wx_spline_add_point(x1, y1);
909
910 while ((node = node->GetNext())
911 #if !wxUSE_STL
912 != NULL
913 #endif // !wxUSE_STL
914 )
915 {
916 p = node->GetData();
917 x1 = x2;
918 y1 = y2;
919 x2 = p->x;
920 y2 = p->y;
921 cx4 = (double)(x1 + x2) / 2;
922 cy4 = (double)(y1 + y2) / 2;
923 cx3 = (double)(x1 + cx4) / 2;
924 cy3 = (double)(y1 + cy4) / 2;
925
926 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
927
928 cx1 = cx4;
929 cy1 = cy4;
930 cx2 = (double)(cx1 + x2) / 2;
931 cy2 = (double)(cy1 + y2) / 2;
932 }
933
934 wx_spline_add_point( cx1, cy1 );
935 wx_spline_add_point( x2, y2 );
936
937 wx_spline_draw_point_array( m_owner );
938 }
939
940 #endif // wxUSE_SPLINES
941
942
943
944 void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
945 const wxColour& initialColour,
946 const wxColour& destColour,
947 wxDirection nDirection)
948 {
949 // save old pen
950 wxPen oldPen = m_pen;
951 wxBrush oldBrush = m_brush;
952
953 wxUint8 nR1 = initialColour.Red();
954 wxUint8 nG1 = initialColour.Green();
955 wxUint8 nB1 = initialColour.Blue();
956 wxUint8 nR2 = destColour.Red();
957 wxUint8 nG2 = destColour.Green();
958 wxUint8 nB2 = destColour.Blue();
959 wxUint8 nR, nG, nB;
960
961 if ( nDirection == wxEAST || nDirection == wxWEST )
962 {
963 wxInt32 x = rect.GetWidth();
964 wxInt32 w = x; // width of area to shade
965 wxInt32 xDelta = w/256; // height of one shade bend
966 if (xDelta < 1)
967 xDelta = 1;
968
969 while (x >= xDelta)
970 {
971 x -= xDelta;
972 if (nR1 > nR2)
973 nR = nR1 - (nR1-nR2)*(w-x)/w;
974 else
975 nR = nR1 + (nR2-nR1)*(w-x)/w;
976
977 if (nG1 > nG2)
978 nG = nG1 - (nG1-nG2)*(w-x)/w;
979 else
980 nG = nG1 + (nG2-nG1)*(w-x)/w;
981
982 if (nB1 > nB2)
983 nB = nB1 - (nB1-nB2)*(w-x)/w;
984 else
985 nB = nB1 + (nB2-nB1)*(w-x)/w;
986
987 wxColour colour(nR,nG,nB);
988 SetPen(wxPen(colour, 1, wxSOLID));
989 SetBrush(wxBrush(colour));
990 if(nDirection == wxEAST)
991 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
992 xDelta, rect.GetHeight());
993 else //nDirection == wxWEST
994 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
995 xDelta, rect.GetHeight());
996 }
997 }
998 else // nDirection == wxNORTH || nDirection == wxSOUTH
999 {
1000 wxInt32 y = rect.GetHeight();
1001 wxInt32 w = y; // height of area to shade
1002 wxInt32 yDelta = w/255; // height of one shade bend
1003 if (yDelta < 1)
1004 yDelta = 1;
1005
1006 while (y > 0)
1007 {
1008 y -= yDelta;
1009 if (nR1 > nR2)
1010 nR = nR1 - (nR1-nR2)*(w-y)/w;
1011 else
1012 nR = nR1 + (nR2-nR1)*(w-y)/w;
1013
1014 if (nG1 > nG2)
1015 nG = nG1 - (nG1-nG2)*(w-y)/w;
1016 else
1017 nG = nG1 + (nG2-nG1)*(w-y)/w;
1018
1019 if (nB1 > nB2)
1020 nB = nB1 - (nB1-nB2)*(w-y)/w;
1021 else
1022 nB = nB1 + (nB2-nB1)*(w-y)/w;
1023
1024 wxColour colour(nR,nG,nB);
1025 SetPen(wxPen(colour, 1, wxSOLID));
1026 SetBrush(wxBrush(colour));
1027 if(nDirection == wxNORTH)
1028 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1029 rect.GetWidth(), yDelta);
1030 else //nDirection == wxSOUTH
1031 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
1032 rect.GetWidth(), yDelta);
1033 }
1034 }
1035
1036 SetPen(oldPen);
1037 SetBrush(oldBrush);
1038 }
1039
1040 void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
1041 const wxColour& initialColour,
1042 const wxColour& destColour,
1043 const wxPoint& circleCenter)
1044 {
1045 //save the old pen color
1046 wxColour oldPenColour = m_pen.GetColour();
1047
1048 wxUint8 nR1 = destColour.Red();
1049 wxUint8 nG1 = destColour.Green();
1050 wxUint8 nB1 = destColour.Blue();
1051 wxUint8 nR2 = initialColour.Red();
1052 wxUint8 nG2 = initialColour.Green();
1053 wxUint8 nB2 = initialColour.Blue();
1054 wxUint8 nR, nG, nB;
1055
1056
1057 //Radius
1058 wxInt32 cx = rect.GetWidth() / 2;
1059 wxInt32 cy = rect.GetHeight() / 2;
1060 wxInt32 nRadius;
1061 if (cx < cy)
1062 nRadius = cx;
1063 else
1064 nRadius = cy;
1065
1066 //Offset of circle
1067 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1068 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1069
1070 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1071 {
1072 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1073 {
1074 //get color difference
1075 wxInt32 nGradient = ((nRadius -
1076 (wxInt32)sqrt(
1077 pow((double)(x - cx - nCircleOffX), 2) +
1078 pow((double)(y - cy - nCircleOffY), 2)
1079 )) * 100) / nRadius;
1080
1081 //normalize Gradient
1082 if (nGradient < 0 )
1083 nGradient = 0;
1084
1085 //get dest colors
1086 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1087 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1088 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1089
1090 //set the pixel
1091 m_pen.SetColour(wxColour(nR,nG,nB));
1092 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
1093 }
1094 }
1095 //return old pen color
1096 m_pen.SetColour(oldPenColour);
1097 }
1098
1099 //-----------------------------------------------------------------------------
1100 // wxDC
1101 //-----------------------------------------------------------------------------
1102
1103 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1104
1105 void wxDC::DrawLabel(const wxString& text,
1106 const wxBitmap& bitmap,
1107 const wxRect& rect,
1108 int alignment,
1109 int indexAccel,
1110 wxRect *rectBounding)
1111 {
1112 // find the text position
1113 wxCoord widthText, heightText, heightLine;
1114 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1115
1116 wxCoord width, height;
1117 if ( bitmap.Ok() )
1118 {
1119 width = widthText + bitmap.GetWidth();
1120 height = bitmap.GetHeight();
1121 }
1122 else // no bitmap
1123 {
1124 width = widthText;
1125 height = heightText;
1126 }
1127
1128 wxCoord x, y;
1129 if ( alignment & wxALIGN_RIGHT )
1130 {
1131 x = rect.GetRight() - width;
1132 }
1133 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1134 {
1135 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1136 }
1137 else // alignment & wxALIGN_LEFT
1138 {
1139 x = rect.GetLeft();
1140 }
1141
1142 if ( alignment & wxALIGN_BOTTOM )
1143 {
1144 y = rect.GetBottom() - height;
1145 }
1146 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1147 {
1148 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1149 }
1150 else // alignment & wxALIGN_TOP
1151 {
1152 y = rect.GetTop();
1153 }
1154
1155 // draw the bitmap first
1156 wxCoord x0 = x,
1157 y0 = y,
1158 width0 = width;
1159 if ( bitmap.Ok() )
1160 {
1161 DrawBitmap(bitmap, x, y, true /* use mask */);
1162
1163 wxCoord offset = bitmap.GetWidth() + 4;
1164 x += offset;
1165 width -= offset;
1166
1167 y += (height - heightText) / 2;
1168 }
1169
1170 // we will draw the underscore under the accel char later
1171 wxCoord startUnderscore = 0,
1172 endUnderscore = 0,
1173 yUnderscore = 0;
1174
1175 // split the string into lines and draw each of them separately
1176 wxString curLine;
1177 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1178 {
1179 if ( *pc == _T('\n') || pc == text.end() )
1180 {
1181 int xRealStart = x; // init it here to avoid compielr warnings
1182
1183 if ( !curLine.empty() )
1184 {
1185 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1186 // wxALIGN_LEFT is 0
1187 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1188 {
1189 wxCoord widthLine;
1190 GetTextExtent(curLine, &widthLine, NULL);
1191
1192 if ( alignment & wxALIGN_RIGHT )
1193 {
1194 xRealStart += width - widthLine;
1195 }
1196 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1197 {
1198 xRealStart += (width - widthLine) / 2;
1199 }
1200 }
1201 //else: left aligned, nothing to do
1202
1203 DrawText(curLine, xRealStart, y);
1204 }
1205
1206 y += heightLine;
1207
1208 // do we have underscore in this line? we can check yUnderscore
1209 // because it is set below to just y + heightLine if we do
1210 if ( y == yUnderscore )
1211 {
1212 // adjust the horz positions to account for the shift
1213 startUnderscore += xRealStart;
1214 endUnderscore += xRealStart;
1215 }
1216
1217 if ( pc == text.end() )
1218 break;
1219
1220 curLine.clear();
1221 }
1222 else // not end of line
1223 {
1224 if ( pc - text.begin() == indexAccel )
1225 {
1226 // remeber to draw underscore here
1227 GetTextExtent(curLine, &startUnderscore, NULL);
1228 curLine += *pc;
1229 GetTextExtent(curLine, &endUnderscore, NULL);
1230
1231 yUnderscore = y + heightLine;
1232 }
1233 else
1234 {
1235 curLine += *pc;
1236 }
1237 }
1238 }
1239
1240 // draw the underscore if found
1241 if ( startUnderscore != endUnderscore )
1242 {
1243 // it should be of the same colour as text
1244 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1245
1246 yUnderscore--;
1247
1248 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1249 }
1250
1251 // return bounding rect if requested
1252 if ( rectBounding )
1253 {
1254 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1255 }
1256
1257 CalcBoundingBox(x0, y0);
1258 CalcBoundingBox(x0 + width0, y0 + height);
1259 }
1260
1261 #if WXWIN_COMPATIBILITY_2_8
1262 // for compatibility with the old code when wxCoord was long everywhere
1263 void wxDC::GetTextExtent(const wxString& string,
1264 long *x, long *y,
1265 long *descent,
1266 long *externalLeading,
1267 const wxFont *theFont) const
1268 {
1269 wxCoord x2, y2, descent2, externalLeading2;
1270 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1271 &descent2, &externalLeading2,
1272 theFont);
1273 if ( x )
1274 *x = x2;
1275 if ( y )
1276 *y = y2;
1277 if ( descent )
1278 *descent = descent2;
1279 if ( externalLeading )
1280 *externalLeading = externalLeading2;
1281 }
1282
1283 void wxDC::GetLogicalOrigin(long *x, long *y) const
1284 {
1285 wxCoord x2, y2;
1286 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1287 if ( x )
1288 *x = x2;
1289 if ( y )
1290 *y = y2;
1291 }
1292
1293 void wxDC::GetDeviceOrigin(long *x, long *y) const
1294 {
1295 wxCoord x2, y2;
1296 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1297 if ( x )
1298 *x = x2;
1299 if ( y )
1300 *y = y2;
1301 }
1302
1303 void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1304 {
1305 wxCoord xx,yy,ww,hh;
1306 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1307 if (x) *x = xx;
1308 if (y) *y = yy;
1309 if (w) *w = ww;
1310 if (h) *h = hh;
1311 }
1312
1313 #endif // WXWIN_COMPATIBILITY_2_8
1314
1315
1316 #else // wxUSE_NEW_DC
1317
1318
1319 // bool wxDCBase::sm_cacheing = false;
1320
1321 IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
1322
1323 // ============================================================================
1324 // implementation
1325 // ============================================================================
1326
1327 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
1328 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
1329
1330 wxDCBase::wxDCBase()
1331 : m_colour(wxColourDisplay())
1332 , m_ok(true)
1333 , m_clipping(false)
1334 , m_isInteractive(0)
1335 , m_isBBoxValid(false)
1336 , m_logicalOriginX(0), m_logicalOriginY(0)
1337 , m_deviceOriginX(0), m_deviceOriginY(0)
1338 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1339 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1340 , m_userScaleX(1.0), m_userScaleY(1.0)
1341 , m_scaleX(1.0), m_scaleY(1.0)
1342 , m_signX(1), m_signY(1)
1343 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1344 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1345 , m_logicalFunction(wxCOPY)
1346 , m_backgroundMode(wxTRANSPARENT)
1347 , m_mappingMode(wxMM_TEXT)
1348 , m_pen()
1349 , m_brush()
1350 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
1351 , m_textForegroundColour(*wxBLACK)
1352 , m_textBackgroundColour(*wxWHITE)
1353 , m_font()
1354 #if wxUSE_PALETTE
1355 , m_palette()
1356 , m_hasCustomPalette(false)
1357 #endif // wxUSE_PALETTE
1358 {
1359 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
1360 (double)wxGetDisplaySizeMM().GetWidth();
1361 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
1362 (double)wxGetDisplaySizeMM().GetHeight();
1363
1364 ResetBoundingBox();
1365 ResetClipping();
1366 }
1367
1368 wxDCBase::~wxDCBase()
1369 {
1370 }
1371
1372 #if WXWIN_COMPATIBILITY_2_6
1373 void wxDCBase::BeginDrawing()
1374 {
1375 }
1376
1377 void wxDCBase::EndDrawing()
1378 {
1379 }
1380 #endif // WXWIN_COMPATIBILITY_2_6
1381
1382 #if WXWIN_COMPATIBILITY_2_8
1383 // for compatibility with the old code when wxCoord was long everywhere
1384 void wxDCBase::GetTextExtent(const wxString& string,
1385 long *x, long *y,
1386 long *descent,
1387 long *externalLeading,
1388 const wxFont *theFont) const
1389 {
1390 wxCoord x2, y2, descent2, externalLeading2;
1391 DoGetTextExtent(string, &x2, &y2,
1392 &descent2, &externalLeading2,
1393 theFont);
1394 if ( x )
1395 *x = x2;
1396 if ( y )
1397 *y = y2;
1398 if ( descent )
1399 *descent = descent2;
1400 if ( externalLeading )
1401 *externalLeading = externalLeading2;
1402 }
1403
1404 void wxDCBase::GetLogicalOrigin(long *x, long *y) const
1405 {
1406 wxCoord x2, y2;
1407 DoGetLogicalOrigin(&x2, &y2);
1408 if ( x )
1409 *x = x2;
1410 if ( y )
1411 *y = y2;
1412 }
1413
1414 void wxDCBase::GetDeviceOrigin(long *x, long *y) const
1415 {
1416 wxCoord x2, y2;
1417 DoGetDeviceOrigin(&x2, &y2);
1418 if ( x )
1419 *x = x2;
1420 if ( y )
1421 *y = y2;
1422 }
1423
1424 void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const
1425 {
1426 wxCoord xx,yy,ww,hh;
1427 DoGetClippingBox(&xx, &yy, &ww, &hh);
1428 if (x) *x = xx;
1429 if (y) *y = yy;
1430 if (w) *w = ww;
1431 if (h) *h = hh;
1432 }
1433 #endif // WXWIN_COMPATIBILITY_2_8
1434
1435
1436
1437 // ----------------------------------------------------------------------------
1438 // coordinate conversions and transforms
1439 // ----------------------------------------------------------------------------
1440
1441 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1442 {
1443 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
1444 }
1445
1446 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1447 {
1448 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
1449 }
1450
1451 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1452 {
1453 return wxRound((double)(x) / m_scaleX);
1454 }
1455
1456 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1457 {
1458 return wxRound((double)(y) / m_scaleY);
1459 }
1460
1461 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1462 {
1463 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
1464 }
1465
1466 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1467 {
1468 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
1469 }
1470
1471 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1472 {
1473 return wxRound((double)(x) * m_scaleX);
1474 }
1475
1476 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1477 {
1478 return wxRound((double)(y) * m_scaleY);
1479 }
1480
1481 void wxDCBase::ComputeScaleAndOrigin()
1482 {
1483 m_scaleX = m_logicalScaleX * m_userScaleX;
1484 m_scaleY = m_logicalScaleY * m_userScaleY;
1485 }
1486
1487 void wxDCBase::SetMapMode( int mode )
1488 {
1489 switch (mode)
1490 {
1491 case wxMM_TWIPS:
1492 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
1493 break;
1494 case wxMM_POINTS:
1495 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
1496 break;
1497 case wxMM_METRIC:
1498 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1499 break;
1500 case wxMM_LOMETRIC:
1501 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
1502 break;
1503 default:
1504 case wxMM_TEXT:
1505 SetLogicalScale( 1.0, 1.0 );
1506 break;
1507 }
1508 m_mappingMode = mode;
1509 }
1510
1511 void wxDCBase::SetUserScale( double x, double y )
1512 {
1513 // allow negative ? -> no
1514 m_userScaleX = x;
1515 m_userScaleY = y;
1516 ComputeScaleAndOrigin();
1517 }
1518
1519 void wxDCBase::SetLogicalScale( double x, double y )
1520 {
1521 // allow negative ?
1522 m_logicalScaleX = x;
1523 m_logicalScaleY = y;
1524 ComputeScaleAndOrigin();
1525 }
1526
1527 void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
1528 {
1529 m_logicalOriginX = x * m_signX;
1530 m_logicalOriginY = y * m_signY;
1531 ComputeScaleAndOrigin();
1532 }
1533
1534 void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
1535 {
1536 m_deviceOriginX = x;
1537 m_deviceOriginY = y;
1538 ComputeScaleAndOrigin();
1539 }
1540
1541 void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
1542 {
1543 m_deviceLocalOriginX = x;
1544 m_deviceLocalOriginY = y;
1545 ComputeScaleAndOrigin();
1546 }
1547
1548 void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1549 {
1550 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1551 // wxWidgets 2.9: no longer override it
1552 m_signX = (xLeftRight ? 1 : -1);
1553 m_signY = (yBottomUp ? -1 : 1);
1554 ComputeScaleAndOrigin();
1555 }
1556
1557 // ----------------------------------------------------------------------------
1558 // special symbols
1559 // ----------------------------------------------------------------------------
1560
1561 void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
1562 wxCoord width, wxCoord height)
1563 {
1564 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1565
1566 wxCoord x2 = x1 + width,
1567 y2 = y1 + height;
1568
1569 // the pen width is calibrated to give 3 for width == height == 10
1570 wxDCPenChanger pen((wxDC&)*this,
1571 wxPen(GetTextForeground(), (width + height + 1)/7));
1572
1573 // we're drawing a scaled version of wx/generic/tick.xpm here
1574 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
1575 y3 = y1 + height / 2; // y of the left tick branch
1576 DoDrawLine(x1, y3, x3, y2);
1577 DoDrawLine(x3, y2, x2, y1);
1578
1579 CalcBoundingBox(x1, y1);
1580 CalcBoundingBox(x2, y2);
1581 }
1582
1583 // ----------------------------------------------------------------------------
1584 // stubs for functions not implemented in all ports
1585 // ----------------------------------------------------------------------------
1586
1587 bool
1588 wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
1589 wxCoord dstWidth, wxCoord dstHeight,
1590 wxDC *source,
1591 wxCoord xsrc, wxCoord ysrc,
1592 wxCoord srcWidth, wxCoord srcHeight,
1593 int rop,
1594 bool useMask,
1595 wxCoord xsrcMask,
1596 wxCoord ysrcMask)
1597 {
1598 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
1599 _T("invalid blit size") );
1600
1601 // emulate the stretching by modifying the DC scale
1602 double xscale = (double)srcWidth/dstWidth,
1603 yscale = (double)srcHeight/dstHeight;
1604
1605 double xscaleOld, yscaleOld;
1606 GetUserScale(&xscaleOld, &yscaleOld);
1607 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
1608
1609 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
1610 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
1611 source,
1612 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
1613
1614 SetUserScale(xscaleOld, yscaleOld);
1615
1616 return rc;
1617 }
1618
1619 // ----------------------------------------------------------------------------
1620 // line/polygons
1621 // ----------------------------------------------------------------------------
1622
1623 void wxDCBase::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
1624 {
1625 unsigned int n = list->GetCount();
1626 wxPoint *points = new wxPoint[n];
1627
1628 unsigned int i = 0;
1629 wxPointList::compatibility_iterator node;
1630 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1631 {
1632 wxPoint *point = node->GetData();
1633 points[i].x = point->x;
1634 points[i].y = point->y;
1635 }
1636
1637 DoDrawLines(n, points, xoffset, yoffset);
1638
1639 delete [] points;
1640 }
1641
1642 #if WXWIN_COMPATIBILITY_2_8
1643 void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset )
1644 {
1645 unsigned int n = list->GetCount();
1646 wxPoint *points = new wxPoint[n];
1647
1648 unsigned int i = 0;
1649 wxObjectList::compatibility_iterator node;
1650 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1651 {
1652 wxPoint *point = (wxPoint*) node->GetData();
1653 points[i].x = point->x;
1654 points[i].y = point->y;
1655 }
1656
1657 DoDrawLines(n, points, xoffset, yoffset);
1658
1659 delete [] points;
1660 }
1661 #endif // WXWIN_COMPATIBILITY_2_8
1662
1663
1664 void wxDCBase::DrawPolygon(const wxPointList *list,
1665 wxCoord xoffset, wxCoord yoffset,
1666 int fillStyle)
1667 {
1668 unsigned int n = list->GetCount();
1669 wxPoint *points = new wxPoint[n];
1670
1671 unsigned int i = 0;
1672 wxPointList::compatibility_iterator node;
1673 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1674 {
1675 wxPoint *point = node->GetData();
1676 points[i].x = point->x;
1677 points[i].y = point->y;
1678 }
1679
1680 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1681
1682 delete [] points;
1683 }
1684
1685
1686 #if WXWIN_COMPATIBILITY_2_8
1687 void wxDCBase::DrawPolygon(const wxList *list,
1688 wxCoord xoffset, wxCoord yoffset,
1689 int fillStyle )
1690 {
1691 unsigned int n = list->GetCount();
1692 wxPoint *points = new wxPoint[n];
1693
1694 unsigned int i = 0;
1695 wxObjectList::compatibility_iterator node;
1696 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1697 {
1698 wxPoint *point = (wxPoint*) node->GetData();
1699 points[i].x = point->x;
1700 points[i].y = point->y;
1701 }
1702
1703 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1704
1705 delete [] points;
1706 }
1707 #endif // WXWIN_COMPATIBILITY_2_8
1708
1709 void
1710 wxDCBase::DoDrawPolyPolygon(int n,
1711 int count[],
1712 wxPoint points[],
1713 wxCoord xoffset, wxCoord yoffset,
1714 int fillStyle)
1715 {
1716 if ( n == 1 )
1717 {
1718 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
1719 return;
1720 }
1721
1722 int i, j, lastOfs;
1723 wxPoint* pts;
1724 wxPen pen;
1725
1726 for (i = j = lastOfs = 0; i < n; i++)
1727 {
1728 lastOfs = j;
1729 j += count[i];
1730 }
1731 pts = new wxPoint[j+n-1];
1732 for (i = 0; i < j; i++)
1733 pts[i] = points[i];
1734 for (i = 2; i <= n; i++)
1735 {
1736 lastOfs -= count[n-i];
1737 pts[j++] = pts[lastOfs];
1738 }
1739
1740 pen = GetPen();
1741 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
1742 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
1743 SetPen(pen);
1744 for (i = j = 0; i < n; i++)
1745 {
1746 DoDrawLines(count[i], pts+j, xoffset, yoffset);
1747 j += count[i];
1748 }
1749 delete[] pts;
1750 }
1751
1752 // ----------------------------------------------------------------------------
1753 // splines
1754 // ----------------------------------------------------------------------------
1755
1756 #if wxUSE_SPLINES
1757
1758 void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
1759 {
1760 wxPointList point_list;
1761
1762 wxPoint *point1 = new wxPoint;
1763 point1->x = x1; point1->y = y1;
1764 point_list.Append( point1 );
1765
1766 wxPoint *point2 = new wxPoint;
1767 point2->x = x2; point2->y = y2;
1768 point_list.Append( point2 );
1769
1770 wxPoint *point3 = new wxPoint;
1771 point3->x = x3; point3->y = y3;
1772 point_list.Append( point3 );
1773
1774 DrawSpline(&point_list);
1775
1776 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
1777 {
1778 wxPoint *p = node->GetData();
1779 delete p;
1780 }
1781 }
1782
1783 void wxDCBase::DrawSpline(int n, wxPoint points[])
1784 {
1785 wxPointList list;
1786 for (int i =0; i < n; i++)
1787 list.Append( &points[i] );
1788
1789 DrawSpline(&list);
1790 }
1791
1792 // ----------------------------------- spline code ----------------------------------------
1793
1794 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1795 double a3, double b3, double a4, double b4);
1796 void wx_clear_stack();
1797 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1798 double *y3, double *x4, double *y4);
1799 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1800 double x4, double y4);
1801 static bool wx_spline_add_point(double x, double y);
1802 static void wx_spline_draw_point_array(wxDCBase *dc);
1803
1804 wxPointList wx_spline_point_list;
1805
1806 #define half(z1, z2) ((z1+z2)/2.0)
1807 #define THRESHOLD 5
1808
1809 /* iterative version */
1810
1811 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1812 double b4)
1813 {
1814 register double xmid, ymid;
1815 double x1, y1, x2, y2, x3, y3, x4, y4;
1816
1817 wx_clear_stack();
1818 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1819
1820 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1821 xmid = (double)half(x2, x3);
1822 ymid = (double)half(y2, y3);
1823 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1824 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1825 wx_spline_add_point( x1, y1 );
1826 wx_spline_add_point( xmid, ymid );
1827 } else {
1828 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1829 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1830 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1831 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1832 }
1833 }
1834 }
1835
1836 /* utilities used by spline drawing routines */
1837
1838 typedef struct wx_spline_stack_struct {
1839 double x1, y1, x2, y2, x3, y3, x4, y4;
1840 } Stack;
1841
1842 #define SPLINE_STACK_DEPTH 20
1843 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1844 static Stack *wx_stack_top;
1845 static int wx_stack_count;
1846
1847 void wx_clear_stack()
1848 {
1849 wx_stack_top = wx_spline_stack;
1850 wx_stack_count = 0;
1851 }
1852
1853 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1854 {
1855 wx_stack_top->x1 = x1;
1856 wx_stack_top->y1 = y1;
1857 wx_stack_top->x2 = x2;
1858 wx_stack_top->y2 = y2;
1859 wx_stack_top->x3 = x3;
1860 wx_stack_top->y3 = y3;
1861 wx_stack_top->x4 = x4;
1862 wx_stack_top->y4 = y4;
1863 wx_stack_top++;
1864 wx_stack_count++;
1865 }
1866
1867 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1868 double *x3, double *y3, double *x4, double *y4)
1869 {
1870 if (wx_stack_count == 0)
1871 return (0);
1872 wx_stack_top--;
1873 wx_stack_count--;
1874 *x1 = wx_stack_top->x1;
1875 *y1 = wx_stack_top->y1;
1876 *x2 = wx_stack_top->x2;
1877 *y2 = wx_stack_top->y2;
1878 *x3 = wx_stack_top->x3;
1879 *y3 = wx_stack_top->y3;
1880 *x4 = wx_stack_top->x4;
1881 *y4 = wx_stack_top->y4;
1882 return (1);
1883 }
1884
1885 static bool wx_spline_add_point(double x, double y)
1886 {
1887 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
1888 wx_spline_point_list.Append( point );
1889 return true;
1890 }
1891
1892 static void wx_spline_draw_point_array(wxDCBase *dc)
1893 {
1894 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1895 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
1896 while (node)
1897 {
1898 wxPoint *point = node->GetData();
1899 delete point;
1900 wx_spline_point_list.Erase(node);
1901 node = wx_spline_point_list.GetFirst();
1902 }
1903 }
1904
1905 #if WXWIN_COMPATIBILITY_2_8
1906 void wxDCBase::DrawSpline(const wxList *points)
1907 {
1908 wxPointList list;
1909 wxObjectList::compatibility_iterator node = points->GetFirst();
1910 while (node)
1911 {
1912 list.Append( (wxPoint*) node->GetData() );
1913 node = node->GetNext();
1914 }
1915 DoDrawSpline( &list );
1916 }
1917 #endif // WXWIN_COMPATIBILITY_2_8
1918
1919 void wxDCBase::DoDrawSpline( const wxPointList *points )
1920 {
1921 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1922
1923 wxPoint *p;
1924 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1925 double x1, y1, x2, y2;
1926
1927 wxPointList::compatibility_iterator node = points->GetFirst();
1928 if (!node)
1929 // empty list
1930 return;
1931
1932 p = node->GetData();
1933
1934 x1 = p->x;
1935 y1 = p->y;
1936
1937 node = node->GetNext();
1938 p = node->GetData();
1939
1940 x2 = p->x;
1941 y2 = p->y;
1942 cx1 = (double)((x1 + x2) / 2);
1943 cy1 = (double)((y1 + y2) / 2);
1944 cx2 = (double)((cx1 + x2) / 2);
1945 cy2 = (double)((cy1 + y2) / 2);
1946
1947 wx_spline_add_point(x1, y1);
1948
1949 while ((node = node->GetNext())
1950 #if !wxUSE_STL
1951 != NULL
1952 #endif // !wxUSE_STL
1953 )
1954 {
1955 p = node->GetData();
1956 x1 = x2;
1957 y1 = y2;
1958 x2 = p->x;
1959 y2 = p->y;
1960 cx4 = (double)(x1 + x2) / 2;
1961 cy4 = (double)(y1 + y2) / 2;
1962 cx3 = (double)(x1 + cx4) / 2;
1963 cy3 = (double)(y1 + cy4) / 2;
1964
1965 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1966
1967 cx1 = cx4;
1968 cy1 = cy4;
1969 cx2 = (double)(cx1 + x2) / 2;
1970 cy2 = (double)(cy1 + y2) / 2;
1971 }
1972
1973 wx_spline_add_point( cx1, cy1 );
1974 wx_spline_add_point( x2, y2 );
1975
1976 wx_spline_draw_point_array( this );
1977 }
1978
1979 #endif // wxUSE_SPLINES
1980
1981 // ----------------------------------------------------------------------------
1982 // Partial Text Extents
1983 // ----------------------------------------------------------------------------
1984
1985
1986 // Each element of the widths array will be the width of the string up to and
1987 // including the corresponding character in text. This is the generic
1988 // implementation, the port-specific classes should do this with native APIs
1989 // if available and if faster. Note: pango_layout_index_to_pos is much slower
1990 // than calling GetTextExtent!!
1991
1992 #define FWC_SIZE 256
1993
1994 class FontWidthCache
1995 {
1996 public:
1997 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
1998 ~FontWidthCache() { delete []m_widths; }
1999
2000 void Reset()
2001 {
2002 if (!m_widths)
2003 m_widths = new int[FWC_SIZE];
2004
2005 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
2006 }
2007
2008 wxFont m_font;
2009 double m_scaleX;
2010 int *m_widths;
2011 };
2012
2013 static FontWidthCache s_fontWidthCache;
2014
2015 bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2016 {
2017 int totalWidth = 0;
2018
2019 const size_t len = text.length();
2020 widths.Empty();
2021 widths.Add(0, len);
2022
2023 // reset the cache if font or horizontal scale have changed
2024 if ( !s_fontWidthCache.m_widths ||
2025 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
2026 (s_fontWidthCache.m_font != GetFont()) )
2027 {
2028 s_fontWidthCache.Reset();
2029 s_fontWidthCache.m_font = GetFont();
2030 s_fontWidthCache.m_scaleX = m_scaleX;
2031 }
2032
2033 // Calculate the position of each character based on the widths of
2034 // the previous characters
2035 int w, h;
2036 for ( size_t i = 0; i < len; i++ )
2037 {
2038 const wxChar c = text[i];
2039 unsigned int c_int = (unsigned int)c;
2040
2041 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
2042 {
2043 w = s_fontWidthCache.m_widths[c_int];
2044 }
2045 else
2046 {
2047 GetTextExtent(c, &w, &h);
2048 if (c_int < FWC_SIZE)
2049 s_fontWidthCache.m_widths[c_int] = w;
2050 }
2051
2052 totalWidth += w;
2053 widths[i] = totalWidth;
2054 }
2055
2056 return true;
2057 }
2058
2059
2060 // ----------------------------------------------------------------------------
2061 // enhanced text drawing
2062 // ----------------------------------------------------------------------------
2063
2064 void wxDCBase::GetMultiLineTextExtent(const wxString& text,
2065 wxCoord *x,
2066 wxCoord *y,
2067 wxCoord *h,
2068 const wxFont *font) const
2069 {
2070 wxCoord widthTextMax = 0, widthLine,
2071 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
2072
2073 wxString curLine;
2074 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2075 {
2076 if ( pc == text.end() || *pc == _T('\n') )
2077 {
2078 if ( curLine.empty() )
2079 {
2080 // we can't use GetTextExtent - it will return 0 for both width
2081 // and height and an empty line should count in height
2082 // calculation
2083
2084 // assume that this line has the same height as the previous
2085 // one
2086 if ( !heightLineDefault )
2087 heightLineDefault = heightLine;
2088
2089 if ( !heightLineDefault )
2090 {
2091 // but we don't know it yet - choose something reasonable
2092 GetTextExtent(_T("W"), NULL, &heightLineDefault,
2093 NULL, NULL, font);
2094 }
2095
2096 heightTextTotal += heightLineDefault;
2097 }
2098 else
2099 {
2100 GetTextExtent(curLine, &widthLine, &heightLine,
2101 NULL, NULL, font);
2102 if ( widthLine > widthTextMax )
2103 widthTextMax = widthLine;
2104 heightTextTotal += heightLine;
2105 }
2106
2107 if ( pc == text.end() )
2108 {
2109 break;
2110 }
2111 else // '\n'
2112 {
2113 curLine.clear();
2114 }
2115 }
2116 else
2117 {
2118 curLine += *pc;
2119 }
2120 }
2121
2122 if ( x )
2123 *x = widthTextMax;
2124 if ( y )
2125 *y = heightTextTotal;
2126 if ( h )
2127 *h = heightLine;
2128 }
2129
2130 void wxDCBase::DrawLabel(const wxString& text,
2131 const wxBitmap& bitmap,
2132 const wxRect& rect,
2133 int alignment,
2134 int indexAccel,
2135 wxRect *rectBounding)
2136 {
2137 // find the text position
2138 wxCoord widthText, heightText, heightLine;
2139 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
2140
2141 wxCoord width, height;
2142 if ( bitmap.Ok() )
2143 {
2144 width = widthText + bitmap.GetWidth();
2145 height = bitmap.GetHeight();
2146 }
2147 else // no bitmap
2148 {
2149 width = widthText;
2150 height = heightText;
2151 }
2152
2153 wxCoord x, y;
2154 if ( alignment & wxALIGN_RIGHT )
2155 {
2156 x = rect.GetRight() - width;
2157 }
2158 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2159 {
2160 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
2161 }
2162 else // alignment & wxALIGN_LEFT
2163 {
2164 x = rect.GetLeft();
2165 }
2166
2167 if ( alignment & wxALIGN_BOTTOM )
2168 {
2169 y = rect.GetBottom() - height;
2170 }
2171 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
2172 {
2173 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
2174 }
2175 else // alignment & wxALIGN_TOP
2176 {
2177 y = rect.GetTop();
2178 }
2179
2180 // draw the bitmap first
2181 wxCoord x0 = x,
2182 y0 = y,
2183 width0 = width;
2184 if ( bitmap.Ok() )
2185 {
2186 DrawBitmap(bitmap, x, y, true /* use mask */);
2187
2188 wxCoord offset = bitmap.GetWidth() + 4;
2189 x += offset;
2190 width -= offset;
2191
2192 y += (height - heightText) / 2;
2193 }
2194
2195 // we will draw the underscore under the accel char later
2196 wxCoord startUnderscore = 0,
2197 endUnderscore = 0,
2198 yUnderscore = 0;
2199
2200 // split the string into lines and draw each of them separately
2201 wxString curLine;
2202 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2203 {
2204 if ( pc == text.end() || *pc == _T('\n') )
2205 {
2206 int xRealStart = x; // init it here to avoid compielr warnings
2207
2208 if ( !curLine.empty() )
2209 {
2210 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2211 // wxALIGN_LEFT is 0
2212 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
2213 {
2214 wxCoord widthLine;
2215 GetTextExtent(curLine, &widthLine, NULL);
2216
2217 if ( alignment & wxALIGN_RIGHT )
2218 {
2219 xRealStart += width - widthLine;
2220 }
2221 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2222 {
2223 xRealStart += (width - widthLine) / 2;
2224 }
2225 }
2226 //else: left aligned, nothing to do
2227
2228 DrawText(curLine, xRealStart, y);
2229 }
2230
2231 y += heightLine;
2232
2233 // do we have underscore in this line? we can check yUnderscore
2234 // because it is set below to just y + heightLine if we do
2235 if ( y == yUnderscore )
2236 {
2237 // adjust the horz positions to account for the shift
2238 startUnderscore += xRealStart;
2239 endUnderscore += xRealStart;
2240 }
2241
2242 if ( pc == text.end() )
2243 break;
2244
2245 curLine.clear();
2246 }
2247 else // not end of line
2248 {
2249 if ( pc - text.begin() == indexAccel )
2250 {
2251 // remeber to draw underscore here
2252 GetTextExtent(curLine, &startUnderscore, NULL);
2253 curLine += *pc;
2254 GetTextExtent(curLine, &endUnderscore, NULL);
2255
2256 yUnderscore = y + heightLine;
2257 }
2258 else
2259 {
2260 curLine += *pc;
2261 }
2262 }
2263 }
2264
2265 // draw the underscore if found
2266 if ( startUnderscore != endUnderscore )
2267 {
2268 // it should be of the same colour as text
2269 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
2270
2271 yUnderscore--;
2272
2273 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
2274 }
2275
2276 // return bounding rect if requested
2277 if ( rectBounding )
2278 {
2279 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
2280 }
2281
2282 CalcBoundingBox(x0, y0);
2283 CalcBoundingBox(x0 + width0, y0 + height);
2284 }
2285
2286
2287 void wxDCBase::DoGradientFillLinear(const wxRect& rect,
2288 const wxColour& initialColour,
2289 const wxColour& destColour,
2290 wxDirection nDirection)
2291 {
2292 // save old pen
2293 wxPen oldPen = m_pen;
2294 wxBrush oldBrush = m_brush;
2295
2296 wxUint8 nR1 = initialColour.Red();
2297 wxUint8 nG1 = initialColour.Green();
2298 wxUint8 nB1 = initialColour.Blue();
2299 wxUint8 nR2 = destColour.Red();
2300 wxUint8 nG2 = destColour.Green();
2301 wxUint8 nB2 = destColour.Blue();
2302 wxUint8 nR, nG, nB;
2303
2304 if ( nDirection == wxEAST || nDirection == wxWEST )
2305 {
2306 wxInt32 x = rect.GetWidth();
2307 wxInt32 w = x; // width of area to shade
2308 wxInt32 xDelta = w/256; // height of one shade bend
2309 if (xDelta < 1)
2310 xDelta = 1;
2311
2312 while (x >= xDelta)
2313 {
2314 x -= xDelta;
2315 if (nR1 > nR2)
2316 nR = nR1 - (nR1-nR2)*(w-x)/w;
2317 else
2318 nR = nR1 + (nR2-nR1)*(w-x)/w;
2319
2320 if (nG1 > nG2)
2321 nG = nG1 - (nG1-nG2)*(w-x)/w;
2322 else
2323 nG = nG1 + (nG2-nG1)*(w-x)/w;
2324
2325 if (nB1 > nB2)
2326 nB = nB1 - (nB1-nB2)*(w-x)/w;
2327 else
2328 nB = nB1 + (nB2-nB1)*(w-x)/w;
2329
2330 wxColour colour(nR,nG,nB);
2331 SetPen(wxPen(colour, 1, wxSOLID));
2332 SetBrush(wxBrush(colour));
2333 if(nDirection == wxEAST)
2334 DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2335 xDelta, rect.GetHeight());
2336 else //nDirection == wxWEST
2337 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
2338 xDelta, rect.GetHeight());
2339 }
2340 }
2341 else // nDirection == wxNORTH || nDirection == wxSOUTH
2342 {
2343 wxInt32 y = rect.GetHeight();
2344 wxInt32 w = y; // height of area to shade
2345 wxInt32 yDelta = w/255; // height of one shade bend
2346 if (yDelta < 1)
2347 yDelta = 1;
2348
2349 while (y > 0)
2350 {
2351 y -= yDelta;
2352 if (nR1 > nR2)
2353 nR = nR1 - (nR1-nR2)*(w-y)/w;
2354 else
2355 nR = nR1 + (nR2-nR1)*(w-y)/w;
2356
2357 if (nG1 > nG2)
2358 nG = nG1 - (nG1-nG2)*(w-y)/w;
2359 else
2360 nG = nG1 + (nG2-nG1)*(w-y)/w;
2361
2362 if (nB1 > nB2)
2363 nB = nB1 - (nB1-nB2)*(w-y)/w;
2364 else
2365 nB = nB1 + (nB2-nB1)*(w-y)/w;
2366
2367 wxColour colour(nR,nG,nB);
2368 SetPen(wxPen(colour, 1, wxSOLID));
2369 SetBrush(wxBrush(colour));
2370 if(nDirection == wxNORTH)
2371 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
2372 rect.GetWidth(), yDelta);
2373 else //nDirection == wxSOUTH
2374 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2375 rect.GetWidth(), yDelta);
2376 }
2377 }
2378
2379 SetPen(oldPen);
2380 SetBrush(oldBrush);
2381 }
2382
2383 void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
2384 const wxColour& initialColour,
2385 const wxColour& destColour,
2386 const wxPoint& circleCenter)
2387 {
2388 //save the old pen color
2389 wxColour oldPenColour = m_pen.GetColour();
2390
2391 wxUint8 nR1 = destColour.Red();
2392 wxUint8 nG1 = destColour.Green();
2393 wxUint8 nB1 = destColour.Blue();
2394 wxUint8 nR2 = initialColour.Red();
2395 wxUint8 nG2 = initialColour.Green();
2396 wxUint8 nB2 = initialColour.Blue();
2397 wxUint8 nR, nG, nB;
2398
2399
2400 //Radius
2401 wxInt32 cx = rect.GetWidth() / 2;
2402 wxInt32 cy = rect.GetHeight() / 2;
2403 wxInt32 nRadius;
2404 if (cx < cy)
2405 nRadius = cx;
2406 else
2407 nRadius = cy;
2408
2409 //Offset of circle
2410 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
2411 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
2412
2413 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
2414 {
2415 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
2416 {
2417 //get color difference
2418 wxInt32 nGradient = ((nRadius -
2419 (wxInt32)sqrt(
2420 pow((double)(x - cx - nCircleOffX), 2) +
2421 pow((double)(y - cy - nCircleOffY), 2)
2422 )) * 100) / nRadius;
2423
2424 //normalize Gradient
2425 if (nGradient < 0 )
2426 nGradient = 0;
2427
2428 //get dest colors
2429 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2430 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2431 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
2432
2433 //set the pixel
2434 m_pen.SetColour(wxColour(nR,nG,nB));
2435 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
2436 }
2437 }
2438 //return old pen color
2439 m_pen.SetColour(oldPenColour);
2440 }
2441
2442 /*
2443 Notes for wxWidgets DrawEllipticArcRot(...)
2444
2445 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2446 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2447 which are also new.
2448
2449 All methods are generic, so they can be implemented in wxDCBase.
2450 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2451 methods like (WinCE) wxDC::DoDrawArc(...).
2452
2453 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2454 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
2455 parts) or every column (in steep parts) only one pixel is calculated.
2456 Trigonometric calculation (sin, cos, tan, atan) is only done if the
2457 starting angle is not equal to the ending angle. The calculation of the
2458 pixels is done using simple arithmetic only and should perform not too
2459 bad even on devices without floating point processor. I didn't test this yet.
2460
2461 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2462 For instance: an ellipse rotated 180 degrees is drawn
2463 slightly different from the original.
2464
2465 The points are then moved to an array and used to draw a polyline and/or polygon
2466 (with center added, the pie).
2467 The result looks quite similar to the native ellipse, only e few pixels differ.
2468
2469 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2470 slower as DrawEllipse(...), which calls the native API.
2471 An rotated ellipse outside the clipping region takes nearly the same time,
2472 while an native ellipse outside takes nearly no time to draw.
2473
2474 If you draw an arc with this new method, you will see the starting and ending angles
2475 are calculated properly.
2476 If you use DrawEllipticArc(...), you will see they are only correct for circles
2477 and not properly calculated for ellipses.
2478
2479 Peter Lenhard
2480 p.lenhard@t-online.de
2481 */
2482
2483 #ifdef __WXWINCE__
2484 void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2485 wxCoord w, wxCoord h,
2486 double sa, double ea, double angle )
2487 {
2488 wxPointList list;
2489
2490 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
2491 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
2492
2493 // Add center (for polygon/pie)
2494 list.Append( new wxPoint( x+w/2, y+h/2 ) );
2495
2496 // copy list into array and delete list elements
2497 int n = list.GetCount();
2498 wxPoint *points = new wxPoint[n];
2499 int i = 0;
2500 wxPointList::compatibility_iterator node;
2501 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
2502 {
2503 wxPoint *point = node->GetData();
2504 points[i].x = point->x;
2505 points[i].y = point->y;
2506 delete point;
2507 }
2508
2509 // first draw the pie without pen, if necessary
2510 if( GetBrush() != *wxTRANSPARENT_BRUSH )
2511 {
2512 wxPen tempPen( GetPen() );
2513 SetPen( *wxTRANSPARENT_PEN );
2514 DoDrawPolygon( n, points, 0, 0 );
2515 SetPen( tempPen );
2516 }
2517
2518 // then draw the arc without brush, if necessary
2519 if( GetPen() != *wxTRANSPARENT_PEN )
2520 {
2521 // without center
2522 DoDrawLines( n-1, points, 0, 0 );
2523 }
2524
2525 delete [] points;
2526
2527 } // DrawEllipticArcRot
2528
2529 void wxDCBase::Rotate( wxPointList* points, double angle, wxPoint center )
2530 {
2531 if( angle != 0.0 )
2532 {
2533 double pi(M_PI);
2534 double dSinA = -sin(angle*2.0*pi/360.0);
2535 double dCosA = cos(angle*2.0*pi/360.0);
2536 wxPointList::compatibility_iterator node;
2537 for ( node = points->GetFirst(); node; node = node->GetNext() )
2538 {
2539 wxPoint* point = node->GetData();
2540
2541 // transform coordinates, if necessary
2542 if( center.x ) point->x -= center.x;
2543 if( center.y ) point->y -= center.y;
2544
2545 // calculate rotation, rounding simply by implicit cast to integer
2546 int xTemp = point->x * dCosA - point->y * dSinA;
2547 point->y = point->x * dSinA + point->y * dCosA;
2548 point->x = xTemp;
2549
2550 // back transform coordinates, if necessary
2551 if( center.x ) point->x += center.x;
2552 if( center.y ) point->y += center.y;
2553 }
2554 }
2555 }
2556
2557 void wxDCBase::CalculateEllipticPoints( wxPointList* points,
2558 wxCoord xStart, wxCoord yStart,
2559 wxCoord w, wxCoord h,
2560 double sa, double ea )
2561 {
2562 double pi = M_PI;
2563 double sar = 0;
2564 double ear = 0;
2565 int xsa = 0;
2566 int ysa = 0;
2567 int xea = 0;
2568 int yea = 0;
2569 int sq = 0;
2570 int eq = 0;
2571 bool bUseAngles = false;
2572 if( w<0 ) w = -w;
2573 if( h<0 ) h = -h;
2574 // half-axes
2575 wxCoord a = w/2;
2576 wxCoord b = h/2;
2577 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2578 int decrX = 0;
2579 if( 2*a == w ) decrX = 1;
2580 int decrY = 0;
2581 if( 2*b == h ) decrY = 1;
2582 // center
2583 wxCoord xCenter = xStart + a;
2584 wxCoord yCenter = yStart + b;
2585 // calculate data for start and end, if necessary
2586 if( sa != ea )
2587 {
2588 bUseAngles = true;
2589 // normalisation of angles
2590 while( sa<0 ) sa += 360;
2591 while( ea<0 ) ea += 360;
2592 while( sa>=360 ) sa -= 360;
2593 while( ea>=360 ) ea -= 360;
2594 // calculate quadrant numbers
2595 if( sa > 270 ) sq = 3;
2596 else if( sa > 180 ) sq = 2;
2597 else if( sa > 90 ) sq = 1;
2598 if( ea > 270 ) eq = 3;
2599 else if( ea > 180 ) eq = 2;
2600 else if( ea > 90 ) eq = 1;
2601 sar = sa * pi / 180.0;
2602 ear = ea * pi / 180.0;
2603 // correct angle circle -> ellipse
2604 sar = atan( -a/(double)b * tan( sar ) );
2605 if ( sq == 1 || sq == 2 ) sar += pi;
2606 ear = atan( -a/(double)b * tan( ear ) );
2607 if ( eq == 1 || eq == 2 ) ear += pi;
2608 // coordinates of points
2609 xsa = xCenter + a * cos( sar );
2610 if( sq == 0 || sq == 3 ) xsa -= decrX;
2611 ysa = yCenter + b * sin( sar );
2612 if( sq == 2 || sq == 3 ) ysa -= decrY;
2613 xea = xCenter + a * cos( ear );
2614 if( eq == 0 || eq == 3 ) xea -= decrX;
2615 yea = yCenter + b * sin( ear );
2616 if( eq == 2 || eq == 3 ) yea -= decrY;
2617 } // if iUseAngles
2618 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2619 double c1 = b * b;
2620 double c2 = 2.0 / w;
2621 c2 *= c2;
2622 c2 *= c1;
2623 wxCoord x = 0;
2624 wxCoord y = b;
2625 long x2 = 1;
2626 long y2 = y*y;
2627 long y2_old = 0;
2628 long y_old = 0;
2629 // Lists for quadrant 1 to 4
2630 wxPointList pointsarray[4];
2631 // Calculate points for first quadrant and set in all quadrants
2632 for( x = 0; x <= a; ++x )
2633 {
2634 x2 = x2+x+x-1;
2635 y2_old = y2;
2636 y_old = y;
2637 bool bNewPoint = false;
2638 while( y2 > c1 - c2 * x2 && y > 0 )
2639 {
2640 bNewPoint = true;
2641 y2 = y2-y-y+1;
2642 --y;
2643 }
2644 // old y now to big: set point with old y, old x
2645 if( bNewPoint && x>1)
2646 {
2647 int x1 = x - 1;
2648 // remove points on the same line
2649 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
2650 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
2651 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
2652 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
2653 } // set point
2654 } // calculate point
2655
2656 // Starting and/or ending points for the quadrants, first quadrant gets both.
2657 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
2658 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
2659 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
2660 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
2661 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
2662
2663 // copy quadrants in original list
2664 if( bUseAngles )
2665 {
2666 // Copy the right part of the points in the lists
2667 // and delete the wxPoints, because they do not leave this method.
2668 points->Append( new wxPoint( xsa, ysa ) );
2669 int q = sq;
2670 bool bStarted = false;
2671 bool bReady = false;
2672 bool bForceTurn = ( sq == eq && sa > ea );
2673 while( !bReady )
2674 {
2675 wxPointList::compatibility_iterator node;
2676 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
2677 {
2678 // once: go to starting point in start quadrant
2679 if( !bStarted &&
2680 (
2681 node->GetData()->x < xsa+1 && q <= 1
2682 ||
2683 node->GetData()->x > xsa-1 && q >= 2
2684 )
2685 )
2686 {
2687 bStarted = true;
2688 }
2689
2690 // copy point, if not at ending point
2691 if( bStarted )
2692 {
2693 if( q != eq || bForceTurn
2694 ||
2695 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2696 ||
2697 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
2698 )
2699 {
2700 // copy point
2701 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
2702 points->Append( pPoint );
2703 }
2704 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
2705 {
2706 bReady = true;
2707 }
2708 }
2709 } // for node
2710 ++q;
2711 if( q > 3 ) q = 0;
2712 bForceTurn = false;
2713 bStarted = true;
2714 } // while not bReady
2715 points->Append( new wxPoint( xea, yea ) );
2716
2717 // delete points
2718 for( q = 0; q < 4; ++q )
2719 {
2720 wxPointList::compatibility_iterator node;
2721 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
2722 {
2723 wxPoint *p = node->GetData();
2724 delete p;
2725 }
2726 }
2727 }
2728 else
2729 {
2730 wxPointList::compatibility_iterator node;
2731 // copy whole ellipse, wxPoints will be deleted outside
2732 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
2733 {
2734 wxPoint *p = node->GetData();
2735 points->Append( p );
2736 }
2737 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
2738 {
2739 wxPoint *p = node->GetData();
2740 points->Append( p );
2741 }
2742 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
2743 {
2744 wxPoint *p = node->GetData();
2745 points->Append( p );
2746 }
2747 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
2748 {
2749 wxPoint *p = node->GetData();
2750 points->Append( p );
2751 }
2752 } // not iUseAngles
2753 } // CalculateEllipticPoints
2754
2755 #endif // __WXWINCE__
2756
2757 #endif // wxUSE_NEW_DC