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(wxTRANSPARENT
)
338 , m_mappingMode(wxMM_TEXT
)
341 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
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_scaleX
) * m_signX
+ m_logicalOriginX
;
374 wxCoord
wxDCImpl::DeviceToLogicalY(wxCoord y
) const
376 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ 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_scaleX
) * m_signX
+ m_deviceOriginX
* m_signY
+ m_deviceLocalOriginX
;
394 wxCoord
wxDCImpl::LogicalToDeviceY(wxCoord y
) const
396 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
* m_signY
+ 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, wxTRANSPARENT
));
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::DoDrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
763 wxPointList point_list
;
765 wxPoint
*point1
= new wxPoint
;
766 point1
->x
= x1
; point1
->y
= y1
;
767 point_list
.Append( point1
);
769 wxPoint
*point2
= new wxPoint
;
770 point2
->x
= x2
; point2
->y
= y2
;
771 point_list
.Append( point2
);
773 wxPoint
*point3
= new wxPoint
;
774 point3
->x
= x3
; point3
->y
= y3
;
775 point_list
.Append( point3
);
777 DoDrawSpline(&point_list
);
779 for( wxPointList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
781 wxPoint
*p
= node
->GetData();
786 void wxDCImpl::DoDrawSpline(int n
, wxPoint points
[])
789 for (int i
=0; i
< n
; i
++)
790 list
.Append( &points
[i
] );
795 // ----------------------------------- spline code ----------------------------------------
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
);
807 wxPointList wx_spline_point_list
;
809 #define half(z1, z2) ((z1+z2)/2.0)
812 /* iterative version */
814 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
817 register double xmid
, ymid
;
818 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
821 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
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
);
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
);
839 /* utilities used by spline drawing routines */
841 typedef struct wx_spline_stack_struct
{
842 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
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
;
850 void wx_clear_stack()
852 wx_stack_top
= wx_spline_stack
;
856 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
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
;
870 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
871 double *x3
, double *y3
, double *x4
, double *y4
)
873 if (wx_stack_count
== 0)
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
;
888 static bool wx_spline_add_point(double x
, double y
)
890 wxPoint
*point
= new wxPoint( wxRound(x
), wxRound(y
) );
891 wx_spline_point_list
.Append(point
);
895 static void wx_spline_draw_point_array(wxDC
*dc
)
897 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
898 wxPointList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
901 wxPoint
*point
= node
->GetData();
903 wx_spline_point_list
.Erase(node
);
904 node
= wx_spline_point_list
.GetFirst();
908 void wxDCImpl::DoDrawSpline( const wxPointList
*points
)
910 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
913 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
914 double x1
, y1
, x2
, y2
;
916 wxPointList::compatibility_iterator node
= points
->GetFirst();
921 p
= (wxPoint
*)node
->GetData();
926 node
= node
->GetNext();
931 cx1
= (double)((x1
+ x2
) / 2);
932 cy1
= (double)((y1
+ y2
) / 2);
933 cx2
= (double)((cx1
+ x2
) / 2);
934 cy2
= (double)((cy1
+ y2
) / 2);
936 wx_spline_add_point(x1
, y1
);
938 while ((node
= node
->GetNext())
949 cx4
= (double)(x1
+ x2
) / 2;
950 cy4
= (double)(y1
+ y2
) / 2;
951 cx3
= (double)(x1
+ cx4
) / 2;
952 cy3
= (double)(y1
+ cy4
) / 2;
954 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
958 cx2
= (double)(cx1
+ x2
) / 2;
959 cy2
= (double)(cy1
+ y2
) / 2;
962 wx_spline_add_point( cx1
, cy1
);
963 wx_spline_add_point( x2
, y2
);
965 wx_spline_draw_point_array( m_owner
);
968 #endif // wxUSE_SPLINES
972 void wxDCImpl::DoGradientFillLinear(const wxRect
& rect
,
973 const wxColour
& initialColour
,
974 const wxColour
& destColour
,
975 wxDirection nDirection
)
978 wxPen oldPen
= m_pen
;
979 wxBrush oldBrush
= m_brush
;
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();
989 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
991 wxInt32 x
= rect
.GetWidth();
992 wxInt32 w
= x
; // width of area to shade
993 wxInt32 xDelta
= w
/256; // height of one shade bend
1001 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
1003 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
1006 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
1008 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
1011 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
1013 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
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());
1026 else // nDirection == wxNORTH || nDirection == wxSOUTH
1028 wxInt32 y
= rect
.GetHeight();
1029 wxInt32 w
= y
; // height of area to shade
1030 wxInt32 yDelta
= w
/255; // height of one shade bend
1038 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1040 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1043 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1045 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1048 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1050 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
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
);
1068 void wxDCImpl::DoGradientFillConcentric(const wxRect
& rect
,
1069 const wxColour
& initialColour
,
1070 const wxColour
& destColour
,
1071 const wxPoint
& circleCenter
)
1073 //save the old pen color
1074 wxColour oldPenColour
= m_pen
.GetColour();
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();
1086 wxInt32 cx
= rect
.GetWidth() / 2;
1087 wxInt32 cy
= rect
.GetHeight() / 2;
1095 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1096 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1098 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1100 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1102 //get color difference
1103 wxInt32 nGradient
= ((nRadius
-
1105 pow((double)(x
- cx
- nCircleOffX
), 2) +
1106 pow((double)(y
- cy
- nCircleOffY
), 2)
1107 )) * 100) / nRadius
;
1109 //normalize Gradient
1114 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1115 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1116 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1119 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1120 DoDrawPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop());
1123 //return old pen color
1124 m_pen
.SetColour(oldPenColour
);
1127 //-----------------------------------------------------------------------------
1129 //-----------------------------------------------------------------------------
1131 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
1133 void wxDC::DrawLabel(const wxString
& text
,
1134 const wxBitmap
& bitmap
,
1138 wxRect
*rectBounding
)
1140 // find the text position
1141 wxCoord widthText
, heightText
, heightLine
;
1142 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
1144 wxCoord width
, height
;
1147 width
= widthText
+ bitmap
.GetWidth();
1148 height
= bitmap
.GetHeight();
1153 height
= heightText
;
1157 if ( alignment
& wxALIGN_RIGHT
)
1159 x
= rect
.GetRight() - width
;
1161 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
1163 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
1165 else // alignment & wxALIGN_LEFT
1170 if ( alignment
& wxALIGN_BOTTOM
)
1172 y
= rect
.GetBottom() - height
;
1174 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
1176 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
1178 else // alignment & wxALIGN_TOP
1183 // draw the bitmap first
1189 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
1191 wxCoord offset
= bitmap
.GetWidth() + 4;
1195 y
+= (height
- heightText
) / 2;
1198 // we will draw the underscore under the accel char later
1199 wxCoord startUnderscore
= 0,
1203 // split the string into lines and draw each of them separately
1205 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
1207 if ( *pc
== _T('\n') || pc
== text
.end() )
1209 int xRealStart
= x
; // init it here to avoid compielr warnings
1211 if ( !curLine
.empty() )
1213 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1214 // wxALIGN_LEFT is 0
1215 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
1218 GetTextExtent(curLine
, &widthLine
, NULL
);
1220 if ( alignment
& wxALIGN_RIGHT
)
1222 xRealStart
+= width
- widthLine
;
1224 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1226 xRealStart
+= (width
- widthLine
) / 2;
1229 //else: left aligned, nothing to do
1231 DrawText(curLine
, xRealStart
, y
);
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
)
1240 // adjust the horz positions to account for the shift
1241 startUnderscore
+= xRealStart
;
1242 endUnderscore
+= xRealStart
;
1245 if ( pc
== text
.end() )
1250 else // not end of line
1252 if ( pc
- text
.begin() == indexAccel
)
1254 // remeber to draw underscore here
1255 GetTextExtent(curLine
, &startUnderscore
, NULL
);
1257 GetTextExtent(curLine
, &endUnderscore
, NULL
);
1259 yUnderscore
= y
+ heightLine
;
1268 // draw the underscore if found
1269 if ( startUnderscore
!= endUnderscore
)
1271 // it should be of the same colour as text
1272 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
1276 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
1279 // return bounding rect if requested
1282 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
1285 CalcBoundingBox(x0
, y0
);
1286 CalcBoundingBox(x0
+ width0
, y0
+ height
);
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
,
1294 long *externalLeading
,
1295 const wxFont
*theFont
) const
1297 wxCoord x2
, y2
, descent2
, externalLeading2
;
1298 m_pimpl
->DoGetTextExtent(string
, &x2
, &y2
,
1299 &descent2
, &externalLeading2
,
1306 *descent
= descent2
;
1307 if ( externalLeading
)
1308 *externalLeading
= externalLeading2
;
1311 void wxDC::GetLogicalOrigin(long *x
, long *y
) const
1314 m_pimpl
->DoGetLogicalOrigin(&x2
, &y2
);
1321 void wxDC::GetDeviceOrigin(long *x
, long *y
) const
1324 m_pimpl
->DoGetDeviceOrigin(&x2
, &y2
);
1331 void wxDC::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
1333 wxCoord xx
,yy
,ww
,hh
;
1334 m_pimpl
->DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
1341 #endif // WXWIN_COMPATIBILITY_2_8