1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.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"
36 #include "wx/module.h"
40 #include "wx/msw/dcclient.h"
41 #include "wx/msw/dcmemory.h"
42 #include "wx/msw/dcscreen.h"
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"
56 #include "wx/mac/dcclient.h"
57 #include "wx/mac/dcmemory.h"
58 #include "wx/mac/dcscreen.h"
62 #include "wx/os2/dcclient.h"
63 #include "wx/os2/dcmemory.h"
64 #include "wx/os2/dcscreen.h"
68 #include "wx/cocoa/dcclient.h"
69 #include "wx/cocoa/dcmemory.h"
70 #include "wx/cocoa/dcscreen.h"
74 #include "wx/motif/dcclient.h"
75 #include "wx/motif/dcmemory.h"
76 #include "wx/motif/dcscreen.h"
80 #include "wx/x11/dcclient.h"
81 #include "wx/x11/dcmemory.h"
82 #include "wx/x11/dcscreen.h"
86 #include "wx/dfb/dcclient.h"
87 #include "wx/dfb/dcmemory.h"
88 #include "wx/dfb/dcscreen.h"
92 #include "wx/palmos/dcclient.h"
93 #include "wx/palmos/dcmemory.h"
94 #include "wx/palmos/dcscreen.h"
97 //----------------------------------------------------------------------------
99 //----------------------------------------------------------------------------
101 wxDCFactory
*wxDCFactory::m_factory
= NULL
;
103 void wxDCFactory::Set(wxDCFactory
*factory
)
110 wxDCFactory
*wxDCFactory::Get()
113 m_factory
= new wxNativeDCFactory
;
118 class wxDCFactoryCleanupModule
: public wxModule
121 virtual bool OnInit() { return true; }
122 virtual void OnExit() { wxDCFactory::Set(NULL
); }
125 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule
)
128 IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule
, wxModule
)
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
134 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
)
136 return new wxWindowDCImpl( owner
);
139 wxDCImpl
* wxNativeDCFactory::CreateWindowDC( wxWindowDC
*owner
, wxWindow
*window
)
141 return new wxWindowDCImpl( owner
, window
);
144 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
)
146 return new wxClientDCImpl( owner
);
149 wxDCImpl
* wxNativeDCFactory::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
151 return new wxClientDCImpl( owner
, window
);
154 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
)
156 return new wxPaintDCImpl( owner
);
159 wxDCImpl
* wxNativeDCFactory::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
161 return new wxPaintDCImpl( owner
, window
);
164 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
)
166 return new wxMemoryDCImpl( owner
);
169 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxBitmap
&bitmap
)
171 return new wxMemoryDCImpl( owner
, bitmap
);
174 wxDCImpl
* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
176 return new wxMemoryDCImpl( owner
, dc
);
179 wxDCImpl
* wxNativeDCFactory::CreateScreenDC( wxScreenDC
*owner
)
181 return new wxScreenDCImpl( owner
);
184 #if wxUSE_PRINTING_ARCHITECTURE
185 wxDCImpl
*wxNativeDCFactory::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
187 wxPrintFactory
*factory
= wxPrintFactory::GetFactory();
188 return factory
->CreatePrinterDCImpl( owner
, data
);
192 //-----------------------------------------------------------------------------
194 //-----------------------------------------------------------------------------
196 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
198 wxWindowDC::wxWindowDC(wxWindow
*win
)
199 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win
))
203 //-----------------------------------------------------------------------------
205 //-----------------------------------------------------------------------------
207 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
209 wxClientDC::wxClientDC(wxWindow
*win
)
210 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win
))
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
220 wxMemoryDC::wxMemoryDC()
221 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
225 wxMemoryDC::wxMemoryDC(wxBitmap
& bitmap
)
226 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap
))
230 wxMemoryDC::wxMemoryDC(wxDC
*dc
)
231 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc
))
235 void wxMemoryDC::SelectObject(wxBitmap
& bmp
)
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
243 GetImpl()->DoSelect(bmp
);
246 void wxMemoryDC::SelectObjectAsSource(const wxBitmap
& bmp
)
248 GetImpl()->DoSelect(bmp
);
251 const wxBitmap
& wxMemoryDC::GetSelectedBitmap() const
253 return GetImpl()->GetSelectedBitmap();
256 wxBitmap
& wxMemoryDC::GetSelectedBitmap()
258 return GetImpl()->GetSelectedBitmap();
262 //-----------------------------------------------------------------------------
264 //-----------------------------------------------------------------------------
266 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
268 wxPaintDC::wxPaintDC(wxWindow
*win
)
269 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win
))
273 //-----------------------------------------------------------------------------
275 //-----------------------------------------------------------------------------
277 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
279 wxScreenDC::wxScreenDC()
280 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
284 //-----------------------------------------------------------------------------
286 //-----------------------------------------------------------------------------
288 #if wxUSE_PRINTING_ARCHITECTURE
290 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
292 wxPrinterDC::wxPrinterDC()
293 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
297 wxPrinterDC::wxPrinterDC(const wxPrintData
& data
)
298 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data
))
302 wxRect
wxPrinterDC::GetPaperRect()
304 return GetImpl()->GetPaperRect();
307 int wxPrinterDC::GetResolution()
309 return GetImpl()->GetResolution();
312 #endif // wxUSE_PRINTING_ARCHITECTURE
314 //-----------------------------------------------------------------------------
316 //-----------------------------------------------------------------------------
318 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
320 wxDCImpl::wxDCImpl( wxDC
*owner
)
322 , m_colour(wxColourDisplay())
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(wxBRUSHSTYLE_TRANSPARENT
)
338 , m_mappingMode(wxMM_TEXT
)
341 , m_backgroundBrush()
342 , m_textForegroundColour(*wxBLACK
)
343 , m_textBackgroundColour(*wxWHITE
)
347 , m_hasCustomPalette(false)
348 #endif // wxUSE_PALETTE
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();
361 wxDCImpl::~wxDCImpl()
365 // ----------------------------------------------------------------------------
366 // coordinate conversions and transforms
367 // ----------------------------------------------------------------------------
369 wxCoord
wxDCImpl::DeviceToLogicalX(wxCoord x
) const
371 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
374 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
376 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
379 wxCoord
wxDCImpl::DeviceToLogicalXRel(wxCoord x
) const
381 return wxRound((double)(x
) / m_scaleX
);
384 wxCoord
wxDCImpl::DeviceToLogicalYRel(wxCoord y
) const
386 return wxRound((double)(y
) / m_scaleY
);
389 wxCoord
wxDCImpl::LogicalToDeviceX(wxCoord x
) const
391 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
394 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
396 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
399 wxCoord
wxDCImpl::LogicalToDeviceXRel(wxCoord x
) const
401 return wxRound((double)(x
) * m_scaleX
);
404 wxCoord
wxDCImpl::LogicalToDeviceYRel(wxCoord y
) const
406 return wxRound((double)(y
) * m_scaleY
);
409 void wxDCImpl::ComputeScaleAndOrigin()
411 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
412 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
415 void wxDCImpl::SetMapMode( int mode
)
420 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
423 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
426 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
429 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
433 SetLogicalScale( 1.0, 1.0 );
436 m_mappingMode
= mode
;
439 void wxDCImpl::SetUserScale( double x
, double y
)
441 // allow negative ? -> no
444 ComputeScaleAndOrigin();
447 void wxDCImpl::SetLogicalScale( double x
, double y
)
452 ComputeScaleAndOrigin();
455 void wxDCImpl::SetLogicalOrigin( wxCoord x
, wxCoord y
)
457 m_logicalOriginX
= x
* m_signX
;
458 m_logicalOriginY
= y
* m_signY
;
459 ComputeScaleAndOrigin();
462 void wxDCImpl::SetDeviceOrigin( wxCoord x
, wxCoord y
)
466 ComputeScaleAndOrigin();
469 void wxDCImpl::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
471 m_deviceLocalOriginX
= x
;
472 m_deviceLocalOriginY
= y
;
473 ComputeScaleAndOrigin();
476 void wxDCImpl::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
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();
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!!
497 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
498 ~FontWidthCache() { delete []m_widths
; }
503 m_widths
= new int[FWC_SIZE
];
505 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
513 static FontWidthCache s_fontWidthCache
;
515 bool wxDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
519 const size_t len
= text
.length();
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()) )
528 s_fontWidthCache
.Reset();
529 s_fontWidthCache
.m_font
= GetFont();
530 s_fontWidthCache
.m_scaleX
= m_scaleX
;
533 // Calculate the position of each character based on the widths of
534 // the previous characters
536 for ( size_t i
= 0; i
< len
; i
++ )
538 const wxChar c
= text
[i
];
539 unsigned int c_int
= (unsigned int)c
;
541 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
543 w
= s_fontWidthCache
.m_widths
[c_int
];
547 DoGetTextExtent(c
, &w
, &h
);
548 if (c_int
< FWC_SIZE
)
549 s_fontWidthCache
.m_widths
[c_int
] = w
;
553 widths
[i
] = totalWidth
;
559 void wxDCImpl::GetMultiLineTextExtent(const wxString
& text
,
563 const wxFont
*font
) const
565 wxCoord widthTextMax
= 0, widthLine
,
566 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
569 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
571 if ( pc
== text
.end() || *pc
== _T('\n') )
573 if ( curLine
.empty() )
575 // we can't use GetTextExtent - it will return 0 for both width
576 // and height and an empty line should count in height
579 // assume that this line has the same height as the previous
581 if ( !heightLineDefault
)
582 heightLineDefault
= heightLine
;
584 if ( !heightLineDefault
)
586 // but we don't know it yet - choose something reasonable
587 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
591 heightTextTotal
+= heightLineDefault
;
595 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
597 if ( widthLine
> widthTextMax
)
598 widthTextMax
= widthLine
;
599 heightTextTotal
+= heightLine
;
602 if ( pc
== text
.end() )
620 *y
= heightTextTotal
;
625 void wxDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
626 wxCoord width
, wxCoord height
)
628 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
630 wxCoord x2
= x1
+ width
,
633 // the pen width is calibrated to give 3 for width == height == 10
634 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
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
);
642 CalcBoundingBox(x1
, y1
);
643 CalcBoundingBox(x2
, y2
);
647 wxDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
648 wxCoord dstWidth
, wxCoord dstHeight
,
650 wxCoord xsrc
, wxCoord ysrc
,
651 wxCoord srcWidth
, wxCoord srcHeight
,
657 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
658 _T("invalid blit size") );
660 // emulate the stretching by modifying the DC scale
661 double xscale
= (double)srcWidth
/dstWidth
,
662 yscale
= (double)srcHeight
/dstHeight
;
664 double xscaleOld
, yscaleOld
;
665 GetUserScale(&xscaleOld
, &yscaleOld
);
666 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
668 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
669 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
671 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
673 SetUserScale(xscaleOld
, yscaleOld
);
678 void wxDCImpl::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
680 int n
= list
->GetCount();
681 wxPoint
*points
= new wxPoint
[n
];
684 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
686 wxPoint
*point
= node
->GetData();
687 points
[i
].x
= point
->x
;
688 points
[i
].y
= point
->y
;
691 DoDrawLines(n
, points
, xoffset
, yoffset
);
696 void wxDCImpl::DrawPolygon(const wxPointList
*list
,
697 wxCoord xoffset
, wxCoord yoffset
,
700 int n
= list
->GetCount();
701 wxPoint
*points
= new wxPoint
[n
];
704 for ( wxPointList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
706 wxPoint
*point
= node
->GetData();
707 points
[i
].x
= point
->x
;
708 points
[i
].y
= point
->y
;
711 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
717 wxDCImpl::DoDrawPolyPolygon(int n
,
720 wxCoord xoffset
, wxCoord yoffset
,
725 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
733 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
738 pts
= new wxPoint
[j
+n
-1];
739 for (i
= 0; i
< j
; i
++)
741 for (i
= 2; i
<= n
; i
++)
743 lastOfs
-= count
[n
-i
];
744 pts
[j
++] = pts
[lastOfs
];
748 SetPen(wxPen(*wxBLACK
, 0, wxPENSTYLE_TRANSPARENT
));
749 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
751 for (i
= j
= 0; i
< n
; i
++)
753 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
761 void wxDCImpl::DrawSpline(wxCoord x1
, wxCoord y1
,
762 wxCoord x2
, wxCoord y2
,
763 wxCoord x3
, wxCoord y3
)
765 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
766 DrawSpline(WXSIZEOF(points
), points
);
769 void wxDCImpl::DrawSpline(int n
, wxPoint points
[])
772 for ( int i
= 0; i
< n
; i
++ )
773 list
.Append(&points
[i
]);
778 // ----------------------------------- spline code ----------------------------------------
780 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
781 double a3
, double b3
, double a4
, double b4
);
782 void wx_clear_stack();
783 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
784 double *y3
, double *x4
, double *y4
);
785 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
786 double x4
, double y4
);
787 static bool wx_spline_add_point(double x
, double y
);
788 static void wx_spline_draw_point_array(wxDC
*dc
);
790 wxPointList wx_spline_point_list
;
792 #define half(z1, z2) ((z1+z2)/2.0)
795 /* iterative version */
797 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
800 register double xmid
, ymid
;
801 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
804 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
806 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
807 xmid
= (double)half(x2
, x3
);
808 ymid
= (double)half(y2
, y3
);
809 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
810 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
811 wx_spline_add_point( x1
, y1
);
812 wx_spline_add_point( xmid
, ymid
);
814 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
815 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
816 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
817 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
822 /* utilities used by spline drawing routines */
824 typedef struct wx_spline_stack_struct
{
825 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
828 #define SPLINE_STACK_DEPTH 20
829 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
830 static Stack
*wx_stack_top
;
831 static int wx_stack_count
;
833 void wx_clear_stack()
835 wx_stack_top
= wx_spline_stack
;
839 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
841 wx_stack_top
->x1
= x1
;
842 wx_stack_top
->y1
= y1
;
843 wx_stack_top
->x2
= x2
;
844 wx_stack_top
->y2
= y2
;
845 wx_stack_top
->x3
= x3
;
846 wx_stack_top
->y3
= y3
;
847 wx_stack_top
->x4
= x4
;
848 wx_stack_top
->y4
= y4
;
853 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
854 double *x3
, double *y3
, double *x4
, double *y4
)
856 if (wx_stack_count
== 0)
860 *x1
= wx_stack_top
->x1
;
861 *y1
= wx_stack_top
->y1
;
862 *x2
= wx_stack_top
->x2
;
863 *y2
= wx_stack_top
->y2
;
864 *x3
= wx_stack_top
->x3
;
865 *y3
= wx_stack_top
->y3
;
866 *x4
= wx_stack_top
->x4
;
867 *y4
= wx_stack_top
->y4
;
871 static bool wx_spline_add_point(double x
, double y
)
873 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
874 wx_spline_point_list
.Append(point
);
878 static void wx_spline_draw_point_array(wxDC
*dc
)
880 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
881 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
884 wxPoint
*point
= node
->GetData();
886 wx_spline_point_list
.Erase(node
);
887 node
= wx_spline_point_list
.GetFirst();
891 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
893 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
896 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
897 double x1
, y1
, x2
, y2
;
899 wxPointList::compatibility_iterator node
= points
->GetFirst();
904 p
= (wxPoint
*)node
->GetData();
909 node
= node
->GetNext();
914 cx1
= (double)((x1
+ x2
) / 2);
915 cy1
= (double)((y1
+ y2
) / 2);
916 cx2
= (double)((cx1
+ x2
) / 2);
917 cy2
= (double)((cy1
+ y2
) / 2);
919 wx_spline_add_point(x1
, y1
);
921 while ((node
= node
->GetNext())
932 cx4
= (double)(x1
+ x2
) / 2;
933 cy4
= (double)(y1
+ y2
) / 2;
934 cx3
= (double)(x1
+ cx4
) / 2;
935 cy3
= (double)(y1
+ cy4
) / 2;
937 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
941 cx2
= (double)(cx1
+ x2
) / 2;
942 cy2
= (double)(cy1
+ y2
) / 2;
945 wx_spline_add_point( cx1
, cy1
);
946 wx_spline_add_point( x2
, y2
);
948 wx_spline_draw_point_array( m_owner
);
951 #endif // wxUSE_SPLINES
955 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
956 const wxColour
& initialColour
,
957 const wxColour
& destColour
,
958 wxDirection nDirection
)
961 wxPen oldPen
= m_pen
;
962 wxBrush oldBrush
= m_brush
;
964 wxUint8 nR1
= initialColour
.Red();
965 wxUint8 nG1
= initialColour
.Green();
966 wxUint8 nB1
= initialColour
.Blue();
967 wxUint8 nR2
= destColour
.Red();
968 wxUint8 nG2
= destColour
.Green();
969 wxUint8 nB2
= destColour
.Blue();
972 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
974 wxInt32 x
= rect
.GetWidth();
975 wxInt32 w
= x
; // width of area to shade
976 wxInt32 xDelta
= w
/256; // height of one shade bend
984 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
986 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
989 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
991 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
994 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
996 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
998 wxColour
colour(nR
,nG
,nB
);
999 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1000 SetBrush(wxBrush(colour
));
1001 if(nDirection
== wxEAST
)
1002 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
1003 xDelta
, rect
.GetHeight());
1004 else //nDirection == wxWEST
1005 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
1006 xDelta
, rect
.GetHeight());
1009 else // nDirection == wxNORTH || nDirection == wxSOUTH
1011 wxInt32 y
= rect
.GetHeight();
1012 wxInt32 w
= y
; // height of area to shade
1013 wxInt32 yDelta
= w
/255; // height of one shade bend
1021 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1023 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1026 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1028 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1031 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1033 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1035 wxColour
colour(nR
,nG
,nB
);
1036 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1037 SetBrush(wxBrush(colour
));
1038 if(nDirection
== wxNORTH
)
1039 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1040 rect
.GetWidth(), yDelta
);
1041 else //nDirection == wxSOUTH
1042 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1043 rect
.GetWidth(), yDelta
);
1051 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1052 const wxColour
& initialColour
,
1053 const wxColour
& destColour
,
1054 const wxPoint
& circleCenter
)
1056 //save the old pen color
1057 wxColour oldPenColour
= m_pen
.GetColour();
1059 wxUint8 nR1
= destColour
.Red();
1060 wxUint8 nG1
= destColour
.Green();
1061 wxUint8 nB1
= destColour
.Blue();
1062 wxUint8 nR2
= initialColour
.Red();
1063 wxUint8 nG2
= initialColour
.Green();
1064 wxUint8 nB2
= initialColour
.Blue();
1069 wxInt32 cx
= rect
.GetWidth() / 2;
1070 wxInt32 cy
= rect
.GetHeight() / 2;
1078 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1079 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1081 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1083 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1085 //get color difference
1086 wxInt32 nGradient
= ((nRadius
-
1088 pow((double)(x
- cx
- nCircleOffX
), 2) +
1089 pow((double)(y
- cy
- nCircleOffY
), 2)
1090 )) * 100) / nRadius
;
1092 //normalize Gradient
1097 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1098 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1099 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1102 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1103 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1106 //return old pen color
1107 m_pen
.SetColour(oldPenColour
);
1110 //-----------------------------------------------------------------------------
1112 //-----------------------------------------------------------------------------
1114 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1116 void wxDC::DrawLabel(const wxString
& text
,
1117 const wxBitmap
& bitmap
,
1121 wxRect
*rectBounding
)
1123 // find the text position
1124 wxCoord widthText
, heightText
, heightLine
;
1125 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1127 wxCoord width
, height
;
1130 width
= widthText
+ bitmap
.GetWidth();
1131 height
= bitmap
.GetHeight();
1136 height
= heightText
;
1140 if ( alignment
& wxALIGN_RIGHT
)
1142 x
= rect
.GetRight() - width
;
1144 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1146 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1148 else // alignment & wxALIGN_LEFT
1153 if ( alignment
& wxALIGN_BOTTOM
)
1155 y
= rect
.GetBottom() - height
;
1157 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1159 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1161 else // alignment & wxALIGN_TOP
1166 // draw the bitmap first
1172 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1174 wxCoord offset
= bitmap
.GetWidth() + 4;
1178 y
+= (height
- heightText
) / 2;
1181 // we will draw the underscore under the accel char later
1182 wxCoord startUnderscore
= 0,
1186 // split the string into lines and draw each of them separately
1188 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1190 if ( pc
== text
.end() || *pc
== '\n' )
1192 int xRealStart
= x
; // init it here to avoid compielr warnings
1194 if ( !curLine
.empty() )
1196 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1197 // wxALIGN_LEFT is 0
1198 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1201 GetTextExtent(curLine
, &widthLine
, NULL
);
1203 if ( alignment
& wxALIGN_RIGHT
)
1205 xRealStart
+= width
- widthLine
;
1207 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1209 xRealStart
+= (width
- widthLine
) / 2;
1212 //else: left aligned, nothing to do
1214 DrawText(curLine
, xRealStart
, y
);
1219 // do we have underscore in this line? we can check yUnderscore
1220 // because it is set below to just y + heightLine if we do
1221 if ( y
== yUnderscore
)
1223 // adjust the horz positions to account for the shift
1224 startUnderscore
+= xRealStart
;
1225 endUnderscore
+= xRealStart
;
1228 if ( pc
== text
.end() )
1233 else // not end of line
1235 if ( pc
- text
.begin() == indexAccel
)
1237 // remeber to draw underscore here
1238 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1240 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1242 yUnderscore
= y
+ heightLine
;
1251 // draw the underscore if found
1252 if ( startUnderscore
!= endUnderscore
)
1254 // it should be of the same colour as text
1255 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1259 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1262 // return bounding rect if requested
1265 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1268 CalcBoundingBox(x0
, y0
);
1269 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1272 #if WXWIN_COMPATIBILITY_2_8
1273 // for compatibility with the old code when wxCoord was long everywhere
1274 void wxDC::GetTextExtent(const wxString
& string
,
1277 long *externalLeading
,
1278 const wxFont
*theFont
) const
1280 wxCoord x2
, y2
, descent2
, externalLeading2
;
1281 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1282 &descent2
, &externalLeading2
,
1289 *descent
= descent2
;
1290 if ( externalLeading
)
1291 *externalLeading
= externalLeading2
;
1294 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1297 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1304 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1307 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1314 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1316 wxCoord xx
,yy
,ww
,hh
;
1317 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1324 #endif // WXWIN_COMPATIBILITY_2_8
1327 Notes for wxWidgets DrawEllipticArcRot(...)
1329 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1330 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1333 All methods are generic, so they can be implemented in wxDCBase.
1334 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1335 methods like (WinCE) wxDC::DoDrawArc(...).
1337 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1338 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1339 parts) or every column (in steep parts) only one pixel is calculated.
1340 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1341 starting angle is not equal to the ending angle. The calculation of the
1342 pixels is done using simple arithmetic only and should perform not too
1343 bad even on devices without floating point processor. I didn't test this yet.
1345 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1346 For instance: an ellipse rotated 180 degrees is drawn
1347 slightly different from the original.
1349 The points are then moved to an array and used to draw a polyline and/or polygon
1350 (with center added, the pie).
1351 The result looks quite similar to the native ellipse, only e few pixels differ.
1353 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1354 slower as DrawEllipse(...), which calls the native API.
1355 An rotated ellipse outside the clipping region takes nearly the same time,
1356 while an native ellipse outside takes nearly no time to draw.
1358 If you draw an arc with this new method, you will see the starting and ending angles
1359 are calculated properly.
1360 If you use DrawEllipticArc(...), you will see they are only correct for circles
1361 and not properly calculated for ellipses.
1364 p.lenhard@t-online.de
1368 void wxDCImpl::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1369 wxCoord w
, wxCoord h
,
1370 double sa
, double ea
, double angle
)
1374 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1375 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1377 // Add center (for polygon/pie)
1378 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1380 // copy list into array and delete list elements
1381 int n
= list
.GetCount();
1382 wxPoint
*points
= new wxPoint
[n
];
1384 wxPointList::compatibility_iterator node
;
1385 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1387 wxPoint
*point
= node
->GetData();
1388 points
[i
].x
= point
->x
;
1389 points
[i
].y
= point
->y
;
1393 // first draw the pie without pen, if necessary
1394 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1396 wxPen
tempPen( GetPen() );
1397 SetPen( *wxTRANSPARENT_PEN
);
1398 DoDrawPolygon( n
, points
, 0, 0 );
1402 // then draw the arc without brush, if necessary
1403 if( GetPen() != *wxTRANSPARENT_PEN
)
1406 DoDrawLines( n
-1, points
, 0, 0 );
1411 } // DrawEllipticArcRot
1413 void wxDCImpl::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1418 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1419 double dCosA
= cos(angle
*2.0*pi
/360.0);
1420 wxPointList::compatibility_iterator node
;
1421 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1423 wxPoint
* point
= node
->GetData();
1425 // transform coordinates, if necessary
1426 if( center
.x
) point
->x
-= center
.x
;
1427 if( center
.y
) point
->y
-= center
.y
;
1429 // calculate rotation, rounding simply by implicit cast to integer
1430 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1431 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1434 // back transform coordinates, if necessary
1435 if( center
.x
) point
->x
+= center
.x
;
1436 if( center
.y
) point
->y
+= center
.y
;
1441 void wxDCImpl::CalculateEllipticPoints( wxPointList
* points
,
1442 wxCoord xStart
, wxCoord yStart
,
1443 wxCoord w
, wxCoord h
,
1444 double sa
, double ea
)
1455 bool bUseAngles
= false;
1461 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1463 if( 2*a
== w
) decrX
= 1;
1465 if( 2*b
== h
) decrY
= 1;
1467 wxCoord xCenter
= xStart
+ a
;
1468 wxCoord yCenter
= yStart
+ b
;
1469 // calculate data for start and end, if necessary
1473 // normalisation of angles
1474 while( sa
<0 ) sa
+= 360;
1475 while( ea
<0 ) ea
+= 360;
1476 while( sa
>=360 ) sa
-= 360;
1477 while( ea
>=360 ) ea
-= 360;
1478 // calculate quadrant numbers
1479 if( sa
> 270 ) sq
= 3;
1480 else if( sa
> 180 ) sq
= 2;
1481 else if( sa
> 90 ) sq
= 1;
1482 if( ea
> 270 ) eq
= 3;
1483 else if( ea
> 180 ) eq
= 2;
1484 else if( ea
> 90 ) eq
= 1;
1485 sar
= sa
* pi
/ 180.0;
1486 ear
= ea
* pi
/ 180.0;
1487 // correct angle circle -> ellipse
1488 sar
= atan( -a
/(double)b
* tan( sar
) );
1489 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1490 ear
= atan( -a
/(double)b
* tan( ear
) );
1491 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1492 // coordinates of points
1493 xsa
= xCenter
+ a
* cos( sar
);
1494 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1495 ysa
= yCenter
+ b
* sin( sar
);
1496 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1497 xea
= xCenter
+ a
* cos( ear
);
1498 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1499 yea
= yCenter
+ b
* sin( ear
);
1500 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1502 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1504 double c2
= 2.0 / w
;
1513 // Lists for quadrant 1 to 4
1514 wxPointList pointsarray
[4];
1515 // Calculate points for first quadrant and set in all quadrants
1516 for( x
= 0; x
<= a
; ++x
)
1521 bool bNewPoint
= false;
1522 while( y2
> c1
- c2
* x2
&& y
> 0 )
1528 // old y now to big: set point with old y, old x
1529 if( bNewPoint
&& x
>1)
1532 // remove points on the same line
1533 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1534 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1535 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1536 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1538 } // calculate point
1540 // Starting and/or ending points for the quadrants, first quadrant gets both.
1541 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1542 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1543 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1544 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1545 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1547 // copy quadrants in original list
1550 // Copy the right part of the points in the lists
1551 // and delete the wxPoints, because they do not leave this method.
1552 points
->Append( new wxPoint( xsa
, ysa
) );
1554 bool bStarted
= false;
1555 bool bReady
= false;
1556 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1559 wxPointList::compatibility_iterator node
;
1560 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1562 // once: go to starting point in start quadrant
1565 node
->GetData()->x
< xsa
+1 && q
<= 1
1567 node
->GetData()->x
> xsa
-1 && q
>= 2
1574 // copy point, if not at ending point
1577 if( q
!= eq
|| bForceTurn
1579 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1581 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1585 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1586 points
->Append( pPoint
);
1588 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1598 } // while not bReady
1599 points
->Append( new wxPoint( xea
, yea
) );
1602 for( q
= 0; q
< 4; ++q
)
1604 wxPointList::compatibility_iterator node
;
1605 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1607 wxPoint
*p
= node
->GetData();
1614 wxPointList::compatibility_iterator node
;
1615 // copy whole ellipse, wxPoints will be deleted outside
1616 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1618 wxPoint
*p
= node
->GetData();
1619 points
->Append( p
);
1621 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1623 wxPoint
*p
= node
->GetData();
1624 points
->Append( p
);
1626 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1628 wxPoint
*p
= node
->GetData();
1629 points
->Append( p
);
1631 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1633 wxPoint
*p
= node
->GetData();
1634 points
->Append( p
);
1637 } // CalculateEllipticPoints
1639 #endif // __WXWINCE__