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"
20 #if wxUSE_GRAPHICS_CONTEXT
23 #include "wx/msw/wrapcdlg.h"
25 #include "wx/window.h"
28 #include "wx/dialog.h"
30 #include "wx/bitmap.h"
31 #include "wx/dcmemory.h"
34 #include "wx/dcprint.h"
35 #include "wx/module.h"
38 #include "wx/graphics.h"
39 #include "wx/msw/wrapgdip.h"
43 WX_DECLARE_STACK(GraphicsState
, GraphicsStates
);
45 //-----------------------------------------------------------------------------
47 //-----------------------------------------------------------------------------
49 const double RAD2DEG
= 180.0 / M_PI
;
51 //-----------------------------------------------------------------------------
53 //-----------------------------------------------------------------------------
55 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
56 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
58 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
59 static inline double RadToDeg(double deg
) { return (deg
* 180.0) / M_PI
; }
61 //-----------------------------------------------------------------------------
62 // device context implementation
64 // more and more of the dc functionality should be implemented by calling
65 // the appropricate wxGDIPlusContext, but we will have to do that step by step
66 // also coordinate conversions should be moved to native matrix ops
67 //-----------------------------------------------------------------------------
69 // we always stock two context states, one at entry, to be able to preserve the
70 // state we were called with, the other one after changing to HI Graphics orientation
71 // (this one is used for getting back clippings etc)
73 //-----------------------------------------------------------------------------
74 // wxGraphicsPath implementation
75 //-----------------------------------------------------------------------------
77 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
79 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
83 class wxGDIPlusPathData
: public wxGraphicsPathData
86 wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
= NULL
);
89 virtual wxGraphicsObjectRefData
*Clone() const;
92 // These are the path primitives from which everything else can be constructed
95 // begins a new subpath at (x,y)
96 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
98 // adds a straight line from the current point to (x,y)
99 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
101 // adds a cubic Bezier curve from the current point, using two control points and an end point
102 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
105 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
106 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
108 // gets the last point of the current path, (0,0) if not yet set
109 virtual void GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const;
112 virtual void AddPath( const wxGraphicsPathData
* path
);
114 // closes the current sub-path
115 virtual void CloseSubpath();
118 // These are convenience functions which - if not available natively will be assembled
119 // using the primitives from above
122 // appends a rectangle as a new closed subpath
123 virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
) ;
126 // appends an ellipsis as a new closed subpath fitting the passed rectangle
127 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
129 // 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)
130 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
133 // returns the native path
134 virtual void * GetNativePath() const { return m_path
; }
136 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
137 virtual void UnGetNativePath(void * WXUNUSED(path
)) const {}
139 // transforms each point of this path by the matrix
140 virtual void Transform( const wxGraphicsMatrixData
* matrix
) ;
142 // gets the bounding box enclosing all points (possibly including control points)
143 virtual void GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const;
145 virtual bool Contains( wxDouble x
, wxDouble y
, int fillStyle
= wxODDEVEN_RULE
) const;
148 GraphicsPath
* m_path
;
151 class wxGDIPlusMatrixData
: public wxGraphicsMatrixData
154 wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
= NULL
) ;
155 virtual ~wxGDIPlusMatrixData() ;
157 virtual wxGraphicsObjectRefData
* Clone() const ;
159 // concatenates the matrix
160 virtual void Concat( const wxGraphicsMatrixData
*t
);
162 // sets the matrix to the respective values
163 virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
164 wxDouble tx
=0.0, wxDouble ty
=0.0);
166 // gets the component valuess of the matrix
167 virtual void Get(wxDouble
* a
=NULL
, wxDouble
* b
=NULL
, wxDouble
* c
=NULL
,
168 wxDouble
* d
=NULL
, wxDouble
* tx
=NULL
, wxDouble
* ty
=NULL
) const;
170 // makes this the inverse matrix
171 virtual void Invert();
173 // returns true if the elements of the transformation matrix are equal ?
174 virtual bool IsEqual( const wxGraphicsMatrixData
* t
) const ;
176 // return true if this is the identity matrix
177 virtual bool IsIdentity() const;
183 // add the translation to this matrix
184 virtual void Translate( wxDouble dx
, wxDouble dy
);
186 // add the scale to this matrix
187 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
189 // add the rotation to this matrix (radians)
190 virtual void Rotate( wxDouble angle
);
193 // apply the transforms
196 // applies that matrix to the point
197 virtual void TransformPoint( wxDouble
*x
, wxDouble
*y
) const;
199 // applies the matrix except for translations
200 virtual void TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const;
202 // returns the native representation
203 virtual void * GetNativeMatrix() const;
208 class wxGDIPlusPenData
: public wxGraphicsObjectRefData
211 wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
);
216 virtual wxDouble
GetWidth() { return m_width
; }
217 virtual Pen
* GetGDIPlusPen() { return m_pen
; }
227 class wxGDIPlusBrushData
: public wxGraphicsObjectRefData
230 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
);
231 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
);
232 ~wxGDIPlusBrushData ();
234 void CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
235 const wxColour
&c1
, const wxColour
&c2
);
236 void CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
237 const wxColour
&oColor
, const wxColour
&cColor
);
238 virtual Brush
* GetGDIPlusBrush() { return m_brush
; }
246 GraphicsPath
* m_brushPath
;
249 class wxGDIPlusFontData
: public wxGraphicsObjectRefData
252 wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
, const wxColour
& col
);
253 ~wxGDIPlusFontData();
255 virtual Brush
* GetGDIPlusBrush() { return m_textBrush
; }
256 virtual Font
* GetGDIPlusFont() { return m_font
; }
262 class wxGDIPlusContext
: public wxGraphicsContext
265 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
);
266 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
);
267 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
);
270 virtual ~wxGDIPlusContext();
272 virtual void Clip( const wxRegion
®ion
);
273 // clips drawings to the rect
274 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
276 // resets the clipping to original extent
277 virtual void ResetClip();
279 virtual void * GetNativeContext();
281 virtual void StrokePath( const wxGraphicsPath
& p
);
282 virtual void FillPath( const wxGraphicsPath
& p
, int fillStyle
= wxODDEVEN_RULE
);
284 virtual void Translate( wxDouble dx
, wxDouble dy
);
285 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
286 virtual void Rotate( wxDouble angle
);
288 // concatenates this transform with the current transform of this context
289 virtual void ConcatTransform( const wxGraphicsMatrix
& matrix
);
291 // sets the transform of this context
292 virtual void SetTransform( const wxGraphicsMatrix
& matrix
);
294 // gets the matrix of this context
295 virtual wxGraphicsMatrix
GetTransform() const;
297 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
298 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
299 virtual void PushState();
300 virtual void PopState();
302 virtual void DrawText( const wxString
&str
, wxDouble x
, wxDouble y
);
303 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
304 wxDouble
*descent
, wxDouble
*externalLeading
) const;
305 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
306 virtual bool ShouldOffset() const;
313 GraphicsStates m_stateStack
;
314 GraphicsState m_state1
;
315 GraphicsState m_state2
;
317 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext
)
320 //-----------------------------------------------------------------------------
321 // wxGDIPlusPen implementation
322 //-----------------------------------------------------------------------------
324 wxGDIPlusPenData::~wxGDIPlusPenData()
331 void wxGDIPlusPenData::Init()
338 wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
)
339 : wxGraphicsObjectRefData(renderer
)
342 m_width
= pen
.GetWidth();
346 m_pen
= new Pen(Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
347 pen
.GetColour().Green() , pen
.GetColour().Blue() ), m_width
);
350 switch ( pen
.GetCap() )
356 case wxCAP_PROJECTING
:
361 cap
= LineCapFlat
; // TODO verify
368 m_pen
->SetLineCap(cap
,cap
, DashCapFlat
);
371 switch ( pen
.GetJoin() )
374 join
= LineJoinBevel
;
378 join
= LineJoinMiter
;
382 join
= LineJoinRound
;
386 join
= LineJoinMiter
;
390 m_pen
->SetLineJoin(join
);
392 m_pen
->SetDashStyle(DashStyleSolid
);
394 DashStyle dashStyle
= DashStyleSolid
;
395 switch ( pen
.GetStyle() )
401 dashStyle
= DashStyleDot
;
405 dashStyle
= DashStyleDash
; // TODO verify
409 dashStyle
= DashStyleDash
;
413 dashStyle
= DashStyleDashDot
;
417 dashStyle
= DashStyleCustom
;
419 int count
= pen
.GetDashes( &dashes
);
420 if ((dashes
!= NULL
) && (count
> 0))
422 REAL
*userLengths
= new REAL
[count
];
423 for ( int i
= 0; i
< count
; ++i
)
425 userLengths
[i
] = dashes
[i
];
427 m_pen
->SetDashPattern( userLengths
, count
);
428 delete[] userLengths
;
434 wxBitmap
* bmp
= pen
.GetStipple();
435 if ( bmp
&& bmp
->Ok() )
437 m_penImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
438 m_penBrush
= new TextureBrush(m_penImage
);
439 m_pen
->SetBrush( m_penBrush
);
445 if ( pen
.GetStyle() >= wxFIRST_HATCH
&& pen
.GetStyle() <= wxLAST_HATCH
)
447 HatchStyle style
= HatchStyleHorizontal
;
448 switch( pen
.GetStyle() )
450 case wxBDIAGONAL_HATCH
:
451 style
= HatchStyleBackwardDiagonal
;
453 case wxCROSSDIAG_HATCH
:
454 style
= HatchStyleDiagonalCross
;
456 case wxFDIAGONAL_HATCH
:
457 style
= HatchStyleForwardDiagonal
;
460 style
= HatchStyleCross
;
462 case wxHORIZONTAL_HATCH
:
463 style
= HatchStyleHorizontal
;
465 case wxVERTICAL_HATCH
:
466 style
= HatchStyleVertical
;
470 m_penBrush
= new HatchBrush(style
,Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
471 pen
.GetColour().Green() , pen
.GetColour().Blue() ), Color::Transparent
);
472 m_pen
->SetBrush( m_penBrush
);
476 if ( dashStyle
!= DashStyleSolid
)
477 m_pen
->SetDashStyle(dashStyle
);
480 //-----------------------------------------------------------------------------
481 // wxGDIPlusBrush implementation
482 //-----------------------------------------------------------------------------
484 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
)
485 : wxGraphicsObjectRefData(renderer
)
490 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
)
491 : wxGraphicsObjectRefData(renderer
)
494 if ( brush
.GetStyle() == wxSOLID
)
496 m_brush
= new SolidBrush( Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
497 brush
.GetColour().Green() , brush
.GetColour().Blue() ) );
499 else if ( brush
.IsHatch() )
501 HatchStyle style
= HatchStyleHorizontal
;
502 switch( brush
.GetStyle() )
504 case wxBDIAGONAL_HATCH
:
505 style
= HatchStyleBackwardDiagonal
;
507 case wxCROSSDIAG_HATCH
:
508 style
= HatchStyleDiagonalCross
;
510 case wxFDIAGONAL_HATCH
:
511 style
= HatchStyleForwardDiagonal
;
514 style
= HatchStyleCross
;
516 case wxHORIZONTAL_HATCH
:
517 style
= HatchStyleHorizontal
;
519 case wxVERTICAL_HATCH
:
520 style
= HatchStyleVertical
;
524 m_brush
= new HatchBrush(style
,Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
525 brush
.GetColour().Green() , brush
.GetColour().Blue() ), Color::Transparent
);
529 wxBitmap
* bmp
= brush
.GetStipple();
530 if ( bmp
&& bmp
->Ok() )
532 wxDELETE( m_brushImage
);
533 m_brushImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
534 m_brush
= new TextureBrush(m_brushImage
);
539 wxGDIPlusBrushData::~wxGDIPlusBrushData()
546 void wxGDIPlusBrushData::Init()
553 void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
)
555 m_brush
= new LinearGradientBrush( PointF( x1
,y1
) , PointF( x2
,y2
),
556 Color( c1
.Alpha(), c1
.Red(),c1
.Green() , c1
.Blue() ),
557 Color( c2
.Alpha(), c2
.Red(),c2
.Green() , c2
.Blue() ));
560 void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
561 const wxColour
&oColor
, const wxColour
&cColor
)
563 // Create a path that consists of a single circle.
564 m_brushPath
= new GraphicsPath();
565 m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
), (REAL
)(2*radius
), (REAL
)(2*radius
));
567 PathGradientBrush
*b
= new PathGradientBrush(m_brushPath
);
569 b
->SetCenterPoint( PointF(xo
,yo
));
570 b
->SetCenterColor(Color( oColor
.Alpha(), oColor
.Red(),oColor
.Green() , oColor
.Blue() ));
572 Color colors
[] = {Color( cColor
.Alpha(), cColor
.Red(),cColor
.Green() , cColor
.Blue() )};
574 b
->SetSurroundColors(colors
, &count
);
577 //-----------------------------------------------------------------------------
578 // wxGDIPlusFont implementation
579 //-----------------------------------------------------------------------------
581 wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
,
582 const wxColour
& col
) : wxGraphicsObjectRefData( renderer
)
587 wxWCharBuffer s
= font
.GetFaceName().wc_str( *wxConvUI
);
588 int size
= font
.GetPointSize();
589 int style
= FontStyleRegular
;
590 if ( font
.GetStyle() == wxFONTSTYLE_ITALIC
)
591 style
|= FontStyleItalic
;
592 if ( font
.GetUnderlined() )
593 style
|= FontStyleUnderline
;
594 if ( font
.GetWeight() == wxFONTWEIGHT_BOLD
)
595 style
|= FontStyleBold
;
596 m_font
= new Font( s
, size
, style
);
597 m_textBrush
= new SolidBrush( Color( col
.Alpha() , col
.Red() ,
598 col
.Green() , col
.Blue() ));
601 wxGDIPlusFontData::~wxGDIPlusFontData()
607 //-----------------------------------------------------------------------------
608 // wxGDIPlusPath implementation
609 //-----------------------------------------------------------------------------
611 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
) : wxGraphicsPathData(renderer
)
616 m_path
= new GraphicsPath();
619 wxGDIPlusPathData::~wxGDIPlusPathData()
624 wxGraphicsObjectRefData
* wxGDIPlusPathData::Clone() const
626 return new wxGDIPlusPathData( GetRenderer() , m_path
->Clone());
633 void wxGDIPlusPathData::MoveToPoint( wxDouble x
, wxDouble y
)
635 m_path
->StartFigure();
636 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
639 void wxGDIPlusPathData::AddLineToPoint( wxDouble x
, wxDouble y
)
641 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
644 void wxGDIPlusPathData::CloseSubpath()
646 m_path
->CloseFigure();
649 void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
655 m_path
->GetLastPoint(&start
);
656 m_path
->AddBezier(start
,c1
,c2
,end
);
659 // gets the last point of the current path, (0,0) if not yet set
660 void wxGDIPlusPathData::GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const
663 m_path
->GetLastPoint(&start
);
668 void wxGDIPlusPathData::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
670 double sweepAngle
= endAngle
- startAngle
;
671 if( abs(sweepAngle
) >= 2*M_PI
)
673 sweepAngle
= 2 * M_PI
;
680 sweepAngle
+= 2 * M_PI
;
685 sweepAngle
-= 2 * M_PI
;
689 m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));
692 void wxGDIPlusPathData::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
694 m_path
->AddRectangle(RectF(x
,y
,w
,h
));
697 void wxGDIPlusPathData::AddPath( const wxGraphicsPathData
* path
)
699 m_path
->AddPath( (GraphicsPath
*) path
->GetNativePath(), FALSE
);
703 // transforms each point of this path by the matrix
704 void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData
* matrix
)
706 m_path
->Transform( (Matrix
*) matrix
->GetNativeMatrix() );
709 // gets the bounding box enclosing all points (possibly including control points)
710 void wxGDIPlusPathData::GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const
713 m_path
->GetBounds( &bounds
, NULL
, NULL
) ;
720 bool wxGDIPlusPathData::Contains( wxDouble x
, wxDouble y
, int fillStyle
) const
722 m_path
->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
723 return m_path
->IsVisible( (FLOAT
) x
,(FLOAT
) y
) == TRUE
;
726 //-----------------------------------------------------------------------------
727 // wxGDIPlusMatrixData implementation
728 //-----------------------------------------------------------------------------
730 wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
)
731 : wxGraphicsMatrixData(renderer
)
736 m_matrix
= new Matrix();
739 wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
744 wxGraphicsObjectRefData
*wxGDIPlusMatrixData::Clone() const
746 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix
->Clone());
749 // concatenates the matrix
750 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData
*t
)
752 m_matrix
->Multiply( (Matrix
*) t
->GetNativeMatrix());
755 // sets the matrix to the respective values
756 void wxGDIPlusMatrixData::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
757 wxDouble tx
, wxDouble ty
)
759 m_matrix
->SetElements(a
,b
,c
,d
,tx
,ty
);
762 // gets the component valuess of the matrix
763 void wxGDIPlusMatrixData::Get(wxDouble
* a
, wxDouble
* b
, wxDouble
* c
,
764 wxDouble
* d
, wxDouble
* tx
, wxDouble
* ty
) const
767 m_matrix
->GetElements(elements
);
768 if (a
) *a
= elements
[0];
769 if (b
) *b
= elements
[1];
770 if (c
) *c
= elements
[2];
771 if (d
) *d
= elements
[3];
772 if (tx
) *tx
= elements
[4];
773 if (ty
) *ty
= elements
[5];
776 // makes this the inverse matrix
777 void wxGDIPlusMatrixData::Invert()
782 // returns true if the elements of the transformation matrix are equal ?
783 bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData
* t
) const
785 return m_matrix
->Equals((Matrix
*) t
->GetNativeMatrix())== TRUE
;
788 // return true if this is the identity matrix
789 bool wxGDIPlusMatrixData::IsIdentity() const
791 return m_matrix
->IsIdentity() == TRUE
;
798 // add the translation to this matrix
799 void wxGDIPlusMatrixData::Translate( wxDouble dx
, wxDouble dy
)
801 m_matrix
->Translate(dx
,dy
);
804 // add the scale to this matrix
805 void wxGDIPlusMatrixData::Scale( wxDouble xScale
, wxDouble yScale
)
807 m_matrix
->Scale(xScale
,yScale
);
810 // add the rotation to this matrix (radians)
811 void wxGDIPlusMatrixData::Rotate( wxDouble angle
)
813 m_matrix
->Rotate( angle
);
817 // apply the transforms
820 // applies that matrix to the point
821 void wxGDIPlusMatrixData::TransformPoint( wxDouble
*x
, wxDouble
*y
) const
824 m_matrix
->TransformPoints(&pt
);
829 // applies the matrix except for translations
830 void wxGDIPlusMatrixData::TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const
833 m_matrix
->TransformVectors(&pt
);
838 // returns the native representation
839 void * wxGDIPlusMatrixData::GetNativeMatrix() const
844 //-----------------------------------------------------------------------------
845 // wxGDIPlusContext implementation
846 //-----------------------------------------------------------------------------
848 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext
,wxGraphicsContext
)
850 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
)
851 : wxGraphicsContext(renderer
)
854 m_context
= new Graphics( hdc
);
858 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
)
859 : wxGraphicsContext(renderer
)
862 m_context
= new Graphics( hwnd
);
866 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
)
867 : wxGraphicsContext(renderer
)
874 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL
)
879 void wxGDIPlusContext::Init()
886 void wxGDIPlusContext::SetDefaults()
888 m_context
->SetSmoothingMode(SmoothingModeHighQuality
);
889 m_state1
= m_context
->Save();
890 m_state2
= m_context
->Save();
893 wxGDIPlusContext::~wxGDIPlusContext()
897 m_context
->Restore( m_state2
);
898 m_context
->Restore( m_state1
);
904 void wxGDIPlusContext::Clip( const wxRegion
®ion
)
906 Region
rgn((HRGN
)region
.GetHRGN());
907 m_context
->SetClip(&rgn
,CombineModeIntersect
);
910 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
912 m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
);
915 void wxGDIPlusContext::ResetClip()
917 m_context
->ResetClip();
920 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
& path
)
922 if ( !m_pen
.IsNull() )
924 m_context
->DrawPath( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath
*) path
.GetNativePath() );
928 void wxGDIPlusContext::FillPath( const wxGraphicsPath
& path
, int fillStyle
)
930 if ( !m_brush
.IsNull() )
932 ((GraphicsPath
*) path
.GetNativePath())->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
933 m_context
->FillPath( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() ,
934 (GraphicsPath
*) path
.GetNativePath());
938 void wxGDIPlusContext::Rotate( wxDouble angle
)
940 m_context
->RotateTransform( RadToDeg(angle
) );
943 void wxGDIPlusContext::Translate( wxDouble dx
, wxDouble dy
)
945 m_context
->TranslateTransform( dx
, dy
);
948 void wxGDIPlusContext::Scale( wxDouble xScale
, wxDouble yScale
)
950 m_context
->ScaleTransform(xScale
,yScale
);
953 void wxGDIPlusContext::PushState()
955 GraphicsState state
= m_context
->Save();
956 m_stateStack
.push(state
);
959 void wxGDIPlusContext::PopState()
961 GraphicsState state
= m_stateStack
.top();
963 m_context
->Restore(state
);
966 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
967 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
968 // bytes as parameter
970 void wxGDIPlusContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
972 Bitmap
* image
= NULL
;
973 Bitmap
* helper
= NULL
;
976 Bitmap
interim((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()) ;
978 size_t width
= interim
.GetWidth();
979 size_t height
= interim
.GetHeight();
980 Rect
bounds(0,0,width
,height
);
982 image
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ;
984 Bitmap
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
);
985 wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
);
987 BitmapData dataMask
;
988 interimMask
.LockBits(&bounds
,ImageLockModeRead
,
989 interimMask
.GetPixelFormat(),&dataMask
);
992 BitmapData imageData
;
993 image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
);
995 BYTE maskPattern
= 0 ;
999 for ( size_t y
= 0 ; y
< height
; ++y
)
1002 for( size_t x
= 0 ; x
< width
; ++x
)
1007 maskByte
= *((BYTE
*)dataMask
.Scan0
+ dataMask
.Stride
*y
+ maskIndex
);
1011 maskPattern
= maskPattern
>> 1;
1013 ARGB
*dest
= (ARGB
*)((BYTE
*)imageData
.Scan0
+ imageData
.Stride
*y
+ x
*4);
1014 if ( (maskByte
& maskPattern
) == 0 )
1019 interim
.GetPixel(x
,y
,&c
) ;
1020 *dest
= (c
.GetValue() | Color::AlphaMask
);
1025 image
->UnlockBits(&imageData
);
1027 interimMask
.UnlockBits(&dataMask
);
1028 interim
.UnlockBits(&dataMask
);
1032 image
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE());
1033 if ( GetPixelFormatSize(image
->GetPixelFormat()) == 32 )
1035 size_t width
= image
->GetWidth();
1036 size_t height
= image
->GetHeight();
1037 Rect
bounds(0,0,width
,height
);
1042 helper
->LockBits(&bounds
, ImageLockModeRead
,
1043 helper
->GetPixelFormat(),&data
);
1045 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1046 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1048 helper
->UnlockBits(&data
);
1052 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1057 void wxGDIPlusContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1059 HICON hIcon
= (HICON
)icon
.GetHICON();
1061 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1062 if (!GetIconInfo(hIcon
,&iconInfo
))
1065 BITMAP iconBmpData
;
1066 GetObject(iconInfo
.hbmColor
,sizeof(BITMAP
),&iconBmpData
);
1067 Bitmap
interim(iconInfo
.hbmColor
,NULL
);
1069 Bitmap
* image
= NULL
;
1071 if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 )
1073 image
= Bitmap::FromHICON(hIcon
);
1077 size_t width
= interim
.GetWidth();
1078 size_t height
= interim
.GetHeight();
1079 Rect
bounds(0,0,width
,height
);
1082 interim
.LockBits(&bounds
, ImageLockModeRead
,
1083 interim
.GetPixelFormat(),&data
);
1084 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1085 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1086 interim
.UnlockBits(&data
);
1089 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1092 DeleteObject(iconInfo
.hbmColor
);
1093 DeleteObject(iconInfo
.hbmMask
);
1096 void wxGDIPlusContext::DrawText( const wxString
&str
, wxDouble x
, wxDouble y
)
1098 if ( m_font
.IsNull() || str
.IsEmpty())
1101 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1102 m_context
->DrawString( s
, -1 , ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont() ,
1103 PointF( x
, y
) , ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusBrush() );
1104 // TODO m_backgroundMode == wxSOLID
1107 void wxGDIPlusContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
1108 wxDouble
*descent
, wxDouble
*externalLeading
) const
1110 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1111 FontFamily ffamily
;
1112 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1114 f
->GetFamily(&ffamily
) ;
1116 REAL factorY
= m_context
->GetDpiY() / 72.0 ;
1118 REAL rDescent
= ffamily
.GetCellDescent(FontStyleRegular
) *
1119 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1120 REAL rAscent
= ffamily
.GetCellAscent(FontStyleRegular
) *
1121 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1122 REAL rHeight
= ffamily
.GetLineSpacing(FontStyleRegular
) *
1123 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1126 *height
= rHeight
* factorY
+ 0.5 ;
1128 *descent
= rDescent
* factorY
+ 0.5 ;
1129 if ( externalLeading
)
1130 *externalLeading
= (rHeight
- rAscent
- rDescent
) * factorY
+ 0.5 ;
1131 // measuring empty strings is not guaranteed, so do it by hand
1139 // MeasureString does return a rectangle that is way too large, so it is
1141 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1142 StringFormat strFormat
;
1143 CharacterRange
strRange(0,wcslen(s
));
1144 strFormat
.SetMeasurableCharacterRanges(1,&strRange
);
1146 m_context
->MeasureCharacterRanges(s
, -1 , f
,layoutRect
, &strFormat
,1,®ion
) ;
1148 region
.GetBounds(&bbox
,m_context
);
1150 *width
= bbox
.GetRight()-bbox
.GetLeft()+0.5;
1154 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
1157 widths
.Add(0, text
.length());
1162 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1163 wxWCharBuffer ws
= text
.wc_str( *wxConvUI
);
1164 size_t len
= wcslen( ws
) ;
1165 wxASSERT_MSG(text
.length() == len
, wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1167 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1168 StringFormat strFormat
;
1170 CharacterRange
* ranges
= new CharacterRange
[len
] ;
1171 Region
* regions
= new Region
[len
];
1173 for( i
= 0 ; i
< len
; ++i
)
1175 ranges
[i
].First
= i
;
1176 ranges
[i
].Length
= 1 ;
1178 strFormat
.SetMeasurableCharacterRanges(len
,ranges
);
1179 m_context
->MeasureCharacterRanges(ws
, -1 , f
,layoutRect
, &strFormat
,1,regions
) ;
1182 for ( i
= 0 ; i
< len
; ++i
)
1184 regions
[i
].GetBounds(&bbox
,m_context
);
1185 widths
[i
] = bbox
.GetRight()-bbox
.GetLeft();
1189 bool wxGDIPlusContext::ShouldOffset() const
1192 if ( !m_pen
.IsNull() )
1194 penwidth
= (int)((wxGDIPlusPenData
*)m_pen
.GetRefData())->GetWidth();
1195 if ( penwidth
== 0 )
1198 return ( penwidth
% 2 ) == 1;
1201 void* wxGDIPlusContext::GetNativeContext()
1206 // concatenates this transform with the current transform of this context
1207 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix
& matrix
)
1209 m_context
->MultiplyTransform((Matrix
*) matrix
.GetNativeMatrix());
1212 // sets the transform of this context
1213 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix
& matrix
)
1215 m_context
->SetTransform((Matrix
*) matrix
.GetNativeMatrix());
1218 // gets the matrix of this context
1219 wxGraphicsMatrix
wxGDIPlusContext::GetTransform() const
1221 wxGraphicsMatrix matrix
= CreateMatrix();
1222 m_context
->GetTransform((Matrix
*) matrix
.GetNativeMatrix());
1225 //-----------------------------------------------------------------------------
1226 // wxGDIPlusRenderer declaration
1227 //-----------------------------------------------------------------------------
1229 class wxGDIPlusRenderer
: public wxGraphicsRenderer
1238 virtual ~wxGDIPlusRenderer()
1248 virtual wxGraphicsContext
* CreateContext( const wxWindowDC
& dc
);
1250 virtual wxGraphicsContext
* CreateContext( const wxMemoryDC
& dc
);
1252 virtual wxGraphicsContext
* CreateContextFromNativeContext( void * context
);
1254 virtual wxGraphicsContext
* CreateContextFromNativeWindow( void * window
);
1256 virtual wxGraphicsContext
* CreateContext( wxWindow
* window
);
1258 virtual wxGraphicsContext
* CreateMeasuringContext();
1262 virtual wxGraphicsPath
CreatePath();
1266 virtual wxGraphicsMatrix
CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
1267 wxDouble tx
=0.0, wxDouble ty
=0.0);
1270 virtual wxGraphicsPen
CreatePen(const wxPen
& pen
) ;
1272 virtual wxGraphicsBrush
CreateBrush(const wxBrush
& brush
) ;
1274 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1275 virtual wxGraphicsBrush
CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1276 const wxColour
&c1
, const wxColour
&c2
) ;
1278 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1279 // with radius r and color cColor
1280 virtual wxGraphicsBrush
CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1281 const wxColour
&oColor
, const wxColour
&cColor
) ;
1284 virtual wxGraphicsFont
CreateFont( const wxFont
&font
, const wxColour
&col
= *wxBLACK
) ;
1286 void EnsureIsLoaded();
1289 friend class wxGDIPlusRendererModule
;
1293 ULONG_PTR m_gditoken
;
1295 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer
)
1298 //-----------------------------------------------------------------------------
1299 // wxGDIPlusRenderer implementation
1300 //-----------------------------------------------------------------------------
1302 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer
,wxGraphicsRenderer
)
1304 static wxGDIPlusRenderer gs_GDIPlusRenderer
;
1306 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer()
1308 return &gs_GDIPlusRenderer
;
1311 void wxGDIPlusRenderer::EnsureIsLoaded()
1319 void wxGDIPlusRenderer::Load()
1321 GdiplusStartupInput input
;
1322 GdiplusStartupOutput output
;
1323 GdiplusStartup(&m_gditoken
,&input
,&output
);
1327 void wxGDIPlusRenderer::Unload()
1331 GdiplusShutdown(m_gditoken
);
1337 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxWindowDC
& dc
)
1340 return new wxGDIPlusContext(this,(HDC
) dc
.GetHDC());
1343 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxMemoryDC
& dc
)
1346 return new wxGDIPlusContext(this,(HDC
) dc
.GetHDC());
1349 wxGraphicsContext
* wxGDIPlusRenderer::CreateMeasuringContext()
1353 // TODO use GetDC(NULL) but then we have to release it from the context
1354 //return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1357 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeContext( void * context
)
1360 return new wxGDIPlusContext(this,(Graphics
*) context
);
1364 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window
)
1367 return new wxGDIPlusContext(this,(HWND
) window
);
1370 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( wxWindow
* window
)
1373 return new wxGDIPlusContext(this, (HWND
) window
->GetHWND() );
1378 wxGraphicsPath
wxGDIPlusRenderer::CreatePath()
1382 m
.SetRefData( new wxGDIPlusPathData(this));
1389 wxGraphicsMatrix
wxGDIPlusRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
1390 wxDouble tx
, wxDouble ty
)
1395 wxGDIPlusMatrixData
* data
= new wxGDIPlusMatrixData( this );
1396 data
->Set( a
,b
,c
,d
,tx
,ty
) ;
1401 wxGraphicsPen
wxGDIPlusRenderer::CreatePen(const wxPen
& pen
)
1404 if ( !pen
.Ok() || pen
.GetStyle() == wxTRANSPARENT
)
1405 return wxNullGraphicsPen
;
1409 p
.SetRefData(new wxGDIPlusPenData( this, pen
));
1414 wxGraphicsBrush
wxGDIPlusRenderer::CreateBrush(const wxBrush
& brush
)
1417 if ( !brush
.Ok() || brush
.GetStyle() == wxTRANSPARENT
)
1418 return wxNullGraphicsBrush
;
1422 p
.SetRefData(new wxGDIPlusBrushData( this, brush
));
1427 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1428 wxGraphicsBrush
wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1429 const wxColour
&c1
, const wxColour
&c2
)
1433 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
1434 d
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, c1
, c2
);
1439 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1440 // with radius r and color cColor
1441 wxGraphicsBrush
wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1442 const wxColour
&oColor
, const wxColour
&cColor
)
1446 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
1447 d
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,oColor
,cColor
);
1453 wxGraphicsFont
wxGDIPlusRenderer::CreateFont( const wxFont
&font
, const wxColour
&col
)
1459 p
.SetRefData(new wxGDIPlusFontData( this , font
, col
));
1463 return wxNullGraphicsFont
;
1466 // Shutdown GDI+ at app exit, before possible dll unload
1467 class wxGDIPlusRendererModule
: public wxModule
1470 virtual bool OnInit() { return true; }
1471 virtual void OnExit() { gs_GDIPlusRenderer
.Unload(); }
1474 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule
)
1477 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule
, wxModule
)
1479 #endif // wxUSE_GRAPHICS_CONTEXT