Implement hatched/stippled pens/brushes in wxGraphicsContext for Cairo.
Refactor the pen/brushes classes to introduce a common base class for them containing their colour and hatch pattern and stipple bitmap, if any. And actually create the hatched pattern and use it. Closes #11981. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71906 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -570,6 +570,7 @@ GTK:
|
||||
|
||||
- Added support for GTK+ 3 (John Chain and Paul Cornett)
|
||||
- Implement support for wxBG_STYLE_TRANSPARENT (Armel Asselin).
|
||||
- Implement stippled/hatched pens/brushes in wxGraphicsContext (Kit Bishop).
|
||||
- Fix wxNotebook best size calculation.
|
||||
- Implement wxDirDialog::Create() and wxFileDialog::Create() (vinayakgarg).
|
||||
- Fix const methods display in assert dialog (vinayakgarg).
|
||||
|
@@ -216,7 +216,44 @@ private:
|
||||
cairo_matrix_t m_matrix ;
|
||||
} ;
|
||||
|
||||
class WXDLLIMPEXP_CORE wxCairoPenData : public wxGraphicsObjectRefData
|
||||
// Common base class for pens and brushes.
|
||||
class wxCairoPenBrushBaseData : public wxGraphicsObjectRefData
|
||||
{
|
||||
public:
|
||||
wxCairoPenBrushBaseData(wxGraphicsRenderer* renderer,
|
||||
const wxColour& col,
|
||||
bool isTransparent);
|
||||
virtual ~wxCairoPenBrushBaseData();
|
||||
|
||||
virtual void Apply( wxGraphicsContext* context );
|
||||
|
||||
protected:
|
||||
// Call this to use the given bitmap as stipple. Bitmap must be non-null
|
||||
// and valid.
|
||||
void InitStipple(wxBitmap* bmp);
|
||||
|
||||
// Call this to use the given hatch style. Hatch style must be valid.
|
||||
void InitHatch(wxHatchStyle hatchStyle);
|
||||
|
||||
|
||||
double m_red;
|
||||
double m_green;
|
||||
double m_blue;
|
||||
double m_alpha;
|
||||
|
||||
cairo_pattern_t* m_pattern;
|
||||
class wxCairoBitmapData* m_bmpdata;
|
||||
|
||||
private:
|
||||
// Called once to allocate m_pattern if needed.
|
||||
void InitHatchPattern(cairo_t* ctext);
|
||||
|
||||
wxHatchStyle m_hatchStyle;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxCairoPenBrushBaseData);
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_CORE wxCairoPenData : public wxCairoPenBrushBaseData
|
||||
{
|
||||
public:
|
||||
wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
|
||||
@@ -230,11 +267,6 @@ public:
|
||||
private :
|
||||
double m_width;
|
||||
|
||||
double m_red;
|
||||
double m_green;
|
||||
double m_blue;
|
||||
double m_alpha;
|
||||
|
||||
cairo_line_cap_t m_cap;
|
||||
cairo_line_join_t m_join;
|
||||
|
||||
@@ -242,19 +274,14 @@ private :
|
||||
const double *m_lengths;
|
||||
double *m_userLengths;
|
||||
|
||||
wxPen m_pen;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxCairoPenData);
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData
|
||||
class WXDLLIMPEXP_CORE wxCairoBrushData : public wxCairoPenBrushBaseData
|
||||
{
|
||||
public:
|
||||
wxCairoBrushData( wxGraphicsRenderer* renderer );
|
||||
wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
|
||||
~wxCairoBrushData ();
|
||||
|
||||
virtual void Apply( wxGraphicsContext* context );
|
||||
|
||||
void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
|
||||
wxDouble x2, wxDouble y2,
|
||||
@@ -268,14 +295,6 @@ protected:
|
||||
|
||||
// common part of Create{Linear,Radial}GradientBrush()
|
||||
void AddGradientStops(const wxGraphicsGradientStops& stops);
|
||||
|
||||
private :
|
||||
double m_red;
|
||||
double m_green;
|
||||
double m_blue;
|
||||
double m_alpha;
|
||||
|
||||
cairo_pattern_t* m_brushPattern;
|
||||
};
|
||||
|
||||
class wxCairoFontData : public wxGraphicsObjectRefData
|
||||
@@ -489,6 +508,139 @@ private:
|
||||
};
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxCairoPenBrushBaseData implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
wxCairoPenBrushBaseData::wxCairoPenBrushBaseData(wxGraphicsRenderer* renderer,
|
||||
const wxColour& col,
|
||||
bool isTransparent)
|
||||
: wxGraphicsObjectRefData(renderer)
|
||||
{
|
||||
m_hatchStyle = wxHATCHSTYLE_INVALID;
|
||||
m_pattern = NULL;
|
||||
m_bmpdata = NULL;
|
||||
|
||||
if ( isTransparent )
|
||||
{
|
||||
m_red =
|
||||
m_green =
|
||||
m_blue =
|
||||
m_alpha = 0;
|
||||
}
|
||||
else // non-transparent
|
||||
{
|
||||
m_red = col.Red()/255.0;
|
||||
m_green = col.Green()/255.0;
|
||||
m_blue = col.Blue()/255.0;
|
||||
m_alpha = col.Alpha()/255.0;
|
||||
}
|
||||
}
|
||||
|
||||
wxCairoPenBrushBaseData::~wxCairoPenBrushBaseData()
|
||||
{
|
||||
if (m_bmpdata)
|
||||
{
|
||||
// Deleting the bitmap data also deletes the pattern referenced by
|
||||
// m_pattern, so set it to NULL to avoid deleting it twice.
|
||||
delete m_bmpdata;
|
||||
m_pattern = NULL;
|
||||
}
|
||||
if (m_pattern)
|
||||
cairo_pattern_destroy(m_pattern);
|
||||
}
|
||||
|
||||
void wxCairoPenBrushBaseData::InitHatchPattern(cairo_t* ctext)
|
||||
{
|
||||
cairo_surface_t* const
|
||||
surface = cairo_surface_create_similar(
|
||||
cairo_get_target(ctext), CAIRO_CONTENT_COLOR_ALPHA, 10, 10
|
||||
);
|
||||
|
||||
cairo_t* const cr = cairo_create(surface);
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
|
||||
cairo_set_line_width(cr, 1);
|
||||
cairo_set_line_join(cr,CAIRO_LINE_JOIN_MITER);
|
||||
|
||||
switch ( m_hatchStyle )
|
||||
{
|
||||
case wxHATCHSTYLE_CROSS:
|
||||
cairo_move_to(cr, 5, 0);
|
||||
cairo_line_to(cr, 5, 10);
|
||||
cairo_move_to(cr, 0, 5);
|
||||
cairo_line_to(cr, 10, 5);
|
||||
break;
|
||||
|
||||
case wxHATCHSTYLE_BDIAGONAL:
|
||||
cairo_move_to(cr, 0, 10);
|
||||
cairo_line_to(cr, 10, 0);
|
||||
break;
|
||||
|
||||
case wxHATCHSTYLE_FDIAGONAL:
|
||||
cairo_move_to(cr, 0, 0);
|
||||
cairo_line_to(cr, 10, 10);
|
||||
break;
|
||||
|
||||
case wxHATCHSTYLE_CROSSDIAG:
|
||||
cairo_move_to(cr, 0, 0);
|
||||
cairo_line_to(cr, 10, 10);
|
||||
cairo_move_to(cr, 10, 0);
|
||||
cairo_line_to(cr, 0, 10);
|
||||
break;
|
||||
|
||||
case wxHATCHSTYLE_HORIZONTAL:
|
||||
cairo_move_to(cr, 0, 5);
|
||||
cairo_line_to(cr, 10, 5);
|
||||
break;
|
||||
|
||||
case wxHATCHSTYLE_VERTICAL:
|
||||
cairo_move_to(cr, 5, 0);
|
||||
cairo_line_to(cr, 5, 10);
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG(wxS("Invalid hatch pattern style."));
|
||||
}
|
||||
|
||||
cairo_set_source_rgba(cr, m_red, m_green, m_blue, m_alpha);
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_destroy(cr);
|
||||
|
||||
m_pattern = cairo_pattern_create_for_surface(surface);
|
||||
cairo_surface_destroy(surface);
|
||||
cairo_pattern_set_extend(m_pattern, CAIRO_EXTEND_REPEAT);
|
||||
}
|
||||
|
||||
void wxCairoPenBrushBaseData::InitStipple(wxBitmap* bmp)
|
||||
{
|
||||
wxCHECK_RET( bmp && bmp->IsOk(), wxS("Invalid stippled bitmap") );
|
||||
|
||||
m_bmpdata = new wxCairoBitmapData(GetRenderer(), *bmp);
|
||||
m_pattern = m_bmpdata->GetCairoPattern();
|
||||
cairo_pattern_set_extend(m_pattern, CAIRO_EXTEND_REPEAT);
|
||||
}
|
||||
|
||||
void wxCairoPenBrushBaseData::InitHatch(wxHatchStyle hatchStyle)
|
||||
{
|
||||
// We can't create m_pattern right now as we don't have the Cairo context
|
||||
// needed for it, so just remember that we need to do it.
|
||||
m_hatchStyle = hatchStyle;
|
||||
}
|
||||
|
||||
void wxCairoPenBrushBaseData::Apply( wxGraphicsContext* context )
|
||||
{
|
||||
cairo_t* const ctext = (cairo_t*) context->GetNativeContext();
|
||||
|
||||
if ( m_hatchStyle != wxHATCHSTYLE_INVALID && !m_pattern )
|
||||
InitHatchPattern(ctext);
|
||||
|
||||
if ( m_pattern )
|
||||
cairo_set_source(ctext, m_pattern);
|
||||
else
|
||||
cairo_set_source_rgba(ctext, m_red, m_green, m_blue, m_alpha);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxCairoPenData implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -507,20 +659,14 @@ void wxCairoPenData::Init()
|
||||
}
|
||||
|
||||
wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
|
||||
: wxGraphicsObjectRefData(renderer)
|
||||
: wxCairoPenBrushBaseData(renderer, pen.GetColour(), pen.IsTransparent())
|
||||
{
|
||||
Init();
|
||||
m_pen = pen;
|
||||
m_width = m_pen.GetWidth();
|
||||
m_width = pen.GetWidth();
|
||||
if (m_width <= 0.0)
|
||||
m_width = 0.1;
|
||||
|
||||
m_red = m_pen.GetColour().Red()/255.0;
|
||||
m_green = m_pen.GetColour().Green()/255.0;
|
||||
m_blue = m_pen.GetColour().Blue()/255.0;
|
||||
m_alpha = m_pen.GetColour().Alpha()/255.0;
|
||||
|
||||
switch ( m_pen.GetCap() )
|
||||
switch ( pen.GetCap() )
|
||||
{
|
||||
case wxCAP_ROUND :
|
||||
m_cap = CAIRO_LINE_CAP_ROUND;
|
||||
@@ -539,7 +685,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( m_pen.GetJoin() )
|
||||
switch ( pen.GetJoin() )
|
||||
{
|
||||
case wxJOIN_BEVEL :
|
||||
m_join = CAIRO_LINE_JOIN_BEVEL;
|
||||
@@ -576,7 +722,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
|
||||
9.0 , 6.0 , 3.0 , 3.0
|
||||
};
|
||||
|
||||
switch ( m_pen.GetStyle() )
|
||||
switch ( pen.GetStyle() )
|
||||
{
|
||||
case wxPENSTYLE_SOLID :
|
||||
break;
|
||||
@@ -606,7 +752,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
|
||||
case wxPENSTYLE_USER_DASH :
|
||||
{
|
||||
wxDash *wxdashes ;
|
||||
m_count = m_pen.GetDashes( &wxdashes ) ;
|
||||
m_count = pen.GetDashes( &wxdashes ) ;
|
||||
if ((wxdashes != NULL) && (m_count > 0))
|
||||
{
|
||||
m_userLengths = new double[m_count] ;
|
||||
@@ -623,54 +769,18 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
|
||||
m_lengths = m_userLengths ;
|
||||
}
|
||||
break;
|
||||
case wxPENSTYLE_STIPPLE :
|
||||
{
|
||||
/*
|
||||
wxBitmap* bmp = pen.GetStipple();
|
||||
if ( bmp && bmp->IsOk() )
|
||||
{
|
||||
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 ( m_pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH
|
||||
&& m_pen.GetStyle() <= wxPENSTYLE_LAST_HATCH )
|
||||
{
|
||||
/*
|
||||
wxDELETE( m_penBrush );
|
||||
HatchStyle style = HatchStyleHorizontal;
|
||||
switch( pen.GetStyle() )
|
||||
{
|
||||
case wxPENSTYLE_BDIAGONAL_HATCH :
|
||||
style = HatchStyleBackwardDiagonal;
|
||||
break ;
|
||||
case wxPENSTYLE_CROSSDIAG_HATCH :
|
||||
style = HatchStyleDiagonalCross;
|
||||
break ;
|
||||
case wxPENSTYLE_FDIAGONAL_HATCH :
|
||||
style = HatchStyleForwardDiagonal;
|
||||
break ;
|
||||
case wxPENSTYLE_CROSS_HATCH :
|
||||
style = HatchStyleCross;
|
||||
break ;
|
||||
case wxPENSTYLE_HORIZONTAL_HATCH :
|
||||
style = HatchStyleHorizontal;
|
||||
break ;
|
||||
case wxPENSTYLE_VERTICAL_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 )
|
||||
*/
|
||||
case wxPENSTYLE_STIPPLE :
|
||||
case wxPENSTYLE_STIPPLE_MASK :
|
||||
case wxPENSTYLE_STIPPLE_MASK_OPAQUE :
|
||||
InitStipple(pen.GetStipple());
|
||||
break;
|
||||
|
||||
default :
|
||||
if ( pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH
|
||||
&& pen.GetStyle() <= wxPENSTYLE_LAST_HATCH )
|
||||
{
|
||||
InitHatch(static_cast<wxHatchStyle>(pen.GetStyle()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -678,9 +788,10 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
|
||||
|
||||
void wxCairoPenData::Apply( wxGraphicsContext* context )
|
||||
{
|
||||
wxCairoPenBrushBaseData::Apply(context);
|
||||
|
||||
cairo_t * ctext = (cairo_t*) context->GetNativeContext();
|
||||
cairo_set_line_width(ctext,m_width);
|
||||
cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha);
|
||||
cairo_set_line_cap(ctext,m_cap);
|
||||
cairo_set_line_join(ctext,m_join);
|
||||
cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0);
|
||||
@@ -691,83 +802,29 @@ void wxCairoPenData::Apply( wxGraphicsContext* context )
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer )
|
||||
: wxGraphicsObjectRefData( renderer )
|
||||
: wxCairoPenBrushBaseData(renderer, wxColour(), true /* transparent */)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush )
|
||||
: wxGraphicsObjectRefData(renderer)
|
||||
wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer,
|
||||
const wxBrush &brush )
|
||||
: wxCairoPenBrushBaseData(renderer, brush.GetColour(), brush.IsTransparent())
|
||||
{
|
||||
Init();
|
||||
|
||||
m_red = brush.GetColour().Red()/255.0;
|
||||
m_green = brush.GetColour().Green()/255.0;
|
||||
m_blue = brush.GetColour().Blue()/255.0;
|
||||
m_alpha = brush.GetColour().Alpha()/255.0;
|
||||
/*
|
||||
if ( brush.GetStyle() == wxBRUSHSTYLE_SOLID)
|
||||
switch ( brush.GetStyle() )
|
||||
{
|
||||
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 wxBRUSHSTYLE_BDIAGONAL_HATCH :
|
||||
style = HatchStyleBackwardDiagonal;
|
||||
break ;
|
||||
case wxBRUSHSTYLE_CROSSDIAG_HATCH :
|
||||
style = HatchStyleDiagonalCross;
|
||||
break ;
|
||||
case wxBRUSHSTYLE_FDIAGONAL_HATCH :
|
||||
style = HatchStyleForwardDiagonal;
|
||||
break ;
|
||||
case wxBRUSHSTYLE_CROSS_HATCH :
|
||||
style = HatchStyleCross;
|
||||
break ;
|
||||
case wxBRUSHSTYLE_HORIZONTAL_HATCH :
|
||||
style = HatchStyleHorizontal;
|
||||
break ;
|
||||
case wxBRUSHSTYLE_VERTICAL_HATCH :
|
||||
style = HatchStyleVertical;
|
||||
break ;
|
||||
case wxBRUSHSTYLE_STIPPLE:
|
||||
case wxBRUSHSTYLE_STIPPLE_MASK:
|
||||
case wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE:
|
||||
InitStipple(brush.GetStipple());
|
||||
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->IsOk() )
|
||||
{
|
||||
wxDELETE( m_brushImage );
|
||||
m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
|
||||
m_brush = new TextureBrush(m_brushImage);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
wxCairoBrushData::~wxCairoBrushData ()
|
||||
{
|
||||
if (m_brushPattern)
|
||||
cairo_pattern_destroy(m_brushPattern);
|
||||
}
|
||||
|
||||
void wxCairoBrushData::Apply( wxGraphicsContext* context )
|
||||
{
|
||||
cairo_t * ctext = (cairo_t*) context->GetNativeContext();
|
||||
if ( m_brushPattern )
|
||||
{
|
||||
cairo_set_source(ctext,m_brushPattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha);
|
||||
default:
|
||||
if ( brush.IsHatch() )
|
||||
InitHatch(static_cast<wxHatchStyle>(brush.GetStyle()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,7 +840,7 @@ void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops)
|
||||
|
||||
cairo_pattern_add_color_stop_rgba
|
||||
(
|
||||
m_brushPattern,
|
||||
m_pattern,
|
||||
stop.GetPosition(),
|
||||
col.Red()/255.0,
|
||||
col.Green()/255.0,
|
||||
@@ -792,7 +849,7 @@ void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops)
|
||||
);
|
||||
}
|
||||
|
||||
wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS,
|
||||
wxASSERT_MSG(cairo_pattern_status(m_pattern) == CAIRO_STATUS_SUCCESS,
|
||||
wxT("Couldn't create cairo pattern"));
|
||||
}
|
||||
|
||||
@@ -801,7 +858,7 @@ wxCairoBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
|
||||
wxDouble x2, wxDouble y2,
|
||||
const wxGraphicsGradientStops& stops)
|
||||
{
|
||||
m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2);
|
||||
m_pattern = cairo_pattern_create_linear(x1,y1,x2,y2);
|
||||
|
||||
AddGradientStops(stops);
|
||||
}
|
||||
@@ -812,14 +869,15 @@ wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
|
||||
wxDouble radius,
|
||||
const wxGraphicsGradientStops& stops)
|
||||
{
|
||||
m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius);
|
||||
m_pattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius);
|
||||
|
||||
AddGradientStops(stops);
|
||||
}
|
||||
|
||||
void wxCairoBrushData::Init()
|
||||
{
|
||||
m_brushPattern = NULL;
|
||||
m_pattern = NULL;
|
||||
m_bmpdata = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user