1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/graphics.cpp
3 // Purpose: wxGCDC class
4 // Author: Stefan Csomor
8 // Copyright: (c) 2006 Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
21 #include "wx/msw/wrapcdlg.h"
23 #include "wx/window.h"
26 #include "wx/dialog.h"
28 #include "wx/bitmap.h"
29 #include "wx/dcmemory.h"
32 #include "wx/dcprint.h"
33 #include "wx/module.h"
36 #include "wx/graphics.h"
38 #if wxUSE_GRAPHICS_CONTEXT
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 const double RAD2DEG
= 180.0 / M_PI
;
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
54 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
55 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
57 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
58 static inline double RadToDeg(double deg
) { return (deg
* 180.0) / M_PI
; }
60 //-----------------------------------------------------------------------------
61 // device context implementation
63 // more and more of the dc functionality should be implemented by calling
64 // the appropricate wxGDIPlusContext, but we will have to do that step by step
65 // also coordinate conversions should be moved to native matrix ops
66 //-----------------------------------------------------------------------------
68 // we always stock two context states, one at entry, to be able to preserve the
69 // state we were called with, the other one after changing to HI Graphics orientation
70 // (this one is used for getting back clippings etc)
72 //-----------------------------------------------------------------------------
73 // wxGraphicsPath implementation
74 //-----------------------------------------------------------------------------
76 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
78 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
82 // TODO remove this dependency (gdiplus needs the macros)
85 #define max(a,b) (((a) > (b)) ? (a) : (b))
89 #define min(a,b) (((a) < (b)) ? (a) : (b))
93 using namespace Gdiplus
;
95 class WXDLLIMPEXP_CORE wxGDIPlusPath
: public wxGraphicsPath
99 wxGDIPlusPath(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
= NULL
);
102 virtual wxGraphicsPath
*Clone() const;
105 // These are the path primitives from which everything else can be constructed
108 // begins a new subpath at (x,y)
109 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
111 // adds a straight line from the current point to (x,y)
112 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
114 // adds a cubic Bezier curve from the current point, using two control points and an end point
115 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
118 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
119 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
121 // gets the last point of the current path, (0,0) if not yet set
122 virtual void GetCurrentPoint( wxDouble
& x
, wxDouble
&y
) ;
125 virtual void AddPath( const wxGraphicsPath
* path
);
127 // closes the current sub-path
128 virtual void CloseSubpath();
131 // These are convenience functions which - if not available natively will be assembled
132 // using the primitives from above
135 // appends a rectangle as a new closed subpath
136 virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
) ;
139 // appends an ellipsis as a new closed subpath fitting the passed rectangle
140 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
142 // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
143 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
146 // returns the native path
147 virtual void * GetNativePath() const { return m_path
; }
149 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
150 virtual void UnGetNativePath(void * WXUNUSED(path
)) {}
152 // transforms each point of this path by the matrix
153 virtual void Transform( wxGraphicsMatrix
* matrix
) ;
155 // gets the bounding box enclosing all points (possibly including control points)
156 virtual void GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) ;
158 virtual bool Contains( wxDouble x
, wxDouble y
, int fillStyle
= wxWINDING_RULE
) ;
161 GraphicsPath
* m_path
;
162 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusPath
)
165 class WXDLLIMPEXP_CORE wxGDIPlusMatrix
: public wxGraphicsMatrix
170 wxGDIPlusMatrix(wxGraphicsRenderer
* renderer
, Matrix
* matrix
= NULL
) ;
171 virtual ~wxGDIPlusMatrix() ;
173 virtual wxGraphicsMatrix
*Clone() const ;
175 // concatenates the matrix
176 virtual void Concat( const wxGraphicsMatrix
*t
);
178 // copies the passed in matrix
179 virtual void Copy( const wxGraphicsMatrix
*t
);
181 // sets the matrix to the respective values
182 virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
183 wxDouble tx
=0.0, wxDouble ty
=0.0);
185 // makes this the inverse matrix
186 virtual void Invert();
188 // returns true if the elements of the transformation matrix are equal ?
189 virtual bool IsEqual( const wxGraphicsMatrix
* t
) const ;
191 // return true if this is the identity matrix
192 virtual bool IsIdentity();
198 // add the translation to this matrix
199 virtual void Translate( wxDouble dx
, wxDouble dy
);
201 // add the scale to this matrix
202 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
204 // add the rotation to this matrix (radians)
205 virtual void Rotate( wxDouble angle
);
208 // apply the transforms
211 // applies that matrix to the point
212 virtual void TransformPoint( wxDouble
*x
, wxDouble
*y
);
214 // applies the matrix except for translations
215 virtual void TransformDistance( wxDouble
*dx
, wxDouble
*dy
);
217 // returns the native representation
218 virtual void * GetNativeMatrix() const;
222 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusMatrix
)
225 class WXDLLIMPEXP_CORE wxGDIPlusPen
: public wxGraphicsPen
229 wxGDIPlusPen( wxGraphicsRenderer
* renderer
, const wxPen
&pen
);
234 virtual void Apply( wxGraphicsContext
* context
);
235 virtual wxDouble
GetWidth() { return m_width
; }
236 virtual Pen
* GetGDIPlusPen() { return m_pen
; }
245 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusPen
)
248 class WXDLLIMPEXP_CORE wxGDIPlusBrush
: public wxGraphicsBrush
252 wxGDIPlusBrush( wxGraphicsRenderer
* renderer
);
253 wxGDIPlusBrush( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
);
256 virtual void Apply( wxGraphicsContext
* context
);
257 void CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
258 const wxColour
&c1
, const wxColour
&c2
);
259 void CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
260 const wxColour
&oColor
, const wxColour
&cColor
);
261 virtual Brush
* GetGDIPlusBrush() { return m_brush
; }
269 GraphicsPath
* m_brushPath
;
271 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusBrush
)
274 class wxGDIPlusFont
: public wxGraphicsFont
278 wxGDIPlusFont( wxGraphicsRenderer
* renderer
, const wxFont
&font
, const wxColour
& col
);
281 virtual void Apply( wxGraphicsContext
* context
);
282 virtual Brush
* GetGDIPlusBrush() { return m_textBrush
; }
283 virtual Font
* GetGDIPlusFont() { return m_font
; }
288 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusFont
)
291 class WXDLLIMPEXP_CORE wxGDIPlusContext
: public wxGraphicsContext
294 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
);
295 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
);
296 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
);
299 virtual ~wxGDIPlusContext();
301 virtual void Clip( const wxRegion
®ion
);
302 // clips drawings to the rect
303 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
305 // resets the clipping to original extent
306 virtual void ResetClip();
308 virtual void * GetNativeContext();
310 virtual void StrokePath( const wxGraphicsPath
*p
);
311 virtual void FillPath( const wxGraphicsPath
*p
, int fillStyle
= wxWINDING_RULE
);
313 virtual void Translate( wxDouble dx
, wxDouble dy
);
314 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
315 virtual void Rotate( wxDouble angle
);
317 // concatenates this transform with the current transform of this context
318 virtual void ConcatTransform( const wxGraphicsMatrix
* matrix
);
320 // sets the transform of this context
321 virtual void SetTransform( const wxGraphicsMatrix
* matrix
);
323 // gets the matrix of this context
324 virtual void GetTransform( wxGraphicsMatrix
* matrix
);
326 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
327 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
328 virtual void PushState();
329 virtual void PopState();
331 virtual void DrawText( const wxString
&str
, wxDouble x
, wxDouble y
);
332 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
333 wxDouble
*descent
, wxDouble
*externalLeading
) const;
334 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
341 vector
<GraphicsState
> m_stateStack
;
342 GraphicsState m_state1
;
343 GraphicsState m_state2
;
345 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext
)
348 //-----------------------------------------------------------------------------
349 // wxGDIPlusPen implementation
350 //-----------------------------------------------------------------------------
352 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusPen
,wxGraphicsPen
)
354 wxGDIPlusPen::wxGDIPlusPen() : wxGraphicsPen(NULL
)
356 wxLogDebug(wxT("Illegal Constructor called"));
359 wxGDIPlusPen::~wxGDIPlusPen()
366 void wxGDIPlusPen::Init()
373 wxGDIPlusPen::wxGDIPlusPen( wxGraphicsRenderer
* renderer
, const wxPen
&pen
)
374 : wxGraphicsPen(renderer
)
377 m_width
= pen
.GetWidth();
381 m_pen
= new Pen(Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
382 pen
.GetColour().Green() , pen
.GetColour().Blue() ), m_width
);
385 switch ( pen
.GetCap() )
391 case wxCAP_PROJECTING
:
396 cap
= LineCapFlat
; // TODO verify
403 m_pen
->SetLineCap(cap
,cap
, DashCapFlat
);
406 switch ( pen
.GetJoin() )
409 join
= LineJoinBevel
;
413 join
= LineJoinMiter
;
417 join
= LineJoinRound
;
421 join
= LineJoinMiter
;
425 m_pen
->SetLineJoin(join
);
427 m_pen
->SetDashStyle(DashStyleSolid
);
429 DashStyle dashStyle
= DashStyleSolid
;
430 switch ( pen
.GetStyle() )
436 dashStyle
= DashStyleDot
;
440 dashStyle
= DashStyleDash
; // TODO verify
444 dashStyle
= DashStyleDash
;
448 dashStyle
= DashStyleDashDot
;
452 dashStyle
= DashStyleCustom
;
454 int count
= pen
.GetDashes( &dashes
);
455 if ((dashes
!= NULL
) && (count
> 0))
457 REAL
*userLengths
= new REAL
[count
];
458 for ( int i
= 0; i
< count
; ++i
)
460 userLengths
[i
] = dashes
[i
];
462 m_pen
->SetDashPattern( userLengths
, count
);
463 delete[] userLengths
;
469 wxBitmap
* bmp
= pen
.GetStipple();
470 if ( bmp
&& bmp
->Ok() )
472 m_penImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
473 m_penBrush
= new TextureBrush(m_penImage
);
474 m_pen
->SetBrush( m_penBrush
);
480 if ( pen
.GetStyle() >= wxFIRST_HATCH
&& pen
.GetStyle() <= wxLAST_HATCH
)
482 HatchStyle style
= HatchStyleHorizontal
;
483 switch( pen
.GetStyle() )
485 case wxBDIAGONAL_HATCH
:
486 style
= HatchStyleBackwardDiagonal
;
488 case wxCROSSDIAG_HATCH
:
489 style
= HatchStyleDiagonalCross
;
491 case wxFDIAGONAL_HATCH
:
492 style
= HatchStyleForwardDiagonal
;
495 style
= HatchStyleCross
;
497 case wxHORIZONTAL_HATCH
:
498 style
= HatchStyleHorizontal
;
500 case wxVERTICAL_HATCH
:
501 style
= HatchStyleVertical
;
505 m_penBrush
= new HatchBrush(style
,Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
506 pen
.GetColour().Green() , pen
.GetColour().Blue() ), Color::Transparent
);
507 m_pen
->SetBrush( m_penBrush
);
511 if ( dashStyle
!= DashStyleSolid
)
512 m_pen
->SetDashStyle(dashStyle
);
515 void wxGDIPlusPen::Apply( wxGraphicsContext
* WXUNUSED(context
) )
517 // nothing to do here
521 //-----------------------------------------------------------------------------
522 // wxGDIPlusBrush implementation
523 //-----------------------------------------------------------------------------
525 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusBrush
,wxGraphicsBrush
)
527 wxGDIPlusBrush::wxGDIPlusBrush( wxGraphicsRenderer
* renderer
)
528 : wxGraphicsBrush(renderer
)
533 wxGDIPlusBrush::wxGDIPlusBrush( )
534 : wxGraphicsBrush(NULL
)
536 wxLogDebug(wxT("Illegal Constructor called"));
540 wxGDIPlusBrush::wxGDIPlusBrush( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
)
541 : wxGraphicsBrush(renderer
)
544 if ( brush
.GetStyle() == wxSOLID
)
546 m_brush
= new SolidBrush( Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
547 brush
.GetColour().Green() , brush
.GetColour().Blue() ) );
549 else if ( brush
.IsHatch() )
551 HatchStyle style
= HatchStyleHorizontal
;
552 switch( brush
.GetStyle() )
554 case wxBDIAGONAL_HATCH
:
555 style
= HatchStyleBackwardDiagonal
;
557 case wxCROSSDIAG_HATCH
:
558 style
= HatchStyleDiagonalCross
;
560 case wxFDIAGONAL_HATCH
:
561 style
= HatchStyleForwardDiagonal
;
564 style
= HatchStyleCross
;
566 case wxHORIZONTAL_HATCH
:
567 style
= HatchStyleHorizontal
;
569 case wxVERTICAL_HATCH
:
570 style
= HatchStyleVertical
;
574 m_brush
= new HatchBrush(style
,Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
575 brush
.GetColour().Green() , brush
.GetColour().Blue() ), Color::Transparent
);
579 wxBitmap
* bmp
= brush
.GetStipple();
580 if ( bmp
&& bmp
->Ok() )
582 wxDELETE( m_brushImage
);
583 m_brushImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
584 m_brush
= new TextureBrush(m_brushImage
);
589 wxGDIPlusBrush::~wxGDIPlusBrush()
596 void wxGDIPlusBrush::Init()
603 void wxGDIPlusBrush::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
)
605 m_brush
= new LinearGradientBrush( PointF( x1
,y1
) , PointF( x2
,y2
),
606 Color( c1
.Alpha(), c1
.Red(),c1
.Green() , c1
.Blue() ),
607 Color( c2
.Alpha(), c2
.Red(),c2
.Green() , c2
.Blue() ));
610 void wxGDIPlusBrush::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
611 const wxColour
&oColor
, const wxColour
&cColor
)
613 // Create a path that consists of a single circle.
614 m_brushPath
= new GraphicsPath();
615 m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
), (REAL
)(2*radius
), (REAL
)(2*radius
));
617 PathGradientBrush
*b
= new PathGradientBrush(m_brushPath
);
619 b
->SetCenterPoint( PointF(xo
,yo
));
620 b
->SetCenterColor(Color( oColor
.Alpha(), oColor
.Red(),oColor
.Green() , oColor
.Blue() ));
622 Color colors
[] = {Color( cColor
.Alpha(), cColor
.Red(),cColor
.Green() , cColor
.Blue() )};
624 b
->SetSurroundColors(colors
, &count
);
627 void wxGDIPlusBrush::Apply( wxGraphicsContext
* WXUNUSED(context
) )
629 // nothing to do here
632 //-----------------------------------------------------------------------------
633 // wxGDIPlusFont implementation
634 //-----------------------------------------------------------------------------
636 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusFont
,wxGraphicsFont
)
638 wxGDIPlusFont::wxGDIPlusFont() : wxGraphicsFont( NULL
)
640 wxLogDebug(wxT("Illegal Constructor called"));
643 wxGDIPlusFont::wxGDIPlusFont( wxGraphicsRenderer
* renderer
, const wxFont
&font
,
644 const wxColour
& col
) : wxGraphicsFont( renderer
)
649 wxWCharBuffer s
= font
.GetFaceName().wc_str( *wxConvUI
);
650 int size
= font
.GetPointSize();
651 int style
= FontStyleRegular
;
652 if ( font
.GetStyle() == wxFONTSTYLE_ITALIC
)
653 style
|= FontStyleItalic
;
654 if ( font
.GetUnderlined() )
655 style
|= FontStyleUnderline
;
656 if ( font
.GetWeight() == wxFONTWEIGHT_BOLD
)
657 style
|= FontStyleBold
;
658 m_font
= new Font( s
, size
, style
);
659 m_textBrush
= new SolidBrush( Color( col
.Alpha() , col
.Red() ,
660 col
.Green() , col
.Blue() ));
663 wxGDIPlusFont::~wxGDIPlusFont()
669 void wxGDIPlusFont::Apply( wxGraphicsContext
* WXUNUSED(context
) )
671 // nothing to do here
674 //-----------------------------------------------------------------------------
675 // wxGDIPlusPath implementation
676 //-----------------------------------------------------------------------------
678 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusPath
,wxGraphicsPath
)
680 wxGDIPlusPath::wxGDIPlusPath(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
) : wxGraphicsPath(renderer
)
685 m_path
= new GraphicsPath();
688 wxGDIPlusPath::wxGDIPlusPath() : wxGraphicsPath(NULL
)
690 wxLogDebug(wxT("Illegal Constructor called"));
694 wxGDIPlusPath::~wxGDIPlusPath()
699 wxGraphicsPath
* wxGDIPlusPath::Clone() const
701 return new wxGDIPlusPath( GetRenderer() , m_path
->Clone());
710 void wxGDIPlusPath::MoveToPoint( wxDouble x
, wxDouble y
)
712 m_path
->StartFigure();
713 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
716 void wxGDIPlusPath::AddLineToPoint( wxDouble x
, wxDouble y
)
718 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
721 void wxGDIPlusPath::CloseSubpath()
723 m_path
->CloseFigure();
726 void wxGDIPlusPath::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
732 m_path
->GetLastPoint(&start
);
733 m_path
->AddBezier(start
,c1
,c2
,end
);
736 // gets the last point of the current path, (0,0) if not yet set
737 void wxGDIPlusPath::GetCurrentPoint( wxDouble
& x
, wxDouble
&y
)
740 m_path
->GetLastPoint(&start
);
745 void wxGDIPlusPath::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
747 double sweepAngle
= endAngle
- startAngle
;
748 if( abs(sweepAngle
) >= 2*M_PI
)
750 sweepAngle
= 2 * M_PI
;
757 sweepAngle
+= 2 * M_PI
;
762 sweepAngle
-= 2 * M_PI
;
766 m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));
769 void wxGDIPlusPath::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
771 m_path
->AddRectangle(RectF(x
,y
,w
,h
));
774 void wxGDIPlusPath::AddPath( const wxGraphicsPath
* path
)
776 m_path
->AddPath( (GraphicsPath
*) path
->GetNativePath(), FALSE
);
780 // transforms each point of this path by the matrix
781 void wxGDIPlusPath::Transform( wxGraphicsMatrix
* matrix
)
783 m_path
->Transform( (Matrix
*) matrix
->GetNativeMatrix() );
786 // gets the bounding box enclosing all points (possibly including control points)
787 void wxGDIPlusPath::GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
)
790 m_path
->GetBounds( &bounds
, NULL
, NULL
) ;
797 bool wxGDIPlusPath::Contains( wxDouble x
, wxDouble y
, int fillStyle
)
799 m_path
->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
800 return m_path
->IsVisible( (FLOAT
) x
,(FLOAT
) y
) == TRUE
;
803 //-----------------------------------------------------------------------------
804 // wxGDIPlusMatrix implementation
805 //-----------------------------------------------------------------------------
807 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusMatrix
,wxGraphicsMatrix
)
809 wxGDIPlusMatrix::wxGDIPlusMatrix() : wxGraphicsMatrix(NULL
)
811 wxLogDebug(wxT("Illegal Constructor called"));
814 wxGDIPlusMatrix::wxGDIPlusMatrix(wxGraphicsRenderer
* renderer
, Matrix
* matrix
)
815 : wxGraphicsMatrix(renderer
)
820 m_matrix
= new Matrix();
823 wxGDIPlusMatrix::~wxGDIPlusMatrix()
828 wxGraphicsMatrix
*wxGDIPlusMatrix::Clone() const
830 return new wxGDIPlusMatrix( GetRenderer(), m_matrix
->Clone());
833 // concatenates the matrix
834 void wxGDIPlusMatrix::Concat( const wxGraphicsMatrix
*t
)
836 m_matrix
->Multiply( (Matrix
*) t
->GetNativeMatrix());
839 // copies the passed in matrix
840 void wxGDIPlusMatrix::Copy( const wxGraphicsMatrix
*t
)
843 m_matrix
= ((Matrix
*) t
->GetNativeMatrix())->Clone();
846 // sets the matrix to the respective values
847 void wxGDIPlusMatrix::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
848 wxDouble tx
, wxDouble ty
)
850 m_matrix
->SetElements(a
,b
,c
,d
,tx
,ty
);
853 // makes this the inverse matrix
854 void wxGDIPlusMatrix::Invert()
859 // returns true if the elements of the transformation matrix are equal ?
860 bool wxGDIPlusMatrix::IsEqual( const wxGraphicsMatrix
* t
) const
862 return m_matrix
->Equals((Matrix
*) t
->GetNativeMatrix())== TRUE
;
865 // return true if this is the identity matrix
866 bool wxGDIPlusMatrix::IsIdentity()
868 return m_matrix
->IsIdentity() == TRUE
;
875 // add the translation to this matrix
876 void wxGDIPlusMatrix::Translate( wxDouble dx
, wxDouble dy
)
878 m_matrix
->Translate(dx
,dy
);
881 // add the scale to this matrix
882 void wxGDIPlusMatrix::Scale( wxDouble xScale
, wxDouble yScale
)
884 m_matrix
->Scale(xScale
,yScale
);
887 // add the rotation to this matrix (radians)
888 void wxGDIPlusMatrix::Rotate( wxDouble angle
)
890 m_matrix
->Rotate( angle
);
894 // apply the transforms
897 // applies that matrix to the point
898 void wxGDIPlusMatrix::TransformPoint( wxDouble
*x
, wxDouble
*y
)
901 m_matrix
->TransformPoints(&pt
);
906 // applies the matrix except for translations
907 void wxGDIPlusMatrix::TransformDistance( wxDouble
*dx
, wxDouble
*dy
)
910 m_matrix
->TransformVectors(&pt
);
915 // returns the native representation
916 void * wxGDIPlusMatrix::GetNativeMatrix() const
921 //-----------------------------------------------------------------------------
922 // wxGDIPlusContext implementation
923 //-----------------------------------------------------------------------------
925 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext
,wxGraphicsContext
)
927 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
)
928 : wxGraphicsContext(renderer
)
931 m_context
= new Graphics( hdc
);
935 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
)
936 : wxGraphicsContext(renderer
)
939 m_context
= new Graphics( hwnd
);
943 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
)
944 : wxGraphicsContext(renderer
)
951 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL
)
956 void wxGDIPlusContext::Init()
963 void wxGDIPlusContext::SetDefaults()
965 m_context
->SetSmoothingMode(SmoothingModeHighQuality
);
966 m_state1
= m_context
->Save();
967 m_state2
= m_context
->Save();
970 wxGDIPlusContext::~wxGDIPlusContext()
978 m_context
->Restore( m_state2
);
979 m_context
->Restore( m_state1
);
985 void wxGDIPlusContext::Clip( const wxRegion
®ion
)
987 m_context
->SetClip((HRGN
)region
.GetHRGN(),CombineModeIntersect
);
990 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
992 m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
);
995 void wxGDIPlusContext::ResetClip()
997 m_context
->ResetClip();
1000 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
*path
)
1004 m_context
->DrawPath( ((wxGDIPlusPen
*)m_pen
)->GetGDIPlusPen() , (GraphicsPath
*) path
->GetNativePath() );
1008 void wxGDIPlusContext::FillPath( const wxGraphicsPath
*path
, int fillStyle
)
1012 ((GraphicsPath
*) path
->GetNativePath())->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
1013 m_context
->FillPath( ((wxGDIPlusBrush
*)m_brush
)->GetGDIPlusBrush() ,
1014 (GraphicsPath
*) path
->GetNativePath());
1018 void wxGDIPlusContext::Rotate( wxDouble angle
)
1020 m_context
->RotateTransform( RadToDeg(angle
) );
1023 void wxGDIPlusContext::Translate( wxDouble dx
, wxDouble dy
)
1025 m_context
->TranslateTransform( dx
, dy
);
1028 void wxGDIPlusContext::Scale( wxDouble xScale
, wxDouble yScale
)
1030 m_context
->ScaleTransform(xScale
,yScale
);
1033 void wxGDIPlusContext::PushState()
1035 GraphicsState state
= m_context
->Save();
1036 m_stateStack
.push_back(state
);
1039 void wxGDIPlusContext::PopState()
1041 GraphicsState state
= m_stateStack
.back();
1042 m_stateStack
.pop_back();
1043 m_context
->Restore(state
);
1046 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
1047 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
1048 // bytes as parameter
1050 void wxGDIPlusContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1052 Bitmap
* image
= NULL
;
1053 Bitmap
* helper
= NULL
;
1054 if ( bmp
.GetMask() )
1056 Bitmap
interim((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()) ;
1058 size_t width
= interim
.GetWidth();
1059 size_t height
= interim
.GetHeight();
1060 Rect
bounds(0,0,width
,height
);
1062 image
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ;
1064 Bitmap
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
);
1065 wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
);
1067 BitmapData dataMask
;
1068 interimMask
.LockBits(&bounds
,ImageLockModeRead
,
1069 interimMask
.GetPixelFormat(),&dataMask
);
1072 BitmapData imageData
;
1073 image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
);
1075 BYTE maskPattern
= 0 ;
1079 for ( size_t y
= 0 ; y
< height
; ++y
)
1082 for( size_t x
= 0 ; x
< width
; ++x
)
1087 maskByte
= *((BYTE
*)dataMask
.Scan0
+ dataMask
.Stride
*y
+ maskIndex
);
1091 maskPattern
= maskPattern
>> 1;
1093 ARGB
*dest
= (ARGB
*)((BYTE
*)imageData
.Scan0
+ imageData
.Stride
*y
+ x
*4);
1094 if ( (maskByte
& maskPattern
) == 0 )
1099 interim
.GetPixel(x
,y
,&c
) ;
1100 *dest
= (c
.GetValue() | Color::AlphaMask
);
1105 image
->UnlockBits(&imageData
);
1107 interimMask
.UnlockBits(&dataMask
);
1108 interim
.UnlockBits(&dataMask
);
1112 image
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE());
1113 if ( GetPixelFormatSize(image
->GetPixelFormat()) == 32 )
1115 size_t width
= image
->GetWidth();
1116 size_t height
= image
->GetHeight();
1117 Rect
bounds(0,0,width
,height
);
1122 helper
->LockBits(&bounds
, ImageLockModeRead
,
1123 helper
->GetPixelFormat(),&data
);
1125 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1126 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1128 helper
->UnlockBits(&data
);
1132 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1137 void wxGDIPlusContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1139 HICON hIcon
= (HICON
)icon
.GetHICON();
1141 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1142 if (!GetIconInfo(hIcon
,&iconInfo
))
1145 BITMAP iconBmpData
;
1146 GetObject(iconInfo
.hbmColor
,sizeof(BITMAP
),&iconBmpData
);
1147 Bitmap
interim(iconInfo
.hbmColor
,NULL
);
1149 Bitmap
* image
= NULL
;
1151 if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 )
1153 image
= Bitmap::FromHICON(hIcon
);
1157 size_t width
= interim
.GetWidth();
1158 size_t height
= interim
.GetHeight();
1159 Rect
bounds(0,0,width
,height
);
1162 interim
.LockBits(&bounds
, ImageLockModeRead
,
1163 interim
.GetPixelFormat(),&data
);
1164 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1165 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1166 interim
.UnlockBits(&data
);
1169 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1172 DeleteObject(iconInfo
.hbmColor
);
1173 DeleteObject(iconInfo
.hbmMask
);
1177 void wxGDIPlusContext::DrawText( const wxString
&str
, wxDouble x
, wxDouble y
)
1182 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1183 m_context
->DrawString( s
, -1 , ((wxGDIPlusFont
*)m_font
)->GetGDIPlusFont() ,
1184 PointF( x
, y
) , ((wxGDIPlusFont
*)m_font
)->GetGDIPlusBrush() );
1185 // TODO m_backgroundMode == wxSOLID
1188 void wxGDIPlusContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
1189 wxDouble
*descent
, wxDouble
*externalLeading
) const
1191 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1192 FontFamily ffamily
;
1193 Font
* f
= ((wxGDIPlusFont
*)m_font
)->GetGDIPlusFont();
1195 f
->GetFamily(&ffamily
) ;
1197 REAL factorY
= m_context
->GetDpiY() / 72.0 ;
1199 REAL rDescent
= ffamily
.GetCellDescent(FontStyleRegular
) *
1200 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1201 REAL rAscent
= ffamily
.GetCellAscent(FontStyleRegular
) *
1202 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1203 REAL rHeight
= ffamily
.GetLineSpacing(FontStyleRegular
) *
1204 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1207 *height
= rHeight
* factorY
+ 0.5 ;
1209 *descent
= rDescent
* factorY
+ 0.5 ;
1210 if ( externalLeading
)
1211 *externalLeading
= (rHeight
- rAscent
- rDescent
) * factorY
+ 0.5 ;
1212 // measuring empty strings is not guaranteed, so do it by hand
1220 // MeasureString does return a rectangle that is way too large, so it is
1222 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1223 StringFormat strFormat
;
1224 CharacterRange
strRange(0,wcslen(s
));
1225 strFormat
.SetMeasurableCharacterRanges(1,&strRange
);
1227 m_context
->MeasureCharacterRanges(s
, -1 , f
,layoutRect
, &strFormat
,1,®ion
) ;
1229 region
.GetBounds(&bbox
,m_context
);
1231 *width
= bbox
.GetRight()-bbox
.GetLeft()+0.5;
1235 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
1238 widths
.Add(0, text
.length());
1243 Font
* f
= ((wxGDIPlusFont
*)m_font
)->GetGDIPlusFont();
1244 wxWCharBuffer ws
= text
.wc_str( *wxConvUI
);
1245 size_t len
= wcslen( ws
) ;
1246 wxASSERT_MSG(text
.length() == len
, wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1248 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1249 StringFormat strFormat
;
1251 CharacterRange
* ranges
= new CharacterRange
[len
] ;
1252 Region
* regions
= new Region
[len
];
1253 for( size_t i
= 0 ; i
< len
; ++i
)
1255 ranges
[i
].First
= i
;
1256 ranges
[i
].Length
= 1 ;
1258 strFormat
.SetMeasurableCharacterRanges(len
,ranges
);
1259 m_context
->MeasureCharacterRanges(ws
, -1 , f
,layoutRect
, &strFormat
,1,regions
) ;
1262 for ( size_t i
= 0 ; i
< len
; ++i
)
1264 regions
[i
].GetBounds(&bbox
,m_context
);
1265 widths
[i
] = bbox
.GetRight()-bbox
.GetLeft();
1269 void* wxGDIPlusContext::GetNativeContext()
1274 // concatenates this transform with the current transform of this context
1275 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix
* matrix
)
1277 m_context
->MultiplyTransform((Matrix
*) matrix
->GetNativeMatrix());
1280 // sets the transform of this context
1281 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix
* matrix
)
1283 m_context
->SetTransform((Matrix
*) matrix
->GetNativeMatrix());
1286 // gets the matrix of this context
1287 void wxGDIPlusContext::GetTransform( wxGraphicsMatrix
* matrix
)
1289 m_context
->GetTransform((Matrix
*) matrix
->GetNativeMatrix());
1291 //-----------------------------------------------------------------------------
1292 // wxGDIPlusRenderer declaration
1293 //-----------------------------------------------------------------------------
1295 class WXDLLIMPEXP_CORE wxGDIPlusRenderer
: public wxGraphicsRenderer
1304 virtual ~wxGDIPlusRenderer()
1314 virtual wxGraphicsContext
* CreateContext( const wxWindowDC
& dc
);
1316 virtual wxGraphicsContext
* CreateContextFromNativeContext( void * context
);
1318 virtual wxGraphicsContext
* CreateContextFromNativeWindow( void * window
);
1320 virtual wxGraphicsContext
* CreateContext( wxWindow
* window
);
1324 virtual wxGraphicsPath
* CreatePath();
1328 virtual wxGraphicsMatrix
* CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
1329 wxDouble tx
=0.0, wxDouble ty
=0.0);
1332 virtual wxGraphicsPen
* CreatePen(const wxPen
& pen
) ;
1334 virtual wxGraphicsBrush
* CreateBrush(const wxBrush
& brush
) ;
1336 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1337 virtual wxGraphicsBrush
* CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1338 const wxColour
&c1
, const wxColour
&c2
) ;
1340 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1341 // with radius r and color cColor
1342 virtual wxGraphicsBrush
* CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1343 const wxColour
&oColor
, const wxColour
&cColor
) ;
1346 virtual wxGraphicsFont
* CreateFont( const wxFont
&font
, const wxColour
&col
= *wxBLACK
) ;
1348 void EnsureIsLoaded();
1356 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer
)
1359 //-----------------------------------------------------------------------------
1360 // wxGDIPlusRenderer implementation
1361 //-----------------------------------------------------------------------------
1363 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer
,wxGraphicsRenderer
)
1365 static wxGDIPlusRenderer gs_GDIPlusRenderer
;
1367 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer()
1369 return &gs_GDIPlusRenderer
;
1372 void wxGDIPlusRenderer::EnsureIsLoaded()
1380 void wxGDIPlusRenderer::Load()
1382 GdiplusStartupInput input
;
1383 GdiplusStartupOutput output
;
1384 GdiplusStartup(&m_gditoken
,&input
,&output
);
1388 void wxGDIPlusRenderer::Unload()
1391 GdiplusShutdown(m_gditoken
);
1394 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxWindowDC
& dc
)
1397 return new wxGDIPlusContext(this,(HDC
) dc
.GetHDC());
1400 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeContext( void * context
)
1403 return new wxGDIPlusContext(this,(Graphics
*) context
);
1407 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window
)
1410 return new wxGDIPlusContext(this,(HWND
) window
);
1413 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( wxWindow
* window
)
1416 return new wxGDIPlusContext(this, (HWND
) window
->GetHWND() );
1421 wxGraphicsPath
* wxGDIPlusRenderer::CreatePath()
1424 return new wxGDIPlusPath( this );
1430 wxGraphicsMatrix
* wxGDIPlusRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
1431 wxDouble tx
, wxDouble ty
)
1435 wxGDIPlusMatrix
* m
= new wxGDIPlusMatrix( this );
1436 m
->Set( a
,b
,c
,d
,tx
,ty
) ;
1440 wxGraphicsPen
* wxGDIPlusRenderer::CreatePen(const wxPen
& pen
)
1443 if ( !pen
.Ok() || pen
.GetStyle() == wxTRANSPARENT
)
1446 return new wxGDIPlusPen( this, pen
);
1449 wxGraphicsBrush
* wxGDIPlusRenderer::CreateBrush(const wxBrush
& brush
)
1452 if ( !brush
.Ok() || brush
.GetStyle() == wxTRANSPARENT
)
1455 return new wxGDIPlusBrush( this, brush
);
1458 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1459 wxGraphicsBrush
* wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1460 const wxColour
&c1
, const wxColour
&c2
)
1463 wxGDIPlusBrush
* brush
= new wxGDIPlusBrush(this);
1464 brush
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, c1
, c2
);
1468 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1469 // with radius r and color cColor
1470 wxGraphicsBrush
* wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1471 const wxColour
&oColor
, const wxColour
&cColor
)
1474 wxGDIPlusBrush
* brush
= new wxGDIPlusBrush(this);
1475 brush
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,oColor
,cColor
);
1480 wxGraphicsFont
* wxGDIPlusRenderer::CreateFont( const wxFont
&font
, const wxColour
&col
)
1484 return new wxGDIPlusFont( this , font
, col
);
1489 #endif // wxUSE_GRAPHICS_CONTEXT