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