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
;
111 void EnsureIsLoaded()
120 GdiplusStartupInput input
;
121 GdiplusStartupOutput output
;
122 GdiplusStartup(&m_gditoken
,&input
,&output
);
128 GdiplusShutdown(m_gditoken
);
136 static GDILoader gGDILoader
;
138 class WXDLLEXPORT wxGDIPlusPath
: public wxGraphicsPath
146 // These are the path primitives from which everything else can be constructed
149 // begins a new subpath at (x,y)
150 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
152 // adds a straight line from the current point to (x,y)
153 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
155 // adds a cubic Bezier curve from the current point, using two control points and an end point
156 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
159 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
160 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
162 // gets the last point of the current path, (0,0) if not yet set
163 virtual void GetCurrentPoint( wxDouble
& x
, wxDouble
&y
) ;
165 // closes the current sub-path
166 virtual void CloseSubpath();
169 // These are convenience functions which - if not available natively will be assembled
170 // using the primitives from above
173 // appends a rectangle as a new closed subpath
174 virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
) ;
177 // appends an ellipsis as a new closed subpath fitting the passed rectangle
178 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
180 // 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)
181 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
184 // returns the native path
185 virtual void * GetNativePath() const { return m_path
; }
187 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
188 virtual void UnGetNativePath(void * WXUNUSED(path
)) {}
191 GraphicsPath
* m_path
;
192 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusPath
)
195 class WXDLLEXPORT wxGDIPlusContext
: public wxGraphicsContext
198 wxGDIPlusContext( HDC hdc
);
199 wxGDIPlusContext( HWND hwnd
);
200 wxGDIPlusContext( Graphics
* gr
);
203 virtual ~wxGDIPlusContext();
205 virtual void Clip( const wxRegion
®ion
);
206 // clips drawings to the rect
207 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
209 // resets the clipping to original extent
210 virtual void ResetClip();
212 virtual void * GetNativeContext();
214 virtual void StrokePath( const wxGraphicsPath
*p
);
215 virtual void FillPath( const wxGraphicsPath
*p
, int fillStyle
= wxWINDING_RULE
);
217 virtual wxGraphicsPath
* CreatePath();
218 virtual void SetPen( const wxPen
&pen
);
219 virtual void SetBrush( const wxBrush
&brush
);
220 virtual void SetLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
) ;
221 virtual void SetRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
222 const wxColour
&oColor
, const wxColour
&cColor
);
224 virtual void Translate( wxDouble dx
, wxDouble dy
);
225 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
226 virtual void Rotate( wxDouble angle
);
228 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
229 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
230 virtual void PushState();
231 virtual void PopState();
233 virtual void SetFont( const wxFont
&font
);
234 virtual void SetTextColour( const wxColour
&col
);
235 virtual void DrawText( const wxString
&str
, wxDouble x
, wxDouble y
);
236 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
237 wxDouble
*descent
, wxDouble
*externalLeading
) const;
238 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
245 vector
<GraphicsState
> m_stateStack
;
246 GraphicsState m_state1
;
247 GraphicsState m_state2
;
250 bool m_penTransparent
;
255 bool m_brushTransparent
;
257 GraphicsPath
* m_brushPath
;
263 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext
)
266 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusPath
,wxGraphicsPath
)
268 wxGDIPlusPath::wxGDIPlusPath()
270 m_path
= new GraphicsPath();
273 wxGDIPlusPath::~wxGDIPlusPath()
282 void wxGDIPlusPath::MoveToPoint( wxDouble x
, wxDouble y
)
284 m_path
->StartFigure();
285 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
288 void wxGDIPlusPath::AddLineToPoint( wxDouble x
, wxDouble y
)
290 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
293 void wxGDIPlusPath::CloseSubpath()
295 m_path
->CloseFigure();
298 void wxGDIPlusPath::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
304 m_path
->GetLastPoint(&start
);
305 m_path
->AddBezier(start
,c1
,c2
,end
);
308 // gets the last point of the current path, (0,0) if not yet set
309 void wxGDIPlusPath::GetCurrentPoint( wxDouble
& x
, wxDouble
&y
)
312 m_path
->GetLastPoint(&start
);
317 void wxGDIPlusPath::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
319 double sweepAngle
= endAngle
- startAngle
;
320 if( abs(sweepAngle
) >= 2*M_PI
)
322 sweepAngle
= 2 * M_PI
;
329 sweepAngle
+= 2 * M_PI
;
334 sweepAngle
-= 2 * M_PI
;
338 m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));
341 void wxGDIPlusPath::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
343 m_path
->AddRectangle(RectF(x
,y
,w
,h
));
346 //-----------------------------------------------------------------------------
347 // wxGDIPlusContext implementation
348 //-----------------------------------------------------------------------------
350 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext
,wxGraphicsContext
)
352 wxGDIPlusContext::wxGDIPlusContext( HDC hdc
)
355 m_context
= new Graphics( hdc
);
359 wxGDIPlusContext::wxGDIPlusContext( HWND hwnd
)
362 m_context
= new Graphics( hwnd
);
366 wxGDIPlusContext::wxGDIPlusContext( Graphics
* gr
)
373 wxGDIPlusContext::wxGDIPlusContext()
378 void wxGDIPlusContext::Init()
380 gGDILoader
.EnsureIsLoaded();
386 m_penTransparent
= true;
391 m_brushTransparent
= true;
399 void wxGDIPlusContext::SetDefaults()
401 m_context
->SetSmoothingMode(SmoothingModeHighQuality
);
402 m_state1
= m_context
->Save();
403 m_state2
= m_context
->Save();
406 m_penTransparent
= false;
407 m_pen
= new Pen((ARGB
)Color::Black
);
411 m_brushTransparent
= false;
412 m_brush
= new SolidBrush((ARGB
)Color::White
);
415 m_textBrush
= new SolidBrush((ARGB
)Color::Black
);
416 m_font
= new Font( L
"Arial" , 9 , FontStyleRegular
);
419 wxGDIPlusContext::~wxGDIPlusContext()
423 m_context
->Restore( m_state2
);
424 m_context
->Restore( m_state1
);
438 void wxGDIPlusContext::Clip( const wxRegion
®ion
)
440 m_context
->SetClip((HRGN
)region
.GetHRGN(),CombineModeIntersect
);
443 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
445 m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
);
448 void wxGDIPlusContext::ResetClip()
450 m_context
->ResetClip();
453 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
*path
)
455 if ( m_penTransparent
)
458 m_context
->DrawPath( m_pen
, (GraphicsPath
*) path
->GetNativePath() );
461 void wxGDIPlusContext::FillPath( const wxGraphicsPath
*path
, int fillStyle
)
463 if ( !m_brushTransparent
)
465 ((GraphicsPath
*) path
->GetNativePath())->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
466 m_context
->FillPath( m_brush
, (GraphicsPath
*) path
->GetNativePath());
470 wxGraphicsPath
* wxGDIPlusContext::CreatePath()
472 return new wxGDIPlusPath();
475 void wxGDIPlusContext::Rotate( wxDouble angle
)
477 m_context
->RotateTransform( RadToDeg(angle
) );
480 void wxGDIPlusContext::Translate( wxDouble dx
, wxDouble dy
)
482 m_context
->TranslateTransform( dx
, dy
);
485 void wxGDIPlusContext::Scale( wxDouble xScale
, wxDouble yScale
)
487 m_context
->ScaleTransform(xScale
,yScale
);
490 void wxGDIPlusContext::PushState()
492 GraphicsState state
= m_context
->Save();
493 m_stateStack
.push_back(state
);
496 void wxGDIPlusContext::PopState()
498 GraphicsState state
= m_stateStack
.back();
499 m_stateStack
.pop_back();
500 m_context
->Restore(state
);
503 void wxGDIPlusContext::SetTextColour( const wxColour
&col
)
506 m_textBrush
= new SolidBrush( Color( col
.Alpha() , col
.Red() ,
507 col
.Green() , col
.Blue() ));
510 void wxGDIPlusContext::SetPen( const wxPen
&pen
)
512 m_penTransparent
= pen
.GetStyle() == wxTRANSPARENT
;
513 if ( m_penTransparent
)
516 m_pen
->SetColor( Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
517 pen
.GetColour().Green() , pen
.GetColour().Blue() ) );
519 // TODO: * m_dc->m_scaleX
520 double penWidth
= pen
.GetWidth();
524 m_pen
->SetWidth(penWidth
);
527 switch ( pen
.GetCap() )
533 case wxCAP_PROJECTING
:
538 cap
= LineCapFlat
; // TODO verify
545 m_pen
->SetLineCap(cap
,cap
, DashCapFlat
);
548 switch ( pen
.GetJoin() )
551 join
= LineJoinBevel
;
555 join
= LineJoinMiter
;
559 join
= LineJoinRound
;
563 join
= LineJoinMiter
;
567 m_pen
->SetLineJoin(join
);
569 m_pen
->SetDashStyle(DashStyleSolid
);
571 DashStyle dashStyle
= DashStyleSolid
;
572 switch ( pen
.GetStyle() )
578 dashStyle
= DashStyleDot
;
582 dashStyle
= DashStyleDash
; // TODO verify
586 dashStyle
= DashStyleDash
;
590 dashStyle
= DashStyleDashDot
;
594 dashStyle
= DashStyleCustom
;
596 int count
= pen
.GetDashes( &dashes
);
597 if ((dashes
!= NULL
) && (count
> 0))
599 REAL
*userLengths
= new REAL
[count
];
600 for ( int i
= 0; i
< count
; ++i
)
602 userLengths
[i
] = dashes
[i
];
604 m_pen
->SetDashPattern( userLengths
, count
);
605 delete[] userLengths
;
611 wxBitmap
* bmp
= pen
.GetStipple();
612 if ( bmp
&& bmp
->Ok() )
614 wxDELETE( m_penImage
);
615 wxDELETE( m_penBrush
);
616 m_penImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
617 m_penBrush
= new TextureBrush(m_penImage
);
618 m_pen
->SetBrush( m_penBrush
);
624 if ( pen
.GetStyle() >= wxFIRST_HATCH
&& pen
.GetStyle() <= wxLAST_HATCH
)
626 wxDELETE( m_penBrush
);
627 HatchStyle style
= HatchStyleHorizontal
;
628 switch( pen
.GetStyle() )
630 case wxBDIAGONAL_HATCH
:
631 style
= HatchStyleBackwardDiagonal
;
633 case wxCROSSDIAG_HATCH
:
634 style
= HatchStyleDiagonalCross
;
636 case wxFDIAGONAL_HATCH
:
637 style
= HatchStyleForwardDiagonal
;
640 style
= HatchStyleCross
;
642 case wxHORIZONTAL_HATCH
:
643 style
= HatchStyleHorizontal
;
645 case wxVERTICAL_HATCH
:
646 style
= HatchStyleVertical
;
650 m_penBrush
= new HatchBrush(style
,Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
651 pen
.GetColour().Green() , pen
.GetColour().Blue() ), Color::Transparent
);
652 m_pen
->SetBrush( m_penBrush
);
656 if ( dashStyle
!= DashStyleSolid
)
657 m_pen
->SetDashStyle(dashStyle
);
660 void wxGDIPlusContext::SetBrush( const wxBrush
&brush
)
663 if ( m_context
== NULL
)
666 m_brushTransparent
= brush
.GetStyle() == wxTRANSPARENT
;
668 if ( m_brushTransparent
)
673 if ( brush
.GetStyle() == wxSOLID
)
675 m_brush
= new SolidBrush( Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
676 brush
.GetColour().Green() , brush
.GetColour().Blue() ) );
678 else if ( brush
.IsHatch() )
680 HatchStyle style
= HatchStyleHorizontal
;
681 switch( brush
.GetStyle() )
683 case wxBDIAGONAL_HATCH
:
684 style
= HatchStyleBackwardDiagonal
;
686 case wxCROSSDIAG_HATCH
:
687 style
= HatchStyleDiagonalCross
;
689 case wxFDIAGONAL_HATCH
:
690 style
= HatchStyleForwardDiagonal
;
693 style
= HatchStyleCross
;
695 case wxHORIZONTAL_HATCH
:
696 style
= HatchStyleHorizontal
;
698 case wxVERTICAL_HATCH
:
699 style
= HatchStyleVertical
;
703 m_brush
= new HatchBrush(style
,Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
704 brush
.GetColour().Green() , brush
.GetColour().Blue() ), Color::Transparent
);
708 wxBitmap
* bmp
= brush
.GetStipple();
709 if ( bmp
&& bmp
->Ok() )
711 wxDELETE( m_brushImage
);
712 m_brushImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
713 m_brush
= new TextureBrush(m_brushImage
);
718 void wxGDIPlusContext::SetLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
)
720 m_brushTransparent
= false ;
724 m_brush
= new LinearGradientBrush( PointF( x1
,y1
) , PointF( x2
,y2
),
725 Color( c1
.Alpha(), c1
.Red(),c1
.Green() , c1
.Blue() ),
726 Color( c2
.Alpha(), c2
.Red(),c2
.Green() , c2
.Blue() ));
729 void wxGDIPlusContext::SetRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
730 const wxColour
&oColor
, const wxColour
&cColor
)
732 m_brushTransparent
= false ;
735 wxDELETE(m_brushPath
);
737 // Create a path that consists of a single circle.
738 m_brushPath
= new GraphicsPath();
739 m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
), (REAL
)(2*radius
), (REAL
)(2*radius
));
741 PathGradientBrush
*b
= new PathGradientBrush(m_brushPath
);
743 b
->SetCenterPoint( PointF(xo
,yo
));
744 b
->SetCenterColor(Color( oColor
.Alpha(), oColor
.Red(),oColor
.Green() , oColor
.Blue() ));
746 Color colors
[] = {Color( cColor
.Alpha(), cColor
.Red(),cColor
.Green() , cColor
.Blue() )};
748 b
->SetSurroundColors(colors
, &count
);
751 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
752 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
753 // bytes as parameter
755 void wxGDIPlusContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
757 Bitmap
* image
= NULL
;
758 Bitmap
* helper
= NULL
;
761 Bitmap
interim((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()) ;
763 size_t width
= interim
.GetWidth();
764 size_t height
= interim
.GetHeight();
765 Rect
bounds(0,0,width
,height
);
767 image
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ;
769 Bitmap
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
);
770 wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
);
772 BitmapData dataMask
;
773 interimMask
.LockBits(&bounds
,ImageLockModeRead
,
774 interimMask
.GetPixelFormat(),&dataMask
);
777 BitmapData imageData
;
778 image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
);
780 BYTE maskPattern
= 0 ;
784 for ( size_t y
= 0 ; y
< height
; ++y
)
787 for( size_t x
= 0 ; x
< width
; ++x
)
792 maskByte
= *((BYTE
*)dataMask
.Scan0
+ dataMask
.Stride
*y
+ maskIndex
);
796 maskPattern
= maskPattern
>> 1;
798 ARGB
*dest
= (ARGB
*)((BYTE
*)imageData
.Scan0
+ imageData
.Stride
*y
+ x
*4);
799 if ( (maskByte
& maskPattern
) == 0 )
804 interim
.GetPixel(x
,y
,&c
) ;
805 *dest
= (c
.GetValue() | Color::AlphaMask
);
810 image
->UnlockBits(&imageData
);
812 interimMask
.UnlockBits(&dataMask
);
813 interim
.UnlockBits(&dataMask
);
817 image
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE());
818 if ( GetPixelFormatSize(image
->GetPixelFormat()) == 32 )
820 size_t width
= image
->GetWidth();
821 size_t height
= image
->GetHeight();
822 Rect
bounds(0,0,width
,height
);
827 helper
->LockBits(&bounds
, ImageLockModeRead
,
828 helper
->GetPixelFormat(),&data
);
830 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
831 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
833 helper
->UnlockBits(&data
);
837 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
842 void wxGDIPlusContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
844 HICON hIcon
= (HICON
)icon
.GetHICON();
846 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
847 if (!GetIconInfo(hIcon
,&iconInfo
))
851 GetObject(iconInfo
.hbmColor
,sizeof(BITMAP
),&iconBmpData
);
852 Bitmap
interim(iconInfo
.hbmColor
,NULL
);
854 Bitmap
* image
= NULL
;
856 if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 )
858 image
= Bitmap::FromHICON(hIcon
);
862 size_t width
= interim
.GetWidth();
863 size_t height
= interim
.GetHeight();
864 Rect
bounds(0,0,width
,height
);
867 interim
.LockBits(&bounds
, ImageLockModeRead
,
868 interim
.GetPixelFormat(),&data
);
869 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
870 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
871 interim
.UnlockBits(&data
);
874 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
877 DeleteObject(iconInfo
.hbmColor
);
878 DeleteObject(iconInfo
.hbmMask
);
882 void wxGDIPlusContext::DrawText( const wxString
&str
, wxDouble x
, wxDouble y
)
887 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
888 m_context
->DrawString( s
, -1 , m_font
, PointF( x
, y
) , m_textBrush
);
889 // TODO m_backgroundMode == wxSOLID
892 void wxGDIPlusContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
893 wxDouble
*descent
, wxDouble
*externalLeading
) const
895 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
898 m_font
->GetFamily(&ffamily
) ;
900 REAL factorY
= m_context
->GetDpiY() / 72.0 ;
902 REAL rDescent
= ffamily
.GetCellDescent(FontStyleRegular
) *
903 m_font
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
904 REAL rAscent
= ffamily
.GetCellAscent(FontStyleRegular
) *
905 m_font
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
906 REAL rHeight
= ffamily
.GetLineSpacing(FontStyleRegular
) *
907 m_font
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
910 *height
= rHeight
* factorY
+ 0.5 ;
912 *descent
= rDescent
* factorY
+ 0.5 ;
913 if ( externalLeading
)
914 *externalLeading
= (rHeight
- rAscent
- rDescent
) * factorY
+ 0.5 ;
915 // measuring empty strings is not guaranteed, so do it by hand
923 // MeasureString does return a rectangle that is way too large, so it is
925 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
926 StringFormat strFormat
;
927 CharacterRange
strRange(0,wcslen(s
));
928 strFormat
.SetMeasurableCharacterRanges(1,&strRange
);
930 m_context
->MeasureCharacterRanges(s
, -1 , m_font
,layoutRect
, &strFormat
,1,®ion
) ;
932 region
.GetBounds(&bbox
,m_context
);
934 *width
= bbox
.GetRight()-bbox
.GetLeft()+0.5;
938 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
941 widths
.Add(0, text
.length());
946 wxWCharBuffer ws
= text
.wc_str( *wxConvUI
);
947 size_t len
= wcslen( ws
) ;
948 wxASSERT_MSG(text
.length() == len
, wxT("GetPartialTextExtents not yet implemented for multichar situations"));
950 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
951 StringFormat strFormat
;
953 CharacterRange
* ranges
= new CharacterRange
[len
] ;
954 Region
* regions
= new Region
[len
];
955 for( size_t i
= 0 ; i
< len
; ++i
)
957 ranges
[i
].First
= i
;
958 ranges
[i
].Length
= 1 ;
960 strFormat
.SetMeasurableCharacterRanges(len
,ranges
);
961 m_context
->MeasureCharacterRanges(ws
, -1 , m_font
,layoutRect
, &strFormat
,1,regions
) ;
964 for ( size_t i
= 0 ; i
< len
; ++i
)
966 regions
[i
].GetBounds(&bbox
,m_context
);
967 widths
[i
] = bbox
.GetRight()-bbox
.GetLeft();
971 void wxGDIPlusContext::SetFont( const wxFont
&font
)
973 wxASSERT( font
.Ok());
975 wxWCharBuffer s
= font
.GetFaceName().wc_str( *wxConvUI
);
976 int size
= font
.GetPointSize();
977 int style
= FontStyleRegular
;
978 if ( font
.GetStyle() == wxFONTSTYLE_ITALIC
)
979 style
|= FontStyleItalic
;
980 if ( font
.GetUnderlined() )
981 style
|= FontStyleUnderline
;
982 if ( font
.GetWeight() == wxFONTWEIGHT_BOLD
)
983 style
|= FontStyleBold
;
984 m_font
= new Font( s
, size
, style
);
987 void* wxGDIPlusContext::GetNativeContext()
992 wxGraphicsContext
* wxGraphicsContext::Create( const wxWindowDC
& dc
)
994 return new wxGDIPlusContext( (HDC
) dc
.GetHDC() );
997 wxGraphicsContext
* wxGraphicsContext::Create( wxWindow
* window
)
999 return new wxGDIPlusContext( (HWND
) window
->GetHWND() );
1002 wxGraphicsContext
* wxGraphicsContext::CreateFromNative( void * context
)
1004 return new wxGDIPlusContext( (Graphics
*) context
);
1009 #endif // wxUSE_GRAPHICS_CONTEXT