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