Add support for gradient pens for GDI+. API also updated for gradient transforms, but that is not working yet.

This commit is contained in:
Robin Dunn
2019-08-01 15:14:50 -07:00
parent 2008d443a8
commit 8478c97ecb

View File

@@ -255,44 +255,30 @@ private:
Matrix* m_matrix ; Matrix* m_matrix ;
} ; } ;
class wxGDIPlusPenData : public wxGraphicsObjectRefData
// Things that pens and brushes have in common
class wxGDIPlusPenBrushBaseData : public wxGraphicsObjectRefData
{ {
public: public:
wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxGraphicsPenInfo &info ); wxGDIPlusPenBrushBaseData(wxGraphicsRenderer* renderer);
~wxGDIPlusPenData(); ~wxGDIPlusPenBrushBaseData();
void Init(); virtual void Init();
virtual wxDouble GetWidth() { return m_width; }
virtual Pen* GetGDIPlusPen() { return m_pen; }
protected :
Pen* m_pen;
Image* m_penImage;
Brush* m_penBrush;
wxDouble m_width;
};
class wxGDIPlusBrushData : public wxGraphicsObjectRefData
{
public:
wxGDIPlusBrushData( wxGraphicsRenderer* renderer );
wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
~wxGDIPlusBrushData ();
void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2, wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops); const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix);
void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, void CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc, wxDouble xc, wxDouble yc,
wxDouble radius, wxDouble radius,
const wxGraphicsGradientStops& stops); const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix);
virtual Brush* GetGDIPlusBrush() { return m_brush; }
protected: protected:
virtual void Init(); Brush* m_brush;
GraphicsPath* m_brushPath;
Image* m_image;
private: private:
// common part of Create{Linear,Radial}GradientBrush() // common part of Create{Linear,Radial}GradientBrush()
@@ -300,10 +286,35 @@ private:
void SetGradientStops(T *brush, void SetGradientStops(T *brush,
const wxGraphicsGradientStops& stops, const wxGraphicsGradientStops& stops,
bool reversed = false); bool reversed = false);
};
class wxGDIPlusPenData : public wxGDIPlusPenBrushBaseData
{
public:
wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxGraphicsPenInfo &info );
~wxGDIPlusPenData();
virtual void Init();
virtual wxDouble GetWidth() { return m_width; }
virtual Pen* GetGDIPlusPen() { return m_pen; }
protected :
Pen* m_pen;
wxDouble m_width;
};
class wxGDIPlusBrushData : public wxGDIPlusPenBrushBaseData
{
public:
wxGDIPlusBrushData( wxGraphicsRenderer* renderer );
wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
~wxGDIPlusBrushData ();
virtual Brush* GetGDIPlusBrush() { return m_brush; }
Brush* m_brush;
Image* m_brushImage;
GraphicsPath* m_brushPath;
}; };
class WXDLLIMPEXP_CORE wxGDIPlusBitmapData : public wxGraphicsBitmapData class WXDLLIMPEXP_CORE wxGDIPlusBitmapData : public wxGraphicsBitmapData
@@ -624,13 +635,15 @@ public :
virtual wxGraphicsBrush virtual wxGraphicsBrush
CreateLinearGradientBrush(wxDouble x1, wxDouble y1, CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2, wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops) wxOVERRIDE; const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix) wxOVERRIDE;
virtual wxGraphicsBrush virtual wxGraphicsBrush
CreateRadialGradientBrush(wxDouble xo, wxDouble yo, CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc, wxDouble xc, wxDouble yc,
wxDouble radius, wxDouble radius,
const wxGraphicsGradientStops& stops) wxOVERRIDE; const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix) wxOVERRIDE;
// create a native bitmap representation // create a native bitmap representation
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) wxOVERRIDE; virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) wxOVERRIDE;
@@ -669,6 +682,135 @@ private :
wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer); wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer);
} ; } ;
//-----------------------------------------------------------------------------
// wxGDIPlusPenBrushBaseData implementation
//-----------------------------------------------------------------------------
wxGDIPlusPenBrushBaseData::wxGDIPlusPenBrushBaseData(wxGraphicsRenderer* renderer)
: wxGraphicsObjectRefData(renderer)
{
Init();
}
wxGDIPlusPenBrushBaseData::~wxGDIPlusPenBrushBaseData()
{
delete m_brush;
delete m_brushPath;
delete m_image;
}
void wxGDIPlusPenBrushBaseData::Init()
{
m_brush = NULL;
m_brushPath = NULL;
m_image = NULL;
}
template <typename T>
void
wxGDIPlusPenBrushBaseData::SetGradientStops(T *brush,
const wxGraphicsGradientStops& stops,
bool reversed)
{
const unsigned numStops = stops.GetCount();
if ( numStops <= 2 )
{
// initial and final colours are set during the brush creation, nothing
// more to do
return;
}
wxVector<Color> colors(numStops);
wxVector<REAL> positions(numStops);
if ( reversed )
{
for ( unsigned i = 0; i < numStops; i++ )
{
wxGraphicsGradientStop stop = stops.Item(numStops - i - 1);
colors[i] = wxColourToColor(stop.GetColour());
positions[i] = 1.0 - stop.GetPosition();
}
}
else
{
for ( unsigned i = 0; i < numStops; i++ )
{
wxGraphicsGradientStop stop = stops.Item(i);
colors[i] = wxColourToColor(stop.GetColour());
positions[i] = stop.GetPosition();
}
}
brush->SetInterpolationColors(&colors[0], &positions[0], numStops);
}
void
wxGDIPlusPenBrushBaseData::CreateLinearGradientBrush(
wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& WXUNUSED(matrix))
{
LinearGradientBrush * const
brush = new LinearGradientBrush(PointF(x1, y1) , PointF(x2, y2),
wxColourToColor(stops.GetStartColour()),
wxColourToColor(stops.GetEndColour()));
// Tell the brush how to draw what's beyond the ends of the gradient
brush->SetWrapMode(WrapModeTileFlipXY);
// Apply the matrix
// This doesn't work as I expected it to. Comment-out for now...
// FIXME
// if (! matrix.IsNull())
// {
// const Matrix* m = static_cast<const Matrix*>(matrix.GetNativeMatrix());
// brush->SetTransform(m);
// }
SetGradientStops(brush, stops);
m_brush = brush;
}
void
wxGDIPlusPenBrushBaseData::CreateRadialGradientBrush(
wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc,
wxDouble radius,
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& WXUNUSED(matrix))
{
m_brushPath = new GraphicsPath();
m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius),
(REAL)(2*radius), (REAL)(2*radius));
PathGradientBrush * const brush = new PathGradientBrush(m_brushPath);
brush->SetCenterPoint(PointF(xo, yo));
brush->SetCenterColor(wxColourToColor(stops.GetStartColour()));
const Color col(wxColourToColor(stops.GetEndColour()));
int count = 1;
brush->SetSurroundColors(&col, &count);
// Apply the matrix
// This doesn't work as I expected it to. Comment-out for now...
// FIXME
// if (! matrix.IsNull())
// {
// const Matrix* m = static_cast<const Matrix*>(matrix.GetNativeMatrix());
// brush->SetTransform(m);
// }
// Because the GDI+ API draws radial gradients from outside towards the
// center we have to reverse the order of the gradient stops.
SetGradientStops(brush, stops, true);
m_brush = brush;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// wxGDIPlusPen implementation // wxGDIPlusPen implementation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -676,20 +818,16 @@ private :
wxGDIPlusPenData::~wxGDIPlusPenData() wxGDIPlusPenData::~wxGDIPlusPenData()
{ {
delete m_pen; delete m_pen;
delete m_penImage;
delete m_penBrush;
} }
void wxGDIPlusPenData::Init() void wxGDIPlusPenData::Init()
{ {
m_pen = NULL ; m_pen = NULL ;
m_penImage = NULL;
m_penBrush = NULL;
} }
wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer, wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
const wxGraphicsPenInfo &info ) const wxGraphicsPenInfo &info )
: wxGraphicsObjectRefData(renderer) : wxGDIPlusPenBrushBaseData(renderer)
{ {
Init(); Init();
m_width = info.GetWidth(); m_width = info.GetWidth();
@@ -786,15 +924,15 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
wxBitmap bmp = info.GetStipple(); wxBitmap bmp = info.GetStipple();
if ( bmp.IsOk() ) if ( bmp.IsOk() )
{ {
m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(), m_image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),
#if wxUSE_PALETTE #if wxUSE_PALETTE
(HPALETTE)bmp.GetPalette()->GetHPALETTE() (HPALETTE)bmp.GetPalette()->GetHPALETTE()
#else #else
NULL NULL
#endif #endif
); );
m_penBrush = new TextureBrush(m_penImage); m_brush = new TextureBrush(m_image);
m_pen->SetBrush( m_penBrush ); m_pen->SetBrush( m_brush );
} }
} }
@@ -827,18 +965,43 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
default: default:
style = HatchStyleHorizontal; style = HatchStyleHorizontal;
} }
m_penBrush = new HatchBrush m_brush = new HatchBrush
( (
style, style,
wxColourToColor(info.GetColour()), wxColourToColor(info.GetColour()),
Color::Transparent Color::Transparent
); );
m_pen->SetBrush( m_penBrush ); m_pen->SetBrush( m_brush );
} }
break; break;
} }
if ( dashStyle != DashStyleSolid ) if ( dashStyle != DashStyleSolid )
m_pen->SetDashStyle(dashStyle); m_pen->SetDashStyle(dashStyle);
switch (info.GetGradientType() )
{
case wxGRADIENT_NONE:
break;
case wxGRADIENT_LINEAR:
if (m_brush)
delete m_brush;
CreateLinearGradientBrush(info.GetX1(), info.GetY1(),
info.GetX2(), info.GetY2(),
info.GetStops());
m_pen->SetBrush(m_brush);
break;
case wxGRADIENT_RADIAL:
if (m_brush)
delete m_brush;
CreateRadialGradientBrush(info.GetXO(), info.GetYO(),
info.GetXC(), info.GetYC(),
info.GetRadius(),
info.GetStops());
m_pen->SetBrush(m_brush);
break;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -846,13 +1009,13 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer ) wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer )
: wxGraphicsObjectRefData(renderer) : wxGDIPlusPenBrushBaseData(renderer)
{ {
Init(); Init();
} }
wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxBrush &brush ) wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxBrush &brush )
: wxGraphicsObjectRefData(renderer) : wxGDIPlusPenBrushBaseData(renderer)
{ {
Init(); Init();
if ( brush.GetStyle() == wxBRUSHSTYLE_SOLID) if ( brush.GetStyle() == wxBRUSHSTYLE_SOLID)
@@ -897,112 +1060,23 @@ wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxB
wxBitmap* bmp = brush.GetStipple(); wxBitmap* bmp = brush.GetStipple();
if ( bmp && bmp->IsOk() ) if ( bmp && bmp->IsOk() )
{ {
wxDELETE( m_brushImage ); wxDELETE( m_image );
m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(), m_image = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),
#if wxUSE_PALETTE #if wxUSE_PALETTE
(HPALETTE)bmp->GetPalette()->GetHPALETTE() (HPALETTE)bmp->GetPalette()->GetHPALETTE()
#else #else
NULL NULL
#endif #endif
); );
m_brush = new TextureBrush(m_brushImage); m_brush = new TextureBrush(m_image);
} }
} }
} }
wxGDIPlusBrushData::~wxGDIPlusBrushData() wxGDIPlusBrushData::~wxGDIPlusBrushData()
{ {
delete m_brush;
delete m_brushImage;
delete m_brushPath;
};
void wxGDIPlusBrushData::Init()
{
m_brush = NULL;
m_brushImage= NULL;
m_brushPath= NULL;
} }
template <typename T>
void
wxGDIPlusBrushData::SetGradientStops(T *brush,
const wxGraphicsGradientStops& stops,
bool reversed)
{
const unsigned numStops = stops.GetCount();
if ( numStops <= 2 )
{
// initial and final colours are set during the brush creation, nothing
// more to do
return;
}
wxVector<Color> colors(numStops);
wxVector<REAL> positions(numStops);
if ( reversed )
{
for ( unsigned i = 0; i < numStops; i++ )
{
wxGraphicsGradientStop stop = stops.Item(numStops - i - 1);
colors[i] = wxColourToColor(stop.GetColour());
positions[i] = 1.0 - stop.GetPosition();
}
}
else
{
for ( unsigned i = 0; i < numStops; i++ )
{
wxGraphicsGradientStop stop = stops.Item(i);
colors[i] = wxColourToColor(stop.GetColour());
positions[i] = stop.GetPosition();
}
}
brush->SetInterpolationColors(&colors[0], &positions[0], numStops);
}
void
wxGDIPlusBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops)
{
LinearGradientBrush * const
brush = new LinearGradientBrush(PointF(x1, y1) , PointF(x2, y2),
wxColourToColor(stops.GetStartColour()),
wxColourToColor(stops.GetEndColour()));
brush->SetWrapMode(WrapModeTileFlipXY);
m_brush = brush;
SetGradientStops(brush, stops);
}
void
wxGDIPlusBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc,
wxDouble radius,
const wxGraphicsGradientStops& stops)
{
m_brushPath = new GraphicsPath();
m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius),
(REAL)(2*radius), (REAL)(2*radius));
PathGradientBrush * const brush = new PathGradientBrush(m_brushPath);
m_brush = brush;
brush->SetCenterPoint(PointF(xo, yo));
brush->SetCenterColor(wxColourToColor(stops.GetStartColour()));
const Color col(wxColourToColor(stops.GetEndColour()));
int count = 1;
brush->SetSurroundColors(&col, &count);
// Because the GDI+ API draws radial gradients from outside towards the
// center we have to reverse the order of the gradient stops.
SetGradientStops(brush, stops, true);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Support for adding private fonts // Support for adding private fonts
@@ -2614,12 +2688,13 @@ wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
wxGraphicsBrush wxGraphicsBrush
wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2, wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops) const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix)
{ {
ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
wxGraphicsBrush p; wxGraphicsBrush p;
wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this ); wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); d->CreateLinearGradientBrush(x1, y1, x2, y2, stops, matrix);
p.SetRefData(d); p.SetRefData(d);
return p; return p;
} }
@@ -2628,12 +2703,13 @@ wxGraphicsBrush
wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc, wxDouble xc, wxDouble yc,
wxDouble radius, wxDouble radius,
const wxGraphicsGradientStops& stops) const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix)
{ {
ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
wxGraphicsBrush p; wxGraphicsBrush p;
wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this ); wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,stops); d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,stops,matrix);
p.SetRefData(d); p.SetRefData(d);
return p; return p;
} }