From 6fea499ca8a3e99bfb7c16ce167146f1fa754367 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sat, 30 Sep 2006 13:06:09 +0000 Subject: [PATCH] gdiplus implementation git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41525 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/msw/graphics.cpp | 831 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 831 insertions(+) create mode 100644 src/msw/graphics.cpp diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp new file mode 100644 index 0000000000..7e9d5da60e --- /dev/null +++ b/src/msw/graphics.cpp @@ -0,0 +1,831 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/mac/carbon/dccg.cpp +// Purpose: wxGCDC class +// Author: Stefan Csomor +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#include "wx/dc.h" + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/msw/wrapcdlg.h" +#include "wx/image.h" +#include "wx/window.h" +#include "wx/dc.h" +#include "wx/utils.h" +#include "wx/dialog.h" +#include "wx/app.h" +#include "wx/bitmap.h" +#include "wx/dcmemory.h" +#include "wx/log.h" +#include "wx/icon.h" +#include "wx/dcprint.h" +#include "wx/module.h" +#endif + +#include "wx/graphics.h" + +#include + +using namespace std; + +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +const double RAD2DEG = 180.0 / M_PI; + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- + +static inline double dmin(double a, double b) { return a < b ? a : b; } +static inline double dmax(double a, double b) { return a > b ? a : b; } + +static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } +static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; } + +//----------------------------------------------------------------------------- +// device context implementation +// +// more and more of the dc functionality should be implemented by calling +// the appropricate wxGDIPlusContext, but we will have to do that step by step +// also coordinate conversions should be moved to native matrix ops +//----------------------------------------------------------------------------- + +// we always stock two context states, one at entry, to be able to preserve the +// state we were called with, the other one after changing to HI Graphics orientation +// (this one is used for getting back clippings etc) + +//----------------------------------------------------------------------------- +// wxGraphicsPath implementation +//----------------------------------------------------------------------------- + +#include "wx/msw/private.h" // needs to be before #include + +#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__) +#include +#endif + +// TODO remove this dependency (gdiplus needs the macros) + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#include "gdiplus.h" +using namespace Gdiplus; + +class GDILoader +{ +public : + GDILoader() + { + m_loaded = false; + m_gditoken = NULL; + } + + ~GDILoader() + { + if (m_loaded) + { + Unload(); + } + } + void EnsureIsLoaded() + { + if (!m_loaded) + { + Load(); + } + } + void Load() + { + GdiplusStartupInput input; + GdiplusStartupOutput output; + GdiplusStartup(&m_gditoken,&input,&output); + m_loaded = true; + } + void Unload() + { + if ( m_gditoken ) + GdiplusShutdown(m_gditoken); + } +private : + bool m_loaded; + DWORD m_gditoken; + +}; + +static GDILoader gGDILoader; + +class WXDLLEXPORT wxGDIPlusPath : public wxGraphicsPath +{ + DECLARE_NO_COPY_CLASS(wxGDIPlusPath) +public : + wxGDIPlusPath(); + ~wxGDIPlusPath(); + + + // + // These are the path primitives from which everything else can be constructed + // + + // begins a new subpath at (x,y) + virtual void MoveToPoint( wxDouble x, wxDouble y ); + + // adds a straight line from the current point to (x,y) + virtual void AddLineToPoint( wxDouble x, wxDouble y ); + + // adds a cubic Bezier curve from the current point, using two control points and an end point + virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ); + + + // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle + virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ; + + // gets the last point of the current path, (0,0) if not yet set + virtual void GetCurrentPoint( wxDouble& x, wxDouble&y) ; + + // closes the current sub-path + virtual void CloseSubpath(); + + // + // These are convenience functions which - if not available natively will be assembled + // using the primitives from above + // + + // appends a rectangle as a new closed subpath + virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ; + /* + + // appends an ellipsis as a new closed subpath fitting the passed rectangle + virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ; + + // 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) + virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ; +*/ + + GraphicsPath* GetPath() const; +private : + GraphicsPath* m_path; +}; + +class WXDLLEXPORT wxGDIPlusContext : public wxGraphicsContext +{ + DECLARE_NO_COPY_CLASS(wxGDIPlusContext) + +public: + wxGDIPlusContext( WXHDC hdc ); + wxGDIPlusContext(); + virtual ~wxGDIPlusContext(); + + virtual void Clip( const wxRegion ®ion ); + virtual void StrokePath( const wxGraphicsPath *p ); + virtual void FillPath( const wxGraphicsPath *p , int fillStyle = wxWINDING_RULE ); + + virtual wxGraphicsPath* CreatePath(); + virtual void SetPen( const wxPen &pen ); + virtual void SetBrush( const wxBrush &brush ); + virtual void SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2) ; + virtual void SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor); + + virtual void Translate( wxDouble dx , wxDouble dy ); + virtual void Scale( wxDouble xScale , wxDouble yScale ); + virtual void Rotate( wxDouble angle ); + + virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); + virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); + virtual void PushState(); + virtual void PopState(); + + virtual void SetFont( const wxFont &font ); + virtual void SetTextColor( const wxColour &col ); + virtual void DrawText( const wxString &str, wxDouble x, wxDouble y); + virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, + wxDouble *descent, wxDouble *externalLeading ) const; + virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const; + +private: + Graphics* m_context; + vector m_stateStack; + GraphicsState m_state1; + GraphicsState m_state2; + + Pen* m_pen; + bool m_penTransparent; + Image* m_penImage; + Brush* m_penBrush; + + Brush* m_brush; + bool m_brushTransparent; + Image* m_brushImage; + GraphicsPath* m_brushPath; + + Brush* m_textBrush; + Font* m_font; + // wxPen m_pen; + // wxBrush m_brush; +}; + +wxGDIPlusPath::wxGDIPlusPath() +{ + m_path = new GraphicsPath(); +} + +wxGDIPlusPath::~wxGDIPlusPath() +{ + delete m_path; +} + +GraphicsPath* wxGDIPlusPath::GetPath() const +{ + return m_path; +} + +// +// The Primitives +// + +void wxGDIPlusPath::MoveToPoint( wxDouble x , wxDouble y ) +{ + m_path->StartFigure(); + m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y); +} + +void wxGDIPlusPath::AddLineToPoint( wxDouble x , wxDouble y ) +{ + m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y); +} + +void wxGDIPlusPath::CloseSubpath() +{ + m_path->CloseFigure(); +} + +void wxGDIPlusPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ) +{ + PointF c1(cx1,cy1); + PointF c2(cx2,cy2); + PointF end(x,y); + PointF start; + m_path->GetLastPoint(&start); + m_path->AddBezier(start,c1,c2,end); +} + +// gets the last point of the current path, (0,0) if not yet set +void wxGDIPlusPath::GetCurrentPoint( wxDouble& x, wxDouble&y) +{ + PointF start; + m_path->GetLastPoint(&start); + x = start.X ; + y = start.Y ; +} + +void wxGDIPlusPath::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise ) +{ + double sweepAngle = endAngle - startAngle ; + if( abs(sweepAngle) >= 2*M_PI) + { + sweepAngle = 2 * M_PI; + } + else + { + if ( clockwise ) + { + if( sweepAngle < 0 ) + sweepAngle += 2 * M_PI; + } + else + { + if( sweepAngle > 0 ) + sweepAngle -= 2 * M_PI; + + } + } + m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),RadToDeg(startAngle),RadToDeg(sweepAngle)); +} + +void wxGDIPlusPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + m_path->AddRectangle(RectF(x,y,w,h)); +} + +// +// +// +/* +// closes the current subpath +void wxGDIPlusPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) +{ +// CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r); +} + +*/ + +//----------------------------------------------------------------------------- +// wxGDIPlusContext implementation +//----------------------------------------------------------------------------- + +wxGDIPlusContext::wxGDIPlusContext( WXHDC hdc ) +{ + gGDILoader.EnsureIsLoaded(); + m_context = new Graphics( (HDC) hdc); + m_state1 = m_context->Save(); + m_state2 = m_context->Save(); + + // set defaults + + m_penTransparent = false; + m_pen = new Pen((ARGB)Color::Black); + m_penImage = NULL; + m_penBrush = NULL; + + m_brushTransparent = false; + m_brush = new SolidBrush((ARGB)Color::White); + m_brushImage = NULL; + m_brushPath = NULL; + m_textBrush = new SolidBrush((ARGB)Color::Black); + m_font = new Font( L"Arial" , 9 , FontStyleRegular ); +} + +wxGDIPlusContext::~wxGDIPlusContext() +{ + if ( m_context ) + { + m_context->Restore( m_state2 ); + m_context->Restore( m_state1 ); + delete m_context; + delete m_pen; + delete m_penImage; + delete m_penBrush; + delete m_brush; + delete m_brushImage; + delete m_brushPath; + delete m_textBrush; + delete m_font; + } +} + + +void wxGDIPlusContext::Clip( const wxRegion & WXUNUSED(region) ) +{ +// ClipCGContextToRegion ( m_context, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ); +} + +void wxGDIPlusContext::StrokePath( const wxGraphicsPath *p ) +{ + if ( m_penTransparent ) + return; + + const wxGDIPlusPath* path = dynamic_cast< const wxGDIPlusPath*>( p ); + m_context->DrawPath( m_pen , path->GetPath() ); +} + +void wxGDIPlusContext::FillPath( const wxGraphicsPath *p , int fillStyle ) +{ + if ( !m_brushTransparent ) + { + const wxGDIPlusPath* path = dynamic_cast< const wxGDIPlusPath*>( p ); + path->GetPath()->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding); + m_context->FillPath( m_brush , path->GetPath() ); + } +} + +wxGraphicsPath* wxGDIPlusContext::CreatePath() +{ + return new wxGDIPlusPath(); +} + +void wxGDIPlusContext::Rotate( wxDouble angle ) +{ + m_context->RotateTransform( angle ); +} + +void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy ) +{ + m_context->TranslateTransform( dx , dy ); +} + +void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale ) +{ + PointF penWidth( m_pen->GetWidth(), 0); + Matrix matrix ; + if ( !m_penTransparent ) + { + m_context->GetTransform(&matrix); + matrix.TransformVectors(&penWidth); + } + m_context->ScaleTransform(xScale,yScale); + if ( !m_penTransparent ) + { + m_context->GetTransform(&matrix); + matrix.Invert(); + matrix.TransformVectors(&penWidth) ; + m_pen->SetWidth( sqrt( penWidth.X*penWidth.X + penWidth.Y*penWidth.Y)); + } +} + +void wxGDIPlusContext::PushState() +{ + GraphicsState state = m_context->Save(); + m_stateStack.push_back(state); +} + +void wxGDIPlusContext::PopState() +{ + GraphicsState state = m_stateStack.back(); + m_stateStack.pop_back(); + m_context->Restore(state); +} + +void wxGDIPlusContext::SetTextColor( const wxColour &col ) +{ + delete m_textBrush; + m_textBrush = new SolidBrush( Color( col.Alpha() , col.Red() , + col.Green() , col.Blue() )); +} + +void wxGDIPlusContext::SetPen( const wxPen &pen ) +{ + m_penTransparent = pen.GetStyle() == wxTRANSPARENT; + if ( m_penTransparent ) + return; + + m_pen->SetColor( Color( pen.GetColour().Alpha() , pen.GetColour().Red() , + pen.GetColour().Green() , pen.GetColour().Blue() ) ); + + // TODO: * m_dc->m_scaleX + double penWidth = pen.GetWidth(); + if (penWidth <= 0.0) + penWidth = 0.1; + + m_pen->SetWidth(penWidth); + + LineCap cap; + switch ( pen.GetCap() ) + { + case wxCAP_ROUND : + cap = LineCapRound; + break; + + case wxCAP_PROJECTING : + cap = LineCapSquare; + break; + + case wxCAP_BUTT : + cap = LineCapFlat; // TODO verify + break; + + default : + cap = LineCapFlat; + break; + } + m_pen->SetLineCap(cap,cap, DashCapFlat); + + LineJoin join; + switch ( pen.GetJoin() ) + { + case wxJOIN_BEVEL : + join = LineJoinBevel; + break; + + case wxJOIN_MITER : + join = LineJoinMiter; + break; + + case wxJOIN_ROUND : + join = LineJoinRound; + break; + + default : + join = LineJoinMiter; + break; + } + + m_pen->SetLineJoin(join); + + m_pen->SetDashStyle(DashStyleSolid); + + DashStyle dashStyle = DashStyleSolid; + switch ( pen.GetStyle() ) + { + case wxSOLID : + break; + + case wxDOT : + dashStyle = DashStyleDot; + break; + + case wxLONG_DASH : + dashStyle = DashStyleDash; // TODO verify + break; + + case wxSHORT_DASH : + dashStyle = DashStyleDash; + break; + + case wxDOT_DASH : + dashStyle = DashStyleDashDot; + break; + case wxUSER_DASH : + { + dashStyle = DashStyleCustom; + wxDash *dashes; + int count = pen.GetDashes( &dashes ); + if ((dashes != NULL) && (count > 0)) + { + REAL *userLengths = new REAL[count]; + for ( int i = 0; i < count; ++i ) + { + userLengths[i] = dashes[i]; + } + m_pen->SetDashPattern( userLengths, count); + delete[] userLengths; + } + } + break; + case wxSTIPPLE : + { + wxBitmap* bmp = pen.GetStipple(); + if ( bmp && bmp->Ok() ) + { + wxDELETE( m_penImage ); + wxDELETE( m_penBrush ); + m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); + m_penBrush = new TextureBrush(m_penImage); + m_pen->SetBrush( m_penBrush ); + } + + } + break; + default : + if ( pen.GetStyle() >= wxFIRST_HATCH && pen.GetStyle() <= wxLAST_HATCH ) + { + wxDELETE( m_penBrush ); + HatchStyle style = HatchStyleHorizontal; + switch( pen.GetStyle() ) + { + case wxBDIAGONAL_HATCH : + style = HatchStyleBackwardDiagonal; + break ; + case wxCROSSDIAG_HATCH : + style = HatchStyleDiagonalCross; + break ; + case wxFDIAGONAL_HATCH : + style = HatchStyleForwardDiagonal; + break ; + case wxCROSS_HATCH : + style = HatchStyleCross; + break ; + case wxHORIZONTAL_HATCH : + style = HatchStyleHorizontal; + break ; + case wxVERTICAL_HATCH : + style = HatchStyleVertical; + break ; + + } + m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() , + pen.GetColour().Green() , pen.GetColour().Blue() ), Color::Transparent ); + m_pen->SetBrush( m_penBrush ); + } + break; + } + if ( dashStyle != DashStyleSolid ) + m_pen->SetDashStyle(dashStyle); +} + +void wxGDIPlusContext::SetBrush( const wxBrush &brush ) +{ +// m_brush = brush; + if ( m_context == NULL ) + return; + + m_brushTransparent = brush.GetStyle() == wxTRANSPARENT; + + if ( m_brushTransparent ) + return; + + wxDELETE(m_brush); + + if ( brush.GetStyle() == wxSOLID) + { + m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() , + brush.GetColour().Green() , brush.GetColour().Blue() ) ); + } + else if ( brush.IsHatch() ) + { + HatchStyle style = HatchStyleHorizontal; + switch( brush.GetStyle() ) + { + case wxBDIAGONAL_HATCH : + style = HatchStyleBackwardDiagonal; + break ; + case wxCROSSDIAG_HATCH : + style = HatchStyleDiagonalCross; + break ; + case wxFDIAGONAL_HATCH : + style = HatchStyleForwardDiagonal; + break ; + case wxCROSS_HATCH : + style = HatchStyleCross; + break ; + case wxHORIZONTAL_HATCH : + style = HatchStyleHorizontal; + break ; + case wxVERTICAL_HATCH : + style = HatchStyleVertical; + break ; + + } + m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() , + brush.GetColour().Green() , brush.GetColour().Blue() ), Color::Transparent ); + } + else + { + wxBitmap* bmp = brush.GetStipple(); + if ( bmp && bmp->Ok() ) + { + wxDELETE( m_brushImage ); + m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); + m_brush = new TextureBrush(m_brushImage); + } + } +} + +void wxGDIPlusContext::SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2) +{ + m_brushTransparent = false ; + + wxDELETE(m_brush); + + m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2), + Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ), + Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() )); +} + +void wxGDIPlusContext::SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor) +{ + m_brushTransparent = false ; + + wxDELETE(m_brush); + wxDELETE(m_brushPath); + + // Create a path that consists of a single circle. + m_brushPath = new GraphicsPath(); + m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius)); + + PathGradientBrush *b = new PathGradientBrush(m_brushPath); + m_brush = b; + b->SetCenterPoint( PointF(xo,yo)); + b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() )); + + Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )}; + int count = 1; + b->SetSurroundColors(colors, &count); +} + +void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + Bitmap* image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE()); + m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ; + delete image ; +} + +void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + Bitmap* image = Bitmap::FromHICON((HICON)icon.GetHICON()); + m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ; + delete image ; +} + + +void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y ) +{ + if ( str.IsEmpty()) + return ; + + wxWCharBuffer s = str.wc_str( *wxConvUI ); + m_context->DrawString( s , -1 , m_font , PointF( x , y ) , m_textBrush ); + // TODO m_backgroundMode == wxSOLID +} + +void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, + wxDouble *descent, wxDouble *externalLeading ) const +{ + wxWCharBuffer s = str.wc_str( *wxConvUI ); + FontFamily ffamily ; + + m_font->GetFamily(&ffamily) ; + + REAL factorY = m_context->GetDpiY() / 72.0 ; + + REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) * + m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular); + REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) * + m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular); + REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) * + m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular); + + if ( height ) + *height = rHeight * factorY + 0.5 ; + if ( descent ) + *descent = rDescent * factorY + 0.5 ; + if ( externalLeading ) + *externalLeading = (rHeight - rAscent - rDescent) * factorY + 0.5 ; + // measuring empty strings is not guaranteed, so do it by hand + if ( str.IsEmpty()) + { + if ( width ) + *width = 0 ; + } + else + { + // MeasureString does return a rectangle that is way too large, so it is + // not usable here + RectF layoutRect(0,0, 100000.0f, 100000.0f); + StringFormat strFormat; + CharacterRange strRange(0,wcslen(s)); + strFormat.SetMeasurableCharacterRanges(1,&strRange); + Region region ; + m_context->MeasureCharacterRanges(s, -1 , m_font,layoutRect, &strFormat,1,®ion) ; + RectF bbox ; + region.GetBounds(&bbox,m_context); + if ( width ) + *width = bbox.GetRight()-bbox.GetLeft()+0.5; + } +} + +void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const +{ + widths.Empty(); + widths.Add(0, text.length()); + + if (text.empty()) + return; + + wxWCharBuffer ws = text.wc_str( *wxConvUI ); + size_t len = wcslen( ws ) ; + wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations")); + + RectF layoutRect(0,0, 100000.0f, 100000.0f); + StringFormat strFormat; + + CharacterRange* ranges = new CharacterRange[len] ; + Region* regions = new Region[len]; + for( size_t i = 0 ; i < len ; ++i) + { + ranges[i].First = i ; + ranges[i].Length = 1 ; + } + strFormat.SetMeasurableCharacterRanges(len,ranges); + m_context->MeasureCharacterRanges(ws, -1 , m_font,layoutRect, &strFormat,1,regions) ; + + RectF bbox ; + for ( size_t i = 0 ; i < len ; ++i) + { + regions[i].GetBounds(&bbox,m_context); + widths[i] = bbox.GetRight()-bbox.GetLeft(); + } +} + +void wxGDIPlusContext::SetFont( const wxFont &font ) +{ + wxASSERT( font.Ok()); + delete m_font; + wxWCharBuffer s = font.GetFaceName().wc_str( *wxConvUI ); + int size = font.GetPointSize(); + int style = FontStyleRegular; + if ( font.GetStyle() == wxFONTSTYLE_ITALIC ) + style |= FontStyleItalic; + if ( font.GetUnderlined() ) + style |= FontStyleUnderline; + if ( font.GetWeight() == wxFONTWEIGHT_BOLD ) + style |= FontStyleBold; + m_font = new Font( s , size , style ); +} + +wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc) +{ + return new wxGDIPlusContext( (HDC) dc.GetHDC() ); +} -- 2.45.2