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:
Vadim Zeitlin
2012-06-30 23:41:18 +00:00
parent c17eafaaf1
commit 7447d53c35
2 changed files with 212 additions and 153 deletions

View File

@@ -570,6 +570,7 @@ GTK:
- Added support for GTK+ 3 (John Chain and Paul Cornett) - Added support for GTK+ 3 (John Chain and Paul Cornett)
- Implement support for wxBG_STYLE_TRANSPARENT (Armel Asselin). - Implement support for wxBG_STYLE_TRANSPARENT (Armel Asselin).
- Implement stippled/hatched pens/brushes in wxGraphicsContext (Kit Bishop).
- Fix wxNotebook best size calculation. - Fix wxNotebook best size calculation.
- Implement wxDirDialog::Create() and wxFileDialog::Create() (vinayakgarg). - Implement wxDirDialog::Create() and wxFileDialog::Create() (vinayakgarg).
- Fix const methods display in assert dialog (vinayakgarg). - Fix const methods display in assert dialog (vinayakgarg).

View File

@@ -216,7 +216,44 @@ private:
cairo_matrix_t m_matrix ; 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: public:
wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ); wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
@@ -230,11 +267,6 @@ public:
private : private :
double m_width; double m_width;
double m_red;
double m_green;
double m_blue;
double m_alpha;
cairo_line_cap_t m_cap; cairo_line_cap_t m_cap;
cairo_line_join_t m_join; cairo_line_join_t m_join;
@@ -242,19 +274,14 @@ private :
const double *m_lengths; const double *m_lengths;
double *m_userLengths; double *m_userLengths;
wxPen m_pen;
wxDECLARE_NO_COPY_CLASS(wxCairoPenData); wxDECLARE_NO_COPY_CLASS(wxCairoPenData);
}; };
class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData class WXDLLIMPEXP_CORE wxCairoBrushData : public wxCairoPenBrushBaseData
{ {
public: public:
wxCairoBrushData( wxGraphicsRenderer* renderer ); wxCairoBrushData( wxGraphicsRenderer* renderer );
wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ); wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
~wxCairoBrushData ();
virtual void Apply( wxGraphicsContext* context );
void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2, wxDouble x2, wxDouble y2,
@@ -268,14 +295,6 @@ protected:
// common part of Create{Linear,Radial}GradientBrush() // common part of Create{Linear,Radial}GradientBrush()
void AddGradientStops(const wxGraphicsGradientStops& stops); 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 class wxCairoFontData : public wxGraphicsObjectRefData
@@ -489,6 +508,139 @@ private:
}; };
#endif // wxUSE_IMAGE #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 // wxCairoPenData implementation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -507,20 +659,14 @@ void wxCairoPenData::Init()
} }
wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
: wxGraphicsObjectRefData(renderer) : wxCairoPenBrushBaseData(renderer, pen.GetColour(), pen.IsTransparent())
{ {
Init(); Init();
m_pen = pen; m_width = pen.GetWidth();
m_width = m_pen.GetWidth();
if (m_width <= 0.0) if (m_width <= 0.0)
m_width = 0.1; m_width = 0.1;
m_red = m_pen.GetColour().Red()/255.0; switch ( pen.GetCap() )
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() )
{ {
case wxCAP_ROUND : case wxCAP_ROUND :
m_cap = CAIRO_LINE_CAP_ROUND; m_cap = CAIRO_LINE_CAP_ROUND;
@@ -539,7 +685,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
break; break;
} }
switch ( m_pen.GetJoin() ) switch ( pen.GetJoin() )
{ {
case wxJOIN_BEVEL : case wxJOIN_BEVEL :
m_join = CAIRO_LINE_JOIN_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 9.0 , 6.0 , 3.0 , 3.0
}; };
switch ( m_pen.GetStyle() ) switch ( pen.GetStyle() )
{ {
case wxPENSTYLE_SOLID : case wxPENSTYLE_SOLID :
break; break;
@@ -606,7 +752,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
case wxPENSTYLE_USER_DASH : case wxPENSTYLE_USER_DASH :
{ {
wxDash *wxdashes ; wxDash *wxdashes ;
m_count = m_pen.GetDashes( &wxdashes ) ; m_count = pen.GetDashes( &wxdashes ) ;
if ((wxdashes != NULL) && (m_count > 0)) if ((wxdashes != NULL) && (m_count > 0))
{ {
m_userLengths = new double[m_count] ; m_userLengths = new double[m_count] ;
@@ -623,54 +769,18 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
m_lengths = m_userLengths ; m_lengths = m_userLengths ;
} }
break; break;
case wxPENSTYLE_STIPPLE : case wxPENSTYLE_STIPPLE :
{ case wxPENSTYLE_STIPPLE_MASK :
/* case wxPENSTYLE_STIPPLE_MASK_OPAQUE :
wxBitmap* bmp = pen.GetStipple(); InitStipple(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; break;
} default :
m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() , if ( pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH
pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent ); && pen.GetStyle() <= wxPENSTYLE_LAST_HATCH )
m_pen->SetBrush( m_penBrush ) {
*/ InitHatch(static_cast<wxHatchStyle>(pen.GetStyle()));
} }
break; break;
} }
@@ -678,9 +788,10 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
void wxCairoPenData::Apply( wxGraphicsContext* context ) void wxCairoPenData::Apply( wxGraphicsContext* context )
{ {
wxCairoPenBrushBaseData::Apply(context);
cairo_t * ctext = (cairo_t*) context->GetNativeContext(); cairo_t * ctext = (cairo_t*) context->GetNativeContext();
cairo_set_line_width(ctext,m_width); 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_cap(ctext,m_cap);
cairo_set_line_join(ctext,m_join); cairo_set_line_join(ctext,m_join);
cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0); cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0);
@@ -691,83 +802,29 @@ void wxCairoPenData::Apply( wxGraphicsContext* context )
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer ) wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer )
: wxGraphicsObjectRefData( renderer ) : wxCairoPenBrushBaseData(renderer, wxColour(), true /* transparent */)
{ {
Init(); Init();
} }
wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ) wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer,
: wxGraphicsObjectRefData(renderer) const wxBrush &brush )
: wxCairoPenBrushBaseData(renderer, brush.GetColour(), brush.IsTransparent())
{ {
Init(); 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)
{
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() ) switch ( brush.GetStyle() )
{ {
case wxBRUSHSTYLE_BDIAGONAL_HATCH : case wxBRUSHSTYLE_STIPPLE:
style = HatchStyleBackwardDiagonal; case wxBRUSHSTYLE_STIPPLE_MASK:
break ; case wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE:
case wxBRUSHSTYLE_CROSSDIAG_HATCH : InitStipple(brush.GetStipple());
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; break;
} default:
m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() , if ( brush.IsHatch() )
brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent ); InitHatch(static_cast<wxHatchStyle>(brush.GetStyle()));
} break;
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);
} }
} }
@@ -783,7 +840,7 @@ void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops)
cairo_pattern_add_color_stop_rgba cairo_pattern_add_color_stop_rgba
( (
m_brushPattern, m_pattern,
stop.GetPosition(), stop.GetPosition(),
col.Red()/255.0, col.Red()/255.0,
col.Green()/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")); wxT("Couldn't create cairo pattern"));
} }
@@ -801,7 +858,7 @@ wxCairoBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
wxDouble x2, wxDouble y2, wxDouble x2, wxDouble y2,
const wxGraphicsGradientStops& stops) 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); AddGradientStops(stops);
} }
@@ -812,14 +869,15 @@ wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
wxDouble radius, wxDouble radius,
const wxGraphicsGradientStops& stops) 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); AddGradientStops(stops);
} }
void wxCairoBrushData::Init() void wxCairoBrushData::Init()
{ {
m_brushPattern = NULL; m_pattern = NULL;
m_bmpdata = NULL;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------