From 7447d53c35249d42128d6243c90998f03882859a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 30 Jun 2012 23:41:18 +0000 Subject: [PATCH] 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 --- docs/changes.txt | 1 + src/generic/graphicc.cpp | 358 +++++++++++++++++++++++---------------- 2 files changed, 209 insertions(+), 150 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 61a1f1c25a..02e4f8c5bb 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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). diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index e0da6bea23..954e2feb57 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -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 ); - } - */ - } + case wxPENSTYLE_STIPPLE_MASK : + case wxPENSTYLE_STIPPLE_MASK_OPAQUE : + InitStipple(pen.GetStipple()); break; + default : - if ( m_pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH - && m_pen.GetStyle() <= wxPENSTYLE_LAST_HATCH ) + if ( pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH + && 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 ) - */ + InitHatch(static_cast(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) - { - 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 ; - - } - 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() ) + switch ( brush.GetStyle() ) { - 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); -} + case wxBRUSHSTYLE_STIPPLE: + case wxBRUSHSTYLE_STIPPLE_MASK: + case wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE: + InitStipple(brush.GetStipple()); + break; -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(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; } //----------------------------------------------------------------------------- -- 2.45.2