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 ;
} ;
class wxGDIPlusPenData : public wxGraphicsObjectRefData
// Things that pens and brushes have in common
class wxGDIPlusPenBrushBaseData : public wxGraphicsObjectRefData
{
public:
wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxGraphicsPenInfo &info );
~wxGDIPlusPenData();
wxGDIPlusPenBrushBaseData(wxGraphicsRenderer* renderer);
~wxGDIPlusPenBrushBaseData();
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 ();
virtual void Init();
void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops);
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix);
void CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc,
wxDouble radius,
const wxGraphicsGradientStops& stops);
virtual Brush* GetGDIPlusBrush() { return m_brush; }
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix);
protected:
virtual void Init();
Brush* m_brush;
GraphicsPath* m_brushPath;
Image* m_image;
private:
// common part of Create{Linear,Radial}GradientBrush()
@@ -300,10 +286,35 @@ private:
void SetGradientStops(T *brush,
const wxGraphicsGradientStops& stops,
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
@@ -624,13 +635,15 @@ public :
virtual wxGraphicsBrush
CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops) wxOVERRIDE;
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix) wxOVERRIDE;
virtual wxGraphicsBrush
CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc,
wxDouble radius,
const wxGraphicsGradientStops& stops) wxOVERRIDE;
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix=wxNullGraphicsMatrix) wxOVERRIDE;
// create a native bitmap representation
virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) wxOVERRIDE;
@@ -669,6 +682,135 @@ private :
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
//-----------------------------------------------------------------------------
@@ -676,20 +818,16 @@ private :
wxGDIPlusPenData::~wxGDIPlusPenData()
{
delete m_pen;
delete m_penImage;
delete m_penBrush;
}
void wxGDIPlusPenData::Init()
{
m_pen = NULL ;
m_penImage = NULL;
m_penBrush = NULL;
}
wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
const wxGraphicsPenInfo &info )
: wxGraphicsObjectRefData(renderer)
: wxGDIPlusPenBrushBaseData(renderer)
{
Init();
m_width = info.GetWidth();
@@ -786,15 +924,15 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
wxBitmap bmp = info.GetStipple();
if ( bmp.IsOk() )
{
m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),
m_image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),
#if wxUSE_PALETTE
(HPALETTE)bmp.GetPalette()->GetHPALETTE()
#else
NULL
#endif
);
m_penBrush = new TextureBrush(m_penImage);
m_pen->SetBrush( m_penBrush );
m_brush = new TextureBrush(m_image);
m_pen->SetBrush( m_brush );
}
}
@@ -827,18 +965,43 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
default:
style = HatchStyleHorizontal;
}
m_penBrush = new HatchBrush
m_brush = new HatchBrush
(
style,
wxColourToColor(info.GetColour()),
Color::Transparent
);
m_pen->SetBrush( m_penBrush );
m_pen->SetBrush( m_brush );
}
break;
}
if ( dashStyle != DashStyleSolid )
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 )
: wxGraphicsObjectRefData(renderer)
: wxGDIPlusPenBrushBaseData(renderer)
{
Init();
}
wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxBrush &brush )
: wxGraphicsObjectRefData(renderer)
: wxGDIPlusPenBrushBaseData(renderer)
{
Init();
if ( brush.GetStyle() == wxBRUSHSTYLE_SOLID)
@@ -897,112 +1060,23 @@ wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxB
wxBitmap* bmp = brush.GetStipple();
if ( bmp && bmp->IsOk() )
{
wxDELETE( m_brushImage );
m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),
wxDELETE( m_image );
m_image = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),
#if wxUSE_PALETTE
(HPALETTE)bmp->GetPalette()->GetHPALETTE()
#else
NULL
#endif
);
m_brush = new TextureBrush(m_brushImage);
m_brush = new TextureBrush(m_image);
}
}
}
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
@@ -2614,12 +2688,13 @@ wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
wxGraphicsBrush
wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops)
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix)
{
ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
wxGraphicsBrush p;
wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
d->CreateLinearGradientBrush(x1, y1, x2, y2, stops);
d->CreateLinearGradientBrush(x1, y1, x2, y2, stops, matrix);
p.SetRefData(d);
return p;
}
@@ -2628,12 +2703,13 @@ wxGraphicsBrush
wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble xc, wxDouble yc,
wxDouble radius,
const wxGraphicsGradientStops& stops)
const wxGraphicsGradientStops& stops,
const wxGraphicsMatrix& matrix)
{
ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
wxGraphicsBrush p;
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);
return p;
}