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/osx/dcclient.h"
57 #include "wx/osx/dcmemory.h"
58 #include "wx/osx/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
, wxWindow
*window
)
136 return new wxWindowDCImpl( owner
, window
);
139 wxDCImpl
* wxNativeDCFactory
::CreateClientDC( wxClientDC
*owner
, wxWindow
*window
)
141 return new wxClientDCImpl( owner
, window
);
144 wxDCImpl
* wxNativeDCFactory
::CreatePaintDC( wxPaintDC
*owner
, wxWindow
*window
)
146 return new wxPaintDCImpl( owner
, window
);
149 wxDCImpl
* wxNativeDCFactory
::CreateMemoryDC( wxMemoryDC
*owner
)
151 return new wxMemoryDCImpl( owner
);
154 wxDCImpl
* wxNativeDCFactory
::CreateMemoryDC( wxMemoryDC
*owner
, wxBitmap
&bitmap
)
156 return new wxMemoryDCImpl( owner
, bitmap
);
159 wxDCImpl
* wxNativeDCFactory
::CreateMemoryDC( wxMemoryDC
*owner
, wxDC
*dc
)
161 return new wxMemoryDCImpl( owner
, dc
);
164 wxDCImpl
* wxNativeDCFactory
::CreateScreenDC( wxScreenDC
*owner
)
166 return new wxScreenDCImpl( owner
);
169 #if wxUSE_PRINTING_ARCHITECTURE
170 wxDCImpl
*wxNativeDCFactory
::CreatePrinterDC( wxPrinterDC
*owner
, const wxPrintData
&data
)
172 wxPrintFactory
*factory
= wxPrintFactory
::GetFactory();
173 return factory
->CreatePrinterDCImpl( owner
, data
);
177 //-----------------------------------------------------------------------------
179 //-----------------------------------------------------------------------------
181 IMPLEMENT_ABSTRACT_CLASS(wxWindowDC
, wxDC
)
183 wxWindowDC
::wxWindowDC(wxWindow
*win
)
184 : wxDC(wxDCFactory
::Get()->CreateWindowDC(this, win
))
188 //-----------------------------------------------------------------------------
190 //-----------------------------------------------------------------------------
192 IMPLEMENT_ABSTRACT_CLASS(wxClientDC
, wxWindowDC
)
194 wxClientDC
::wxClientDC(wxWindow
*win
)
195 : wxWindowDC(wxDCFactory
::Get()->CreateClientDC(this, win
))
199 //-----------------------------------------------------------------------------
201 //-----------------------------------------------------------------------------
203 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC
, wxDC
)
205 wxMemoryDC
::wxMemoryDC()
206 : wxDC(wxDCFactory
::Get()->CreateMemoryDC(this))
210 wxMemoryDC
::wxMemoryDC(wxBitmap
& bitmap
)
211 : wxDC(wxDCFactory
::Get()->CreateMemoryDC(this, bitmap
))
215 wxMemoryDC
::wxMemoryDC(wxDC
*dc
)
216 : wxDC(wxDCFactory
::Get()->CreateMemoryDC(this, dc
))
220 void wxMemoryDC
::SelectObject(wxBitmap
& bmp
)
222 // make sure that the given wxBitmap is not sharing its data with other
223 // wxBitmap instances as its contents will be modified by any drawing
224 // operation done on this DC
228 GetImpl()->DoSelect(bmp
);
231 void wxMemoryDC
::SelectObjectAsSource(const wxBitmap
& bmp
)
233 GetImpl()->DoSelect(bmp
);
236 const wxBitmap
& wxMemoryDC
::GetSelectedBitmap() const
238 return GetImpl()->GetSelectedBitmap();
241 wxBitmap
& wxMemoryDC
::GetSelectedBitmap()
243 return GetImpl()->GetSelectedBitmap();
247 //-----------------------------------------------------------------------------
249 //-----------------------------------------------------------------------------
251 IMPLEMENT_ABSTRACT_CLASS(wxPaintDC
, wxClientDC
)
253 wxPaintDC
::wxPaintDC(wxWindow
*win
)
254 : wxClientDC(wxDCFactory
::Get()->CreatePaintDC(this, win
))
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
262 IMPLEMENT_DYNAMIC_CLASS(wxScreenDC
, wxWindowDC
)
264 wxScreenDC
::wxScreenDC()
265 : wxDC(wxDCFactory
::Get()->CreateScreenDC(this))
269 //-----------------------------------------------------------------------------
271 //-----------------------------------------------------------------------------
273 #if wxUSE_PRINTING_ARCHITECTURE
275 IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC
, wxDC
)
277 wxPrinterDC
::wxPrinterDC()
278 : wxDC(wxDCFactory
::Get()->CreatePrinterDC(this, wxPrintData()))
282 wxPrinterDC
::wxPrinterDC(const wxPrintData
& data
)
283 : wxDC(wxDCFactory
::Get()->CreatePrinterDC(this, data
))
287 wxRect wxPrinterDC
::GetPaperRect()
289 return GetImpl()->GetPaperRect();
292 int wxPrinterDC
::GetResolution()
294 return GetImpl()->GetResolution();
297 #endif // wxUSE_PRINTING_ARCHITECTURE
299 //-----------------------------------------------------------------------------
301 //-----------------------------------------------------------------------------
303 IMPLEMENT_ABSTRACT_CLASS(wxDCImpl
, wxObject
)
305 wxDCImpl
::wxDCImpl( wxDC
*owner
)
307 , m_colour(wxColourDisplay())
311 , m_isBBoxValid(false)
312 , m_logicalOriginX(0), m_logicalOriginY(0)
313 , m_deviceOriginX(0), m_deviceOriginY(0)
314 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
315 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
316 , m_userScaleX(1.0), m_userScaleY(1.0)
317 , m_scaleX(1.0), m_scaleY(1.0)
318 , m_signX(1), m_signY(1)
319 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
320 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
321 , m_logicalFunction(wxCOPY
)
322 , m_backgroundMode(wxBRUSHSTYLE_TRANSPARENT
)
323 , m_mappingMode(wxMM_TEXT
)
326 , m_backgroundBrush()
327 , m_textForegroundColour(*wxBLACK
)
328 , m_textBackgroundColour(*wxWHITE
)
332 , m_hasCustomPalette(false)
333 #endif // wxUSE_PALETTE
337 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
338 (double)wxGetDisplaySizeMM().GetWidth();
339 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
340 (double)wxGetDisplaySizeMM().GetHeight();
346 wxDCImpl
::~wxDCImpl()
350 // ----------------------------------------------------------------------------
351 // coordinate conversions and transforms
352 // ----------------------------------------------------------------------------
354 wxCoord wxDCImpl
::DeviceToLogicalX(wxCoord x
) const
356 return wxRound( (double)((x
- m_deviceOriginX
- m_deviceLocalOriginX
) * m_signX
) / m_scaleX
) + m_logicalOriginX
;
359 wxCoord wxDCImpl
::DeviceToLogicalY(wxCoord y
) const
361 return wxRound( (double)((y
- m_deviceOriginY
- m_deviceLocalOriginY
) * m_signY
) / m_scaleY
) + m_logicalOriginY
;
364 wxCoord wxDCImpl
::DeviceToLogicalXRel(wxCoord x
) const
366 return wxRound((double)(x
) / m_scaleX
);
369 wxCoord wxDCImpl
::DeviceToLogicalYRel(wxCoord y
) const
371 return wxRound((double)(y
) / m_scaleY
);
374 wxCoord wxDCImpl
::LogicalToDeviceX(wxCoord x
) const
376 return wxRound( (double)((x
- m_logicalOriginX
) * m_signX
) * m_scaleX
) + m_deviceOriginX
+ m_deviceLocalOriginX
;
379 wxCoord wxDCImpl
::LogicalToDeviceY(wxCoord y
) const
381 return wxRound( (double)((y
- m_logicalOriginY
) * m_signY
) * m_scaleY
) + m_deviceOriginY
+ m_deviceLocalOriginY
;
384 wxCoord wxDCImpl
::LogicalToDeviceXRel(wxCoord x
) const
386 return wxRound((double)(x
) * m_scaleX
);
389 wxCoord wxDCImpl
::LogicalToDeviceYRel(wxCoord y
) const
391 return wxRound((double)(y
) * m_scaleY
);
394 void wxDCImpl
::ComputeScaleAndOrigin()
396 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
397 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
400 void wxDCImpl
::SetMapMode( int mode
)
405 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
408 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
411 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
414 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
418 SetLogicalScale( 1.0, 1.0 );
421 m_mappingMode
= mode
;
424 void wxDCImpl
::SetUserScale( double x
, double y
)
426 // allow negative ? -> no
429 ComputeScaleAndOrigin();
432 void wxDCImpl
::SetLogicalScale( double x
, double y
)
437 ComputeScaleAndOrigin();
440 void wxDCImpl
::SetLogicalOrigin( wxCoord x
, wxCoord y
)
442 m_logicalOriginX
= x
* m_signX
;
443 m_logicalOriginY
= y
* m_signY
;
444 ComputeScaleAndOrigin();
447 void wxDCImpl
::SetDeviceOrigin( wxCoord x
, wxCoord y
)
451 ComputeScaleAndOrigin();
454 void wxDCImpl
::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
456 m_deviceLocalOriginX
= x
;
457 m_deviceLocalOriginY
= y
;
458 ComputeScaleAndOrigin();
461 void wxDCImpl
::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
463 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
464 // wxWidgets 2.9: no longer override it
465 m_signX
= (xLeftRight ?
1 : -1);
466 m_signY
= (yBottomUp ?
-1 : 1);
467 ComputeScaleAndOrigin();
471 // Each element of the widths array will be the width of the string up to and
472 // including the corresponding character in text. This is the generic
473 // implementation, the port-specific classes should do this with native APIs
474 // if available and if faster. Note: pango_layout_index_to_pos is much slower
475 // than calling GetTextExtent!!
482 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
483 ~FontWidthCache() { delete []m_widths
; }
488 m_widths
= new int[FWC_SIZE
];
490 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
498 static FontWidthCache s_fontWidthCache
;
500 bool wxDCImpl
::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
504 const size_t len
= text
.length();
508 // reset the cache if font or horizontal scale have changed
509 if ( !s_fontWidthCache
.m_widths
||
510 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
511 (s_fontWidthCache
.m_font
!= GetFont()) )
513 s_fontWidthCache
.Reset();
514 s_fontWidthCache
.m_font
= GetFont();
515 s_fontWidthCache
.m_scaleX
= m_scaleX
;
518 // Calculate the position of each character based on the widths of
519 // the previous characters
521 for ( size_t i
= 0; i
< len
; i
++ )
523 const wxChar c
= text
[i
];
524 unsigned int c_int
= (unsigned int)c
;
526 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
528 w
= s_fontWidthCache
.m_widths
[c_int
];
532 DoGetTextExtent(c
, &w
, &h
);
533 if (c_int
< FWC_SIZE
)
534 s_fontWidthCache
.m_widths
[c_int
] = w
;
538 widths
[i
] = totalWidth
;
544 void wxDCImpl
::GetMultiLineTextExtent(const wxString
& text
,
548 const wxFont
*font
) const
550 wxCoord widthTextMax
= 0, widthLine
,
551 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
554 for ( wxString
::const_iterator pc
= text
.begin(); ; ++pc
)
556 if ( pc
== text
.end() || *pc
== _T('\n') )
558 if ( curLine
.empty() )
560 // we can't use GetTextExtent - it will return 0 for both width
561 // and height and an empty line should count in height
564 // assume that this line has the same height as the previous
566 if ( !heightLineDefault
)
567 heightLineDefault
= heightLine
;
569 if ( !heightLineDefault
)
571 // but we don't know it yet - choose something reasonable
572 DoGetTextExtent(_T("W"), NULL
, &heightLineDefault
,
576 heightTextTotal
+= heightLineDefault
;
580 DoGetTextExtent(curLine
, &widthLine
, &heightLine
,
582 if ( widthLine
> widthTextMax
)
583 widthTextMax
= widthLine
;
584 heightTextTotal
+= heightLine
;
587 if ( pc
== text
.end() )
605 *y
= heightTextTotal
;
610 void wxDCImpl
::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
611 wxCoord width
, wxCoord height
)
613 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
615 wxCoord x2
= x1
+ width
,
618 // the pen width is calibrated to give 3 for width == height == 10
619 wxDCPenChanger
pen( *m_owner
, wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
621 // we're drawing a scaled version of wx/generic/tick.xpm here
622 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
623 y3
= y1
+ height
/ 2; // y of the left tick branch
624 DoDrawLine(x1
, y3
, x3
, y2
);
625 DoDrawLine(x3
, y2
, x2
, y1
);
627 CalcBoundingBox(x1
, y1
);
628 CalcBoundingBox(x2
, y2
);
632 wxDCImpl
::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
633 wxCoord dstWidth
, wxCoord dstHeight
,
635 wxCoord xsrc
, wxCoord ysrc
,
636 wxCoord srcWidth
, wxCoord srcHeight
,
642 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
643 _T("invalid blit size") );
645 // emulate the stretching by modifying the DC scale
646 double xscale
= (double)srcWidth
/dstWidth
,
647 yscale
= (double)srcHeight
/dstHeight
;
649 double xscaleOld
, yscaleOld
;
650 GetUserScale(&xscaleOld
, &yscaleOld
);
651 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
653 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
654 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
656 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
658 SetUserScale(xscaleOld
, yscaleOld
);
663 void wxDCImpl
::DrawLines(const wxPointList
*list
, wxCoord xoffset
, wxCoord yoffset
)
665 int n
= list
->GetCount();
666 wxPoint
*points
= new wxPoint
[n
];
669 for ( wxPointList
::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
671 wxPoint
*point
= node
->GetData();
672 points
[i
].x
= point
->x
;
673 points
[i
].y
= point
->y
;
676 DoDrawLines(n
, points
, xoffset
, yoffset
);
681 void wxDCImpl
::DrawPolygon(const wxPointList
*list
,
682 wxCoord xoffset
, wxCoord yoffset
,
685 int n
= list
->GetCount();
686 wxPoint
*points
= new wxPoint
[n
];
689 for ( wxPointList
::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
691 wxPoint
*point
= node
->GetData();
692 points
[i
].x
= point
->x
;
693 points
[i
].y
= point
->y
;
696 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
702 wxDCImpl
::DoDrawPolyPolygon(int n
,
705 wxCoord xoffset
, wxCoord yoffset
,
710 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
718 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
723 pts
= new wxPoint
[j
+n
-1];
724 for (i
= 0; i
< j
; i
++)
726 for (i
= 2; i
<= n
; i
++)
728 lastOfs
-= count
[n
-i
];
729 pts
[j
++] = pts
[lastOfs
];
733 SetPen(wxPen(*wxBLACK
, 0, wxPENSTYLE_TRANSPARENT
));
734 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
736 for (i
= j
= 0; i
< n
; i
++)
738 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
746 void wxDCImpl
::DrawSpline(wxCoord x1
, wxCoord y1
,
747 wxCoord x2
, wxCoord y2
,
748 wxCoord x3
, wxCoord y3
)
750 wxPoint points
[] = { wxPoint(x1
, y1
), wxPoint(x2
, y2
), wxPoint(x3
, y3
) };
751 DrawSpline(WXSIZEOF(points
), points
);
754 void wxDCImpl
::DrawSpline(int n
, wxPoint points
[])
757 for ( int i
= 0; i
< n
; i
++ )
758 list
.Append(&points
[i
]);
763 // ----------------------------------- spline code ----------------------------------------
765 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
766 double a3
, double b3
, double a4
, double b4
);
767 void wx_clear_stack();
768 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
769 double *y3
, double *x4
, double *y4
);
770 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
771 double x4
, double y4
);
772 static bool wx_spline_add_point(double x
, double y
);
773 static void wx_spline_draw_point_array(wxDC
*dc
);
775 wxPointList wx_spline_point_list
;
777 #define half(z1, z2) ((z1+z2)/2.0)
780 /* iterative version */
782 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
785 register double xmid
, ymid
;
786 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
789 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
791 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
792 xmid
= (double)half(x2
, x3
);
793 ymid
= (double)half(y2
, y3
);
794 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
795 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
796 wx_spline_add_point( x1
, y1
);
797 wx_spline_add_point( xmid
, ymid
);
799 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
800 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
801 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
802 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
807 /* utilities used by spline drawing routines */
809 typedef struct wx_spline_stack_struct
{
810 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
813 #define SPLINE_STACK_DEPTH 20
814 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
815 static Stack
*wx_stack_top
;
816 static int wx_stack_count
;
818 void wx_clear_stack()
820 wx_stack_top
= wx_spline_stack
;
824 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
826 wx_stack_top
->x1
= x1
;
827 wx_stack_top
->y1
= y1
;
828 wx_stack_top
->x2
= x2
;
829 wx_stack_top
->y2
= y2
;
830 wx_stack_top
->x3
= x3
;
831 wx_stack_top
->y3
= y3
;
832 wx_stack_top
->x4
= x4
;
833 wx_stack_top
->y4
= y4
;
838 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
839 double *x3
, double *y3
, double *x4
, double *y4
)
841 if (wx_stack_count
== 0)
845 *x1
= wx_stack_top
->x1
;
846 *y1
= wx_stack_top
->y1
;
847 *x2
= wx_stack_top
->x2
;
848 *y2
= wx_stack_top
->y2
;
849 *x3
= wx_stack_top
->x3
;
850 *y3
= wx_stack_top
->y3
;
851 *x4
= wx_stack_top
->x4
;
852 *y4
= wx_stack_top
->y4
;
856 static bool wx_spline_add_point(double x
, double y
)
858 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
859 wx_spline_point_list
.Append(point
);
863 static void wx_spline_draw_point_array(wxDC
*dc
)
865 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
866 wxPointList
::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
869 wxPoint
*point
= node
->GetData();
871 wx_spline_point_list
.Erase(node
);
872 node
= wx_spline_point_list
.GetFirst();
876 void wxDCImpl
::DoDrawSpline( const wxPointList
*points
)
878 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
881 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
882 double x1
, y1
, x2
, y2
;
884 wxPointList
::compatibility_iterator node
= points
->GetFirst();
889 p
= (wxPoint
*)node
->GetData();
894 node
= node
->GetNext();
899 cx1
= (double)((x1
+ x2
) / 2);
900 cy1
= (double)((y1
+ y2
) / 2);
901 cx2
= (double)((cx1
+ x2
) / 2);
902 cy2
= (double)((cy1
+ y2
) / 2);
904 wx_spline_add_point(x1
, y1
);
906 while ((node
= node
->GetNext())
917 cx4
= (double)(x1
+ x2
) / 2;
918 cy4
= (double)(y1
+ y2
) / 2;
919 cx3
= (double)(x1
+ cx4
) / 2;
920 cy3
= (double)(y1
+ cy4
) / 2;
922 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
926 cx2
= (double)(cx1
+ x2
) / 2;
927 cy2
= (double)(cy1
+ y2
) / 2;
930 wx_spline_add_point( cx1
, cy1
);
931 wx_spline_add_point( x2
, y2
);
933 wx_spline_draw_point_array( m_owner
);
936 #endif // wxUSE_SPLINES
940 void wxDCImpl
::DoGradientFillLinear(const wxRect
& rect
,
941 const wxColour
& initialColour
,
942 const wxColour
& destColour
,
943 wxDirection nDirection
)
946 wxPen oldPen
= m_pen
;
947 wxBrush oldBrush
= m_brush
;
949 wxUint8 nR1
= initialColour
.Red();
950 wxUint8 nG1
= initialColour
.Green();
951 wxUint8 nB1
= initialColour
.Blue();
952 wxUint8 nR2
= destColour
.Red();
953 wxUint8 nG2
= destColour
.Green();
954 wxUint8 nB2
= destColour
.Blue();
957 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
959 wxInt32 x
= rect
.GetWidth();
960 wxInt32 w
= x
; // width of area to shade
961 wxInt32 xDelta
= w
/256; // height of one shade bend
969 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
971 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
974 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
976 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
979 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
981 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
983 wxColour
colour(nR
,nG
,nB
);
984 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
985 SetBrush(wxBrush(colour
));
986 if(nDirection
== wxEAST
)
987 DoDrawRectangle(rect
.GetRight()-x
-xDelta
+1, rect
.GetTop(),
988 xDelta
, rect
.GetHeight());
989 else //nDirection == wxWEST
990 DoDrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
991 xDelta
, rect
.GetHeight());
994 else // nDirection == wxNORTH || nDirection == wxSOUTH
996 wxInt32 y
= rect
.GetHeight();
997 wxInt32 w
= y
; // height of area to shade
998 wxInt32 yDelta
= w
/255; // height of one shade bend
1006 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1008 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1011 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1013 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1016 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1018 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1020 wxColour
colour(nR
,nG
,nB
);
1021 SetPen(wxPen(colour
, 1, wxPENSTYLE_SOLID
));
1022 SetBrush(wxBrush(colour
));
1023 if(nDirection
== wxNORTH
)
1024 DoDrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1025 rect
.GetWidth(), yDelta
);
1026 else //nDirection == wxSOUTH
1027 DoDrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
+1,
1028 rect
.GetWidth(), yDelta
);
1036 void wxDCImpl
::DoGradientFillConcentric(const wxRect
& rect
,
1037 const wxColour
& initialColour
,
1038 const wxColour
& destColour
,
1039 const wxPoint
& circleCenter
)
1041 //save the old pen color
1042 wxColour oldPenColour
= m_pen
.GetColour();
1044 wxUint8 nR1
= destColour
.Red();
1045 wxUint8 nG1
= destColour
.Green();
1046 wxUint8 nB1
= destColour
.Blue();
1047 wxUint8 nR2
= initialColour
.Red();
1048 wxUint8 nG2
= initialColour
.Green();
1049 wxUint8 nB2
= initialColour
.Blue();
1054 wxInt32 cx
= rect
.GetWidth() / 2;
1055 wxInt32 cy
= rect
.GetHeight() / 2;
1063 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1064 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1066 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1068 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1070 //get color difference
1071 wxInt32 nGradient
= ((nRadius
-
1073 pow((double)(x
- cx
- nCircleOffX
), 2) +
1074 pow((double)(y
- cy
- nCircleOffY
), 2)
1075 )) * 100) / nRadius
;
1077 //normalize Gradient
1082 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1083 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1084 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1087 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1088 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1091 //return old pen color
1092 m_pen
.SetColour(oldPenColour
);
1095 //-----------------------------------------------------------------------------
1097 //-----------------------------------------------------------------------------
1099 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1101 void wxDC
::DrawLabel(const wxString
& text
,
1102 const wxBitmap
& bitmap
,
1106 wxRect
*rectBounding
)
1108 // find the text position
1109 wxCoord widthText
, heightText
, heightLine
;
1110 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1112 wxCoord width
, height
;
1115 width
= widthText
+ bitmap
.GetWidth();
1116 height
= bitmap
.GetHeight();
1121 height
= heightText
;
1125 if ( alignment
& wxALIGN_RIGHT
)
1127 x
= rect
.GetRight() - width
;
1129 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1131 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1133 else // alignment & wxALIGN_LEFT
1138 if ( alignment
& wxALIGN_BOTTOM
)
1140 y
= rect
.GetBottom() - height
;
1142 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1144 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1146 else // alignment & wxALIGN_TOP
1151 // draw the bitmap first
1157 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1159 wxCoord offset
= bitmap
.GetWidth() + 4;
1163 y
+= (height
- heightText
) / 2;
1166 // we will draw the underscore under the accel char later
1167 wxCoord startUnderscore
= 0,
1171 // split the string into lines and draw each of them separately
1173 for ( wxString
::const_iterator pc
= text
.begin(); ; ++pc
)
1175 if ( pc
== text
.end() || *pc
== '\n' )
1177 int xRealStart
= x
; // init it here to avoid compielr warnings
1179 if ( !curLine
.empty() )
1181 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1182 // wxALIGN_LEFT is 0
1183 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1186 GetTextExtent(curLine
, &widthLine
, NULL
);
1188 if ( alignment
& wxALIGN_RIGHT
)
1190 xRealStart
+= width
- widthLine
;
1192 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1194 xRealStart
+= (width
- widthLine
) / 2;
1197 //else: left aligned, nothing to do
1199 DrawText(curLine
, xRealStart
, y
);
1204 // do we have underscore in this line? we can check yUnderscore
1205 // because it is set below to just y + heightLine if we do
1206 if ( y
== yUnderscore
)
1208 // adjust the horz positions to account for the shift
1209 startUnderscore
+= xRealStart
;
1210 endUnderscore
+= xRealStart
;
1213 if ( pc
== text
.end() )
1218 else // not end of line
1220 if ( pc
- text
.begin() == indexAccel
)
1222 // remeber to draw underscore here
1223 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1225 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1227 yUnderscore
= y
+ heightLine
;
1236 // draw the underscore if found
1237 if ( startUnderscore
!= endUnderscore
)
1239 // it should be of the same colour as text
1240 SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID
));
1244 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1247 // return bounding rect if requested
1250 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1253 CalcBoundingBox(x0
, y0
);
1254 CalcBoundingBox(x0
+ width0
, y0
+ height
);
1257 #if WXWIN_COMPATIBILITY_2_8
1258 // for compatibility with the old code when wxCoord was long everywhere
1259 void wxDC
::GetTextExtent(const wxString
& string
,
1262 long *externalLeading
,
1263 const wxFont
*theFont
) const
1265 wxCoord x2
, y2
, descent2
, externalLeading2
;
1266 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1267 &descent2
, &externalLeading2
,
1274 *descent
= descent2
;
1275 if ( externalLeading
)
1276 *externalLeading
= externalLeading2
;
1279 void wxDC
::GetLogicalOrigin(long *x
, long *y
) const
1282 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1289 void wxDC
::GetDeviceOrigin(long *x
, long *y
) const
1292 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1299 void wxDC
::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1301 wxCoord xx
,yy
,ww
,hh
;
1302 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1309 #endif // WXWIN_COMPATIBILITY_2_8
1312 Notes for wxWidgets DrawEllipticArcRot(...)
1314 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1315 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1318 All methods are generic, so they can be implemented in wxDCBase.
1319 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1320 methods like (WinCE) wxDC::DoDrawArc(...).
1322 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1323 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1324 parts) or every column (in steep parts) only one pixel is calculated.
1325 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1326 starting angle is not equal to the ending angle. The calculation of the
1327 pixels is done using simple arithmetic only and should perform not too
1328 bad even on devices without floating point processor. I didn't test this yet.
1330 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1331 For instance: an ellipse rotated 180 degrees is drawn
1332 slightly different from the original.
1334 The points are then moved to an array and used to draw a polyline and/or polygon
1335 (with center added, the pie).
1336 The result looks quite similar to the native ellipse, only e few pixels differ.
1338 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1339 slower as DrawEllipse(...), which calls the native API.
1340 An rotated ellipse outside the clipping region takes nearly the same time,
1341 while an native ellipse outside takes nearly no time to draw.
1343 If you draw an arc with this new method, you will see the starting and ending angles
1344 are calculated properly.
1345 If you use DrawEllipticArc(...), you will see they are only correct for circles
1346 and not properly calculated for ellipses.
1349 p.lenhard@t-online.de
1353 void wxDCImpl
::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1354 wxCoord w
, wxCoord h
,
1355 double sa
, double ea
, double angle
)
1359 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1360 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1362 // Add center (for polygon/pie)
1363 list
.Append( new wxPoint( x
+w
/2, y
+h
/2 ) );
1365 // copy list into array and delete list elements
1366 int n
= list
.GetCount();
1367 wxPoint
*points
= new wxPoint
[n
];
1369 wxPointList
::compatibility_iterator node
;
1370 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1372 wxPoint
*point
= node
->GetData();
1373 points
[i
].x
= point
->x
;
1374 points
[i
].y
= point
->y
;
1378 // first draw the pie without pen, if necessary
1379 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1381 wxPen
tempPen( GetPen() );
1382 SetPen( *wxTRANSPARENT_PEN
);
1383 DoDrawPolygon( n
, points
, 0, 0 );
1387 // then draw the arc without brush, if necessary
1388 if( GetPen() != *wxTRANSPARENT_PEN
)
1391 DoDrawLines( n
-1, points
, 0, 0 );
1396 } // DrawEllipticArcRot
1398 void wxDCImpl
::Rotate( wxPointList
* points
, double angle
, wxPoint center
)
1403 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1404 double dCosA
= cos(angle
*2.0*pi
/360.0);
1405 wxPointList
::compatibility_iterator node
;
1406 for ( node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1408 wxPoint
* point
= node
->GetData();
1410 // transform coordinates, if necessary
1411 if( center
.x
) point
->x
-= center
.x
;
1412 if( center
.y
) point
->y
-= center
.y
;
1414 // calculate rotation, rounding simply by implicit cast to integer
1415 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1416 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1419 // back transform coordinates, if necessary
1420 if( center
.x
) point
->x
+= center
.x
;
1421 if( center
.y
) point
->y
+= center
.y
;
1426 void wxDCImpl
::CalculateEllipticPoints( wxPointList
* points
,
1427 wxCoord xStart
, wxCoord yStart
,
1428 wxCoord w
, wxCoord h
,
1429 double sa
, double ea
)
1440 bool bUseAngles
= false;
1446 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1448 if( 2*a
== w
) decrX
= 1;
1450 if( 2*b
== h
) decrY
= 1;
1452 wxCoord xCenter
= xStart
+ a
;
1453 wxCoord yCenter
= yStart
+ b
;
1454 // calculate data for start and end, if necessary
1458 // normalisation of angles
1459 while( sa
<0 ) sa
+= 360;
1460 while( ea
<0 ) ea
+= 360;
1461 while( sa
>=360 ) sa
-= 360;
1462 while( ea
>=360 ) ea
-= 360;
1463 // calculate quadrant numbers
1464 if( sa
> 270 ) sq
= 3;
1465 else if( sa
> 180 ) sq
= 2;
1466 else if( sa
> 90 ) sq
= 1;
1467 if( ea
> 270 ) eq
= 3;
1468 else if( ea
> 180 ) eq
= 2;
1469 else if( ea
> 90 ) eq
= 1;
1470 sar
= sa
* pi
/ 180.0;
1471 ear
= ea
* pi
/ 180.0;
1472 // correct angle circle -> ellipse
1473 sar
= atan( -a
/(double)b
* tan( sar
) );
1474 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1475 ear
= atan( -a
/(double)b
* tan( ear
) );
1476 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1477 // coordinates of points
1478 xsa
= xCenter
+ a
* cos( sar
);
1479 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1480 ysa
= yCenter
+ b
* sin( sar
);
1481 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1482 xea
= xCenter
+ a
* cos( ear
);
1483 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1484 yea
= yCenter
+ b
* sin( ear
);
1485 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1487 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1489 double c2
= 2.0 / w
;
1498 // Lists for quadrant 1 to 4
1499 wxPointList pointsarray
[4];
1500 // Calculate points for first quadrant and set in all quadrants
1501 for( x
= 0; x
<= a
; ++x
)
1506 bool bNewPoint
= false;
1507 while( y2
> c1
- c2
* x2
&& y
> 0 )
1513 // old y now to big: set point with old y, old x
1514 if( bNewPoint
&& x
>1)
1517 // remove points on the same line
1518 pointsarray
[0].Insert( new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1519 pointsarray
[1].Append( new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1520 pointsarray
[2].Insert( new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1521 pointsarray
[3].Append( new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1523 } // calculate point
1525 // Starting and/or ending points for the quadrants, first quadrant gets both.
1526 pointsarray
[0].Insert( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1527 pointsarray
[0].Append( new wxPoint( xCenter
, yCenter
- b
) );
1528 pointsarray
[1].Append( new wxPoint( xCenter
- a
, yCenter
) );
1529 pointsarray
[2].Append( new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1530 pointsarray
[3].Append( new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1532 // copy quadrants in original list
1535 // Copy the right part of the points in the lists
1536 // and delete the wxPoints, because they do not leave this method.
1537 points
->Append( new wxPoint( xsa
, ysa
) );
1539 bool bStarted
= false;
1540 bool bReady
= false;
1541 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1544 wxPointList
::compatibility_iterator node
;
1545 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1547 // once: go to starting point in start quadrant
1550 node
->GetData()->x
< xsa
+1 && q
<= 1
1552 node
->GetData()->x
> xsa
-1 && q
>= 2
1559 // copy point, if not at ending point
1562 if( q
!= eq
|| bForceTurn
1564 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1566 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1570 wxPoint
* pPoint
= new wxPoint( *(node
->GetData()) );
1571 points
->Append( pPoint
);
1573 else if( q
== eq
&& !bForceTurn
|| node
->GetData()->x
== xea
)
1583 } // while not bReady
1584 points
->Append( new wxPoint( xea
, yea
) );
1587 for( q
= 0; q
< 4; ++q
)
1589 wxPointList
::compatibility_iterator node
;
1590 for( node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1592 wxPoint
*p
= node
->GetData();
1599 wxPointList
::compatibility_iterator node
;
1600 // copy whole ellipse, wxPoints will be deleted outside
1601 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1603 wxPoint
*p
= node
->GetData();
1604 points
->Append( p
);
1606 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1608 wxPoint
*p
= node
->GetData();
1609 points
->Append( p
);
1611 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1613 wxPoint
*p
= node
->GetData();
1614 points
->Append( p
);
1616 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1618 wxPoint
*p
= node
->GetData();
1619 points
->Append( p
);
1622 } // CalculateEllipticPoints
1624 #endif // __WXWINCE__